blob: 0640e7f8a418225e4941c70b05912eabfe55fd43 [file] [log] [blame]
David Tolnay52759782020-05-03 23:59:40 -07001use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07002use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04003use crate::syntax::{
Joel Galensonc03402a2020-04-23 17:31:09 -07004 attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
David Tolnaye2f9ec42020-05-07 16:19:33 -07005 Struct, Ty1, Type, TypeAlias, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04006};
David Tolnaye2f9ec42020-05-07 16:19:33 -07007use proc_macro2::TokenStream;
David Tolnayc071b892020-03-18 16:59:53 -07008use quote::{format_ident, quote};
Joel Galenson88547732020-05-05 08:23:42 -07009use std::collections::HashSet;
Joel Galenson8ef1bc82020-05-05 08:45:49 -070010use std::u32;
David Tolnaye2f9ec42020-05-07 16:19:33 -070011use syn::parse::{ParseStream, Parser};
David Tolnaye3a48152020-04-08 19:38:05 -070012use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040013use syn::{
David Tolnaye2f9ec42020-05-07 16:19:33 -070014 Abi, Attribute, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn,
15 ForeignItemType, GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Lit, Pat,
16 PathArguments, Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath,
17 TypeReference, TypeSlice, Variant as RustVariant,
David Tolnay7db73692019-10-20 14:51:12 -040018};
19
David Tolnaye3a48152020-04-08 19:38:05 -070020pub mod kw {
21 syn::custom_keyword!(Result);
22}
23
David Tolnay52759782020-05-03 23:59:40 -070024pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040025 let mut apis = Vec::new();
26 for item in items {
27 match item {
David Tolnay52759782020-05-03 23:59:40 -070028 Item::Struct(item) => match parse_struct(item) {
29 Ok(strct) => apis.push(strct),
30 Err(err) => cx.push(err),
31 },
32 Item::Enum(item) => match parse_enum(item) {
33 Ok(enm) => apis.push(enm),
34 Err(err) => cx.push(err),
35 },
36 Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
37 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
38 _ => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040039 }
40 }
David Tolnay52759782020-05-03 23:59:40 -070041 apis
David Tolnay7db73692019-10-20 14:51:12 -040042}
43
44fn parse_struct(item: ItemStruct) -> Result<Api> {
45 let generics = &item.generics;
46 if !generics.params.is_empty() || generics.where_clause.is_some() {
47 let struct_token = item.struct_token;
48 let ident = &item.ident;
49 let where_clause = &generics.where_clause;
50 let span = quote!(#struct_token #ident #generics #where_clause);
51 return Err(Error::new_spanned(
52 span,
53 "struct with generic parameters is not supported yet",
54 ));
55 }
56
57 let mut doc = Doc::new();
58 let mut derives = Vec::new();
59 attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
David Tolnay09462ac2020-03-20 14:58:41 -070060
61 let fields = match item.fields {
62 Fields::Named(fields) => fields,
63 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
64 Fields::Unnamed(_) => {
65 return Err(Error::new_spanned(item, "tuple structs are not supported"))
66 }
67 };
68
69 Ok(Api::Struct(Struct {
70 doc,
71 derives,
72 struct_token: item.struct_token,
73 ident: item.ident,
74 brace_token: fields.brace_token,
75 fields: fields
76 .named
77 .into_iter()
78 .map(|field| {
79 Ok(Var {
80 ident: field.ident.unwrap(),
81 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040082 })
David Tolnay09462ac2020-03-20 14:58:41 -070083 })
84 .collect::<Result<_>>()?,
85 }))
David Tolnay7db73692019-10-20 14:51:12 -040086}
87
Joel Galensonc03402a2020-04-23 17:31:09 -070088fn parse_enum(item: ItemEnum) -> Result<Api> {
89 let generics = &item.generics;
90 if !generics.params.is_empty() || generics.where_clause.is_some() {
91 let enum_token = item.enum_token;
92 let ident = &item.ident;
93 let where_clause = &generics.where_clause;
94 let span = quote!(#enum_token #ident #generics #where_clause);
95 return Err(Error::new_spanned(
96 span,
97 "enums with generic parameters are not allowed",
98 ));
99 }
100
David Tolnayd7984c22020-04-30 20:09:31 -0700101 let doc = attrs::parse_doc(&item.attrs)?;
Joel Galensonc03402a2020-04-23 17:31:09 -0700102
Joel Galenson88547732020-05-05 08:23:42 -0700103 let mut variants = Vec::new();
104 let mut discriminants = HashSet::new();
105 let mut prev_discriminant = None;
106 for variant in item.variants {
107 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700108 Fields::Unit => {}
109 _ => {
110 return Err(Error::new_spanned(
111 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700112 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700113 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700114 }
115 }
David Tolnay4301f3c2020-05-05 10:29:52 -0700116 if variant.discriminant.is_none() && prev_discriminant == Some(u32::MAX) {
David Tolnaya3f64072020-05-05 10:24:24 -0700117 let msg = format!("discriminant overflow on value after {}", u32::MAX);
118 return Err(Error::new_spanned(variant, msg));
Joel Galenson88547732020-05-05 08:23:42 -0700119 }
120 let discriminant =
121 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
122 if !discriminants.insert(discriminant) {
123 let msg = format!("discriminant value `{}` already exists", discriminant);
124 return Err(Error::new_spanned(variant, msg));
125 }
126 variants.push(Variant {
127 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700128 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700129 });
130 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700131 }
132
133 Ok(Api::Enum(Enum {
134 doc,
135 enum_token: item.enum_token,
136 ident: item.ident,
137 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700138 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700139 }))
140}
141
Joel Galenson88547732020-05-05 08:23:42 -0700142fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700143 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700144 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700145 Some((
146 _,
147 Expr::Lit(ExprLit {
148 lit: Lit::Int(n), ..
149 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700150 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700151 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700152 Err(_) => Err(Error::new_spanned(
153 variant,
154 "cannot parse enum discriminant as an integer",
155 )),
156 },
157 _ => Err(Error::new_spanned(
158 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700159 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700160 )),
161 }
162}
163
David Tolnay52759782020-05-03 23:59:40 -0700164fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
165 let lang = match parse_lang(foreign_mod.abi) {
166 Ok(lang) => lang,
167 Err(err) => return cx.push(err),
168 };
David Tolnay7db73692019-10-20 14:51:12 -0400169
Joel Galensone1e969d2020-04-21 12:50:20 -0700170 let mut items = Vec::new();
171 for foreign in &foreign_mod.items {
172 match foreign {
David Tolnay295ef6b2020-05-07 16:10:22 -0700173 ForeignItem::Type(foreign) => match parse_extern_type(foreign, lang) {
174 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700175 Err(err) => cx.push(err),
176 },
177 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700178 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700179 Err(err) => cx.push(err),
180 },
David Tolnay7db73692019-10-20 14:51:12 -0400181 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700182 match foreign.mac.parse_body() {
183 Ok(include) => items.push(Api::Include(include)),
184 Err(err) => cx.push(err),
185 }
David Tolnay7db73692019-10-20 14:51:12 -0400186 }
David Tolnaye2f9ec42020-05-07 16:19:33 -0700187 ForeignItem::Verbatim(tokens) => match parse_extern_verbatim(tokens, lang) {
188 Ok(api) => items.push(api),
189 Err(err) => cx.push(err),
190 },
David Tolnay52759782020-05-03 23:59:40 -0700191 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400192 }
193 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700194
195 let mut types = items.iter().filter_map(|item| match item {
David Tolnaye5a015a2020-05-07 21:54:26 -0700196 Api::CxxType(ty) | Api::RustType(ty) => Some(&ty.ident),
197 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700198 _ => None,
199 });
200 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700201 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700202 for item in &mut items {
203 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
204 if let Some(receiver) = &mut efn.receiver {
205 if receiver.ty == "Self" {
206 receiver.ty = single_type.clone();
207 }
208 }
209 }
210 }
211 }
212
David Tolnay52759782020-05-03 23:59:40 -0700213 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400214}
215
216fn parse_lang(abi: Abi) -> Result<Lang> {
217 let name = match &abi.name {
218 Some(name) => name,
219 None => {
220 return Err(Error::new_spanned(
221 abi,
222 "ABI name is required, extern \"C\" or extern \"Rust\"",
223 ));
224 }
225 };
226 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700227 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400228 "Rust" => Ok(Lang::Rust),
229 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
230 }
231}
232
David Tolnay295ef6b2020-05-07 16:10:22 -0700233fn parse_extern_type(foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400234 let doc = attrs::parse_doc(&foreign_type.attrs)?;
235 let type_token = foreign_type.type_token;
236 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700237 let api_type = match lang {
238 Lang::Cxx => Api::CxxType,
239 Lang::Rust => Api::RustType,
240 };
241 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400242 doc,
243 type_token,
244 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700245 }))
David Tolnay7db73692019-10-20 14:51:12 -0400246}
247
David Tolnay295ef6b2020-05-07 16:10:22 -0700248fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400249 let generics = &foreign_fn.sig.generics;
250 if !generics.params.is_empty() || generics.where_clause.is_some() {
251 return Err(Error::new_spanned(
252 foreign_fn,
253 "extern function with generic parameters is not supported yet",
254 ));
255 }
256 if let Some(variadic) = &foreign_fn.sig.variadic {
257 return Err(Error::new_spanned(
258 variadic,
259 "variadic function is not supported yet",
260 ));
261 }
262
263 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700264 let mut args = Punctuated::new();
265 for arg in foreign_fn.sig.inputs.pairs() {
266 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400267 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700268 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700269 if let Some((ampersand, lifetime)) = &arg.reference {
270 receiver = Some(Receiver {
271 ampersand: *ampersand,
272 lifetime: lifetime.clone(),
273 mutability: arg.mutability,
274 var: arg.self_token,
275 ty: Token![Self](arg.self_token.span).into(),
276 shorthand: true,
277 });
278 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700279 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700280 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400281 }
282 FnArg::Typed(arg) => {
283 let ident = match arg.pat.as_ref() {
284 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700285 Pat::Wild(pat) => {
286 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
287 }
David Tolnay7db73692019-10-20 14:51:12 -0400288 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
289 };
290 let ty = parse_type(&arg.ty)?;
291 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700292 args.push_value(Var { ident, ty });
293 if let Some(comma) = comma {
294 args.push_punct(*comma);
295 }
David Tolnay7db73692019-10-20 14:51:12 -0400296 continue;
297 }
298 if let Type::Ref(reference) = ty {
299 if let Type::Ident(ident) = reference.inner {
300 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700301 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700302 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400303 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700304 var: Token![self](ident.span()),
305 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700306 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400307 });
308 continue;
309 }
310 }
311 return Err(Error::new_spanned(arg, "unsupported method receiver"));
312 }
313 }
314 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700315
David Tolnaye3a48152020-04-08 19:38:05 -0700316 let mut throws_tokens = None;
317 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
318 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400319 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
320 let fn_token = foreign_fn.sig.fn_token;
321 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700322 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400323 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700324 let api_function = match lang {
325 Lang::Cxx => Api::CxxFunction,
326 Lang::Rust => Api::RustFunction,
327 };
David Tolnayd95b1192020-03-18 20:07:46 -0700328
David Tolnay295ef6b2020-05-07 16:10:22 -0700329 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700330 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400331 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400332 ident,
David Tolnay16448732020-03-18 12:39:36 -0700333 sig: Signature {
334 fn_token,
335 receiver,
336 args,
337 ret,
338 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700339 paren_token,
340 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700341 },
David Tolnay7db73692019-10-20 14:51:12 -0400342 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700343 }))
David Tolnay7db73692019-10-20 14:51:12 -0400344}
345
David Tolnaye2f9ec42020-05-07 16:19:33 -0700346fn parse_extern_verbatim(tokens: &TokenStream, lang: Lang) -> Result<Api> {
347 // type Alias = crate::path::to::Type;
348 fn parse(input: ParseStream) -> Result<TypeAlias> {
349 let attrs = input.call(Attribute::parse_outer)?;
350 let type_token: Token![type] = match input.parse()? {
351 Some(type_token) => type_token,
352 None => {
353 let span = input.cursor().token_stream();
354 return Err(Error::new_spanned(span, "unsupported foreign item"));
355 }
356 };
357 let ident: Ident = input.parse()?;
358 let eq_token: Token![=] = input.parse()?;
359 let ty: RustType = input.parse()?;
360 let semi_token: Token![;] = input.parse()?;
361 attrs::parse_doc(&attrs)?;
362
363 Ok(TypeAlias {
364 type_token,
365 ident,
366 eq_token,
367 ty,
368 semi_token,
369 })
370 }
371
372 let type_alias = parse.parse2(tokens.clone())?;
373 match lang {
374 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
375 Lang::Rust => {
376 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
377 let span = quote!(#type_token #semi_token);
378 let msg = "type alias in extern \"Rust\" block is not supported";
379 Err(Error::new_spanned(span, msg))
380 }
381 }
382}
383
David Tolnay7db73692019-10-20 14:51:12 -0400384fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700385 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700386 RustType::Reference(ty) => parse_type_reference(ty),
387 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700388 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700389 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700390 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
391 _ => Err(Error::new_spanned(ty, "unsupported type")),
392 }
393}
394
395fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
396 let inner = parse_type(&ty.elem)?;
397 let which = match &inner {
398 Type::Ident(ident) if ident == "str" => {
399 if ty.mutability.is_some() {
400 return Err(Error::new_spanned(ty, "unsupported type"));
401 } else {
402 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400403 }
404 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700405 Type::Slice(slice) => match &slice.inner {
406 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
407 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700408 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700409 _ => Type::Ref,
410 };
411 Ok(which(Box::new(Ref {
412 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700413 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700414 mutability: ty.mutability,
415 inner,
416 })))
417}
418
419fn parse_type_path(ty: &TypePath) -> Result<Type> {
420 let path = &ty.path;
421 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
422 let segment = &path.segments[0];
423 let ident = segment.ident.clone();
424 match &segment.arguments {
425 PathArguments::None => return Ok(Type::Ident(ident)),
426 PathArguments::AngleBracketed(generic) => {
427 if ident == "UniquePtr" && generic.args.len() == 1 {
428 if let GenericArgument::Type(arg) = &generic.args[0] {
429 let inner = parse_type(arg)?;
430 return Ok(Type::UniquePtr(Box::new(Ty1 {
431 name: ident,
432 langle: generic.lt_token,
433 inner,
434 rangle: generic.gt_token,
435 })));
436 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700437 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700438 if let GenericArgument::Type(arg) = &generic.args[0] {
439 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700440 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700441 name: ident,
442 langle: generic.lt_token,
443 inner,
444 rangle: generic.gt_token,
445 })));
446 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700447 } else if ident == "Box" && generic.args.len() == 1 {
448 if let GenericArgument::Type(arg) = &generic.args[0] {
449 let inner = parse_type(arg)?;
450 return Ok(Type::RustBox(Box::new(Ty1 {
451 name: ident,
452 langle: generic.lt_token,
453 inner,
454 rangle: generic.gt_token,
455 })));
456 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700457 } else if ident == "Vec" && generic.args.len() == 1 {
458 if let GenericArgument::Type(arg) = &generic.args[0] {
459 let inner = parse_type(arg)?;
460 return Ok(Type::RustVec(Box::new(Ty1 {
461 name: ident,
462 langle: generic.lt_token,
463 inner,
464 rangle: generic.gt_token,
465 })));
466 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700467 }
468 }
469 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700470 }
David Tolnay7db73692019-10-20 14:51:12 -0400471 }
472 Err(Error::new_spanned(ty, "unsupported type"))
473}
474
David Tolnayeebe9b72020-04-14 16:32:18 -0700475fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
476 let inner = parse_type(&ty.elem)?;
477 Ok(Type::Slice(Box::new(Slice {
478 bracket: ty.bracket_token,
479 inner,
480 })))
481}
482
David Tolnayc071b892020-03-18 16:59:53 -0700483fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
484 if ty.lifetimes.is_some() {
485 return Err(Error::new_spanned(
486 ty,
487 "function pointer with lifetime parameters is not supported yet",
488 ));
489 }
490 if ty.variadic.is_some() {
491 return Err(Error::new_spanned(
492 ty,
493 "variadic function pointer is not supported yet",
494 ));
495 }
496 let args = ty
497 .inputs
498 .iter()
499 .enumerate()
500 .map(|(i, arg)| {
501 let ty = parse_type(&arg.ty)?;
502 let ident = match &arg.name {
503 Some(ident) => ident.0.clone(),
504 None => format_ident!("_{}", i),
505 };
506 Ok(Var { ident, ty })
507 })
508 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700509 let mut throws_tokens = None;
510 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
511 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700512 Ok(Type::Fn(Box::new(Signature {
513 fn_token: ty.fn_token,
514 receiver: None,
515 args,
516 ret,
517 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700518 paren_token: ty.paren_token,
519 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700520 })))
521}
522
David Tolnaye3a48152020-04-08 19:38:05 -0700523fn parse_return_type(
524 ty: &ReturnType,
525 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
526) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700527 let mut ret = match ty {
528 ReturnType::Default => return Ok(None),
529 ReturnType::Type(_, ret) => ret.as_ref(),
530 };
531 if let RustType::Path(ty) = ret {
532 let path = &ty.path;
533 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
534 let segment = &path.segments[0];
535 let ident = segment.ident.clone();
536 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
537 if ident == "Result" && generic.args.len() == 1 {
538 if let GenericArgument::Type(arg) = &generic.args[0] {
539 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700540 *throws_tokens =
541 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700542 }
543 }
544 }
545 }
546 }
547 match parse_type(ret)? {
548 Type::Void(_) => Ok(None),
549 ty => Ok(Some(ty)),
550 }
551}