• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::syntax::attrs::OtherAttrs;
2 use crate::syntax::cfg::CfgExpr;
3 use crate::syntax::discriminant::DiscriminantSet;
4 use crate::syntax::file::{Item, ItemForeignMod};
5 use crate::syntax::report::Errors;
6 use crate::syntax::Atom::*;
7 use crate::syntax::{
8     attrs, error, Api, Array, Derive, Doc, Enum, EnumRepr, ExternFn, ExternType, ForeignName, Impl,
9     Include, IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Ptr, Receiver, Ref,
10     Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var, Variant,
11 };
12 use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
13 use quote::{format_ident, quote, quote_spanned};
14 use std::mem;
15 use syn::parse::{ParseStream, Parser};
16 use syn::punctuated::Punctuated;
17 use syn::{
18     Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
19     GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
20     Pat, PathArguments, Result, ReturnType, Signature as RustSignature, Token, TraitBound,
21     TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypePtr,
22     TypeReference, Variant as RustVariant, Visibility,
23 };
24 
25 pub mod kw {
26     syn::custom_keyword!(Pin);
27     syn::custom_keyword!(Result);
28 }
29 
parse_items( cx: &mut Errors, items: Vec<Item>, trusted: bool, namespace: &Namespace, ) -> Vec<Api>30 pub fn parse_items(
31     cx: &mut Errors,
32     items: Vec<Item>,
33     trusted: bool,
34     namespace: &Namespace,
35 ) -> Vec<Api> {
36     let mut apis = Vec::new();
37     for item in items {
38         match item {
39             Item::Struct(item) => match parse_struct(cx, item, namespace) {
40                 Ok(strct) => apis.push(strct),
41                 Err(err) => cx.push(err),
42             },
43             Item::Enum(item) => apis.push(parse_enum(cx, item, namespace)),
44             Item::ForeignMod(foreign_mod) => {
45                 parse_foreign_mod(cx, foreign_mod, &mut apis, trusted, namespace)
46             }
47             Item::Impl(item) => match parse_impl(cx, item) {
48                 Ok(imp) => apis.push(imp),
49                 Err(err) => cx.push(err),
50             },
51             Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
52             Item::Other(item) => cx.error(item, "unsupported item"),
53         }
54     }
55     apis
56 }
57 
parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result<Api>58 fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result<Api> {
59     let mut cfg = CfgExpr::Unconditional;
60     let mut doc = Doc::new();
61     let mut derives = Vec::new();
62     let mut namespace = namespace.clone();
63     let mut cxx_name = None;
64     let mut rust_name = None;
65     let attrs = attrs::parse(
66         cx,
67         mem::take(&mut item.attrs),
68         attrs::Parser {
69             cfg: Some(&mut cfg),
70             doc: Some(&mut doc),
71             derives: Some(&mut derives),
72             namespace: Some(&mut namespace),
73             cxx_name: Some(&mut cxx_name),
74             rust_name: Some(&mut rust_name),
75             ..Default::default()
76         },
77     );
78 
79     let named_fields = match item.fields {
80         Fields::Named(fields) => fields,
81         Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
82         Fields::Unnamed(_) => {
83             return Err(Error::new_spanned(item, "tuple structs are not supported"));
84         }
85     };
86 
87     let mut lifetimes = Punctuated::new();
88     let mut has_unsupported_generic_param = false;
89     for pair in item.generics.params.into_pairs() {
90         let (param, punct) = pair.into_tuple();
91         match param {
92             GenericParam::Lifetime(param) => {
93                 if !param.bounds.is_empty() && !has_unsupported_generic_param {
94                     let msg = "lifetime parameter with bounds is not supported yet";
95                     cx.error(&param, msg);
96                     has_unsupported_generic_param = true;
97                 }
98                 lifetimes.push_value(param.lifetime);
99                 if let Some(punct) = punct {
100                     lifetimes.push_punct(punct);
101                 }
102             }
103             GenericParam::Type(param) => {
104                 if !has_unsupported_generic_param {
105                     let msg = "struct with generic type parameter is not supported yet";
106                     cx.error(&param, msg);
107                     has_unsupported_generic_param = true;
108                 }
109             }
110             GenericParam::Const(param) => {
111                 if !has_unsupported_generic_param {
112                     let msg = "struct with const generic parameter is not supported yet";
113                     cx.error(&param, msg);
114                     has_unsupported_generic_param = true;
115                 }
116             }
117         }
118     }
119 
120     if let Some(where_clause) = &item.generics.where_clause {
121         cx.error(
122             where_clause,
123             "struct with where-clause is not supported yet",
124         );
125     }
126 
127     let mut fields = Vec::new();
128     for field in named_fields.named {
129         let ident = field.ident.unwrap();
130         let mut cfg = CfgExpr::Unconditional;
131         let mut doc = Doc::new();
132         let mut cxx_name = None;
133         let mut rust_name = None;
134         let attrs = attrs::parse(
135             cx,
136             field.attrs,
137             attrs::Parser {
138                 cfg: Some(&mut cfg),
139                 doc: Some(&mut doc),
140                 cxx_name: Some(&mut cxx_name),
141                 rust_name: Some(&mut rust_name),
142                 ..Default::default()
143             },
144         );
145         let ty = match parse_type(&field.ty) {
146             Ok(ty) => ty,
147             Err(err) => {
148                 cx.push(err);
149                 continue;
150             }
151         };
152         let visibility = visibility_pub(&field.vis, ident.span());
153         let name = pair(Namespace::default(), &ident, cxx_name, rust_name);
154         let colon_token = field.colon_token.unwrap();
155         fields.push(Var {
156             cfg,
157             doc,
158             attrs,
159             visibility,
160             name,
161             colon_token,
162             ty,
163         });
164     }
165 
166     let struct_token = item.struct_token;
167     let visibility = visibility_pub(&item.vis, struct_token.span);
168     let name = pair(namespace, &item.ident, cxx_name, rust_name);
169     let generics = Lifetimes {
170         lt_token: item.generics.lt_token,
171         lifetimes,
172         gt_token: item.generics.gt_token,
173     };
174     let brace_token = named_fields.brace_token;
175 
176     Ok(Api::Struct(Struct {
177         cfg,
178         doc,
179         derives,
180         attrs,
181         visibility,
182         struct_token,
183         name,
184         generics,
185         brace_token,
186         fields,
187     }))
188 }
189 
parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api190 fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
191     let mut cfg = CfgExpr::Unconditional;
192     let mut doc = Doc::new();
193     let mut derives = Vec::new();
194     let mut repr = None;
195     let mut namespace = namespace.clone();
196     let mut cxx_name = None;
197     let mut rust_name = None;
198     let mut variants_from_header = None;
199     let attrs = attrs::parse(
200         cx,
201         item.attrs,
202         attrs::Parser {
203             cfg: Some(&mut cfg),
204             doc: Some(&mut doc),
205             derives: Some(&mut derives),
206             repr: Some(&mut repr),
207             namespace: Some(&mut namespace),
208             cxx_name: Some(&mut cxx_name),
209             rust_name: Some(&mut rust_name),
210             variants_from_header: Some(&mut variants_from_header),
211             ..Default::default()
212         },
213     );
214 
215     if !item.generics.params.is_empty() {
216         let vis = &item.vis;
217         let enum_token = item.enum_token;
218         let ident = &item.ident;
219         let generics = &item.generics;
220         let span = quote!(#vis #enum_token #ident #generics);
221         cx.error(span, "enum with generic parameters is not supported");
222     } else if let Some(where_clause) = &item.generics.where_clause {
223         cx.error(where_clause, "enum with where-clause is not supported");
224     }
225 
226     let mut variants = Vec::new();
227     let mut discriminants = DiscriminantSet::new(repr);
228     for variant in item.variants {
229         match parse_variant(cx, variant, &mut discriminants) {
230             Ok(variant) => variants.push(variant),
231             Err(err) => cx.push(err),
232         }
233     }
234 
235     let enum_token = item.enum_token;
236     let visibility = visibility_pub(&item.vis, enum_token.span);
237     let brace_token = item.brace_token;
238 
239     let explicit_repr = repr.is_some();
240     let mut repr = U8;
241     match discriminants.inferred_repr() {
242         Ok(inferred) => repr = inferred,
243         Err(err) => {
244             let span = quote_spanned!(brace_token.span=> #enum_token {});
245             cx.error(span, err);
246             variants.clear();
247         }
248     }
249 
250     let name = pair(namespace, &item.ident, cxx_name, rust_name);
251     let repr_ident = Ident::new(repr.as_ref(), Span::call_site());
252     let repr_type = Type::Ident(NamedType::new(repr_ident));
253     let repr = EnumRepr::Native {
254         atom: repr,
255         repr_type,
256     };
257     let generics = Lifetimes {
258         lt_token: None,
259         lifetimes: Punctuated::new(),
260         gt_token: None,
261     };
262     let variants_from_header_attr = variants_from_header;
263     let variants_from_header = variants_from_header_attr.is_some();
264 
265     Api::Enum(Enum {
266         cfg,
267         doc,
268         derives,
269         attrs,
270         visibility,
271         enum_token,
272         name,
273         generics,
274         brace_token,
275         variants,
276         variants_from_header,
277         variants_from_header_attr,
278         repr,
279         explicit_repr,
280     })
281 }
282 
parse_variant( cx: &mut Errors, mut variant: RustVariant, discriminants: &mut DiscriminantSet, ) -> Result<Variant>283 fn parse_variant(
284     cx: &mut Errors,
285     mut variant: RustVariant,
286     discriminants: &mut DiscriminantSet,
287 ) -> Result<Variant> {
288     let mut cfg = CfgExpr::Unconditional;
289     let mut doc = Doc::new();
290     let mut cxx_name = None;
291     let mut rust_name = None;
292     let attrs = attrs::parse(
293         cx,
294         mem::take(&mut variant.attrs),
295         attrs::Parser {
296             cfg: Some(&mut cfg),
297             doc: Some(&mut doc),
298             cxx_name: Some(&mut cxx_name),
299             rust_name: Some(&mut rust_name),
300             ..Default::default()
301         },
302     );
303 
304     match variant.fields {
305         Fields::Unit => {}
306         _ => {
307             let msg = "enums with data are not supported yet";
308             return Err(Error::new_spanned(variant, msg));
309         }
310     }
311 
312     let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
313     let try_discriminant = match &expr {
314         Some(lit) => discriminants.insert(lit),
315         None => discriminants.insert_next(),
316     };
317     let discriminant = match try_discriminant {
318         Ok(discriminant) => discriminant,
319         Err(err) => return Err(Error::new_spanned(variant, err)),
320     };
321 
322     let name = pair(Namespace::ROOT, &variant.ident, cxx_name, rust_name);
323     let expr = variant.discriminant.map(|(_, expr)| expr);
324 
325     Ok(Variant {
326         cfg,
327         doc,
328         attrs,
329         name,
330         discriminant,
331         expr,
332     })
333 }
334 
parse_foreign_mod( cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>, trusted: bool, namespace: &Namespace, )335 fn parse_foreign_mod(
336     cx: &mut Errors,
337     foreign_mod: ItemForeignMod,
338     out: &mut Vec<Api>,
339     trusted: bool,
340     namespace: &Namespace,
341 ) {
342     let lang = match parse_lang(&foreign_mod.abi) {
343         Ok(lang) => lang,
344         Err(err) => return cx.push(err),
345     };
346 
347     match lang {
348         Lang::Rust => {
349             if foreign_mod.unsafety.is_some() {
350                 let unsafety = foreign_mod.unsafety;
351                 let abi = &foreign_mod.abi;
352                 let span = quote!(#unsafety #abi);
353                 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
354             }
355         }
356         Lang::Cxx => {}
357     }
358 
359     let trusted = trusted || foreign_mod.unsafety.is_some();
360 
361     let mut cfg = CfgExpr::Unconditional;
362     let mut namespace = namespace.clone();
363     let attrs = attrs::parse(
364         cx,
365         foreign_mod.attrs,
366         attrs::Parser {
367             cfg: Some(&mut cfg),
368             namespace: Some(&mut namespace),
369             ..Default::default()
370         },
371     );
372 
373     let mut items = Vec::new();
374     for foreign in foreign_mod.items {
375         match foreign {
376             ForeignItem::Type(foreign) => {
377                 let ety = parse_extern_type(cx, foreign, lang, trusted, &cfg, &namespace, &attrs);
378                 items.push(ety);
379             }
380             ForeignItem::Fn(foreign) => {
381                 match parse_extern_fn(cx, foreign, lang, trusted, &cfg, &namespace, &attrs) {
382                     Ok(efn) => items.push(efn),
383                     Err(err) => cx.push(err),
384                 }
385             }
386             ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
387                 match foreign.mac.parse_body_with(parse_include) {
388                     Ok(mut include) => {
389                         include.cfg = cfg.clone();
390                         items.push(Api::Include(include));
391                     }
392                     Err(err) => cx.push(err),
393                 }
394             }
395             ForeignItem::Verbatim(tokens) => {
396                 match parse_extern_verbatim(cx, tokens, lang, trusted, &cfg, &namespace, &attrs) {
397                     Ok(api) => items.push(api),
398                     Err(err) => cx.push(err),
399                 }
400             }
401             _ => cx.error(foreign, "unsupported foreign item"),
402         }
403     }
404 
405     if !trusted
406         && items.iter().any(|api| match api {
407             Api::CxxFunction(efn) => efn.unsafety.is_none(),
408             _ => false,
409         })
410     {
411         cx.error(
412             foreign_mod.abi,
413             "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
414         );
415     }
416 
417     let mut types = items.iter().filter_map(|item| match item {
418         Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
419         Api::TypeAlias(alias) => Some(&alias.name),
420         _ => None,
421     });
422     if let (Some(single_type), None) = (types.next(), types.next()) {
423         let single_type = single_type.clone();
424         for item in &mut items {
425             if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
426                 if let Some(receiver) = &mut efn.receiver {
427                     if receiver.ty.rust == "Self" {
428                         receiver.ty.rust = single_type.rust.clone();
429                     }
430                 }
431             }
432         }
433     }
434 
435     out.extend(items);
436 }
437 
parse_lang(abi: &Abi) -> Result<Lang>438 fn parse_lang(abi: &Abi) -> Result<Lang> {
439     let name = match &abi.name {
440         Some(name) => name,
441         None => {
442             return Err(Error::new_spanned(
443                 abi,
444                 "ABI name is required, extern \"C++\" or extern \"Rust\"",
445             ));
446         }
447     };
448 
449     match name.value().as_str() {
450         "C++" => Ok(Lang::Cxx),
451         "Rust" => Ok(Lang::Rust),
452         _ => Err(Error::new_spanned(
453             abi,
454             "unrecognized ABI, requires either \"C++\" or \"Rust\"",
455         )),
456     }
457 }
458 
parse_extern_type( cx: &mut Errors, foreign_type: ForeignItemType, lang: Lang, trusted: bool, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Api459 fn parse_extern_type(
460     cx: &mut Errors,
461     foreign_type: ForeignItemType,
462     lang: Lang,
463     trusted: bool,
464     extern_block_cfg: &CfgExpr,
465     namespace: &Namespace,
466     attrs: &OtherAttrs,
467 ) -> Api {
468     let mut cfg = extern_block_cfg.clone();
469     let mut doc = Doc::new();
470     let mut derives = Vec::new();
471     let mut namespace = namespace.clone();
472     let mut cxx_name = None;
473     let mut rust_name = None;
474     let mut attrs = attrs.clone();
475     attrs.extend(attrs::parse(
476         cx,
477         foreign_type.attrs,
478         attrs::Parser {
479             cfg: Some(&mut cfg),
480             doc: Some(&mut doc),
481             derives: Some(&mut derives),
482             namespace: Some(&mut namespace),
483             cxx_name: Some(&mut cxx_name),
484             rust_name: Some(&mut rust_name),
485             ..Default::default()
486         },
487     ));
488 
489     let type_token = foreign_type.type_token;
490     let visibility = visibility_pub(&foreign_type.vis, type_token.span);
491     let name = pair(namespace, &foreign_type.ident, cxx_name, rust_name);
492     let generics = Lifetimes {
493         lt_token: None,
494         lifetimes: Punctuated::new(),
495         gt_token: None,
496     };
497     let colon_token = None;
498     let bounds = Vec::new();
499     let semi_token = foreign_type.semi_token;
500 
501     (match lang {
502         Lang::Cxx => Api::CxxType,
503         Lang::Rust => Api::RustType,
504     })(ExternType {
505         cfg,
506         lang,
507         doc,
508         derives,
509         attrs,
510         visibility,
511         type_token,
512         name,
513         generics,
514         colon_token,
515         bounds,
516         semi_token,
517         trusted,
518     })
519 }
520 
parse_extern_fn( cx: &mut Errors, mut foreign_fn: ForeignItemFn, lang: Lang, trusted: bool, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Result<Api>521 fn parse_extern_fn(
522     cx: &mut Errors,
523     mut foreign_fn: ForeignItemFn,
524     lang: Lang,
525     trusted: bool,
526     extern_block_cfg: &CfgExpr,
527     namespace: &Namespace,
528     attrs: &OtherAttrs,
529 ) -> Result<Api> {
530     let mut cfg = extern_block_cfg.clone();
531     let mut doc = Doc::new();
532     let mut namespace = namespace.clone();
533     let mut cxx_name = None;
534     let mut rust_name = None;
535     let mut attrs = attrs.clone();
536     attrs.extend(attrs::parse(
537         cx,
538         mem::take(&mut foreign_fn.attrs),
539         attrs::Parser {
540             cfg: Some(&mut cfg),
541             doc: Some(&mut doc),
542             namespace: Some(&mut namespace),
543             cxx_name: Some(&mut cxx_name),
544             rust_name: Some(&mut rust_name),
545             ..Default::default()
546         },
547     ));
548 
549     let generics = &foreign_fn.sig.generics;
550     if generics.where_clause.is_some()
551         || generics.params.iter().any(|param| match param {
552             GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
553             GenericParam::Type(_) | GenericParam::Const(_) => true,
554         })
555     {
556         return Err(Error::new_spanned(
557             foreign_fn,
558             "extern function with generic parameters is not supported yet",
559         ));
560     }
561 
562     if let Some(variadic) = &foreign_fn.sig.variadic {
563         return Err(Error::new_spanned(
564             variadic,
565             "variadic function is not supported yet",
566         ));
567     }
568 
569     if foreign_fn.sig.asyncness.is_some() && !cfg!(feature = "experimental-async-fn") {
570         return Err(Error::new_spanned(
571             foreign_fn,
572             "async function is not directly supported yet, but see https://cxx.rs/async.html \
573             for a working approach, and https://github.com/pcwalton/cxx-async for some helpers; \
574             eventually what you wrote will work but it isn't integrated into the cxx::bridge \
575             macro yet",
576         ));
577     }
578 
579     if foreign_fn.sig.constness.is_some() {
580         return Err(Error::new_spanned(
581             foreign_fn,
582             "const extern function is not supported",
583         ));
584     }
585 
586     if let Some(abi) = &foreign_fn.sig.abi {
587         return Err(Error::new_spanned(
588             abi,
589             "explicit ABI on extern function is not supported",
590         ));
591     }
592 
593     let mut receiver = None;
594     let mut args = Punctuated::new();
595     for arg in foreign_fn.sig.inputs.pairs() {
596         let (arg, comma) = arg.into_tuple();
597         match arg {
598             FnArg::Receiver(arg) => {
599                 if let Some((ampersand, lifetime)) = &arg.reference {
600                     receiver = Some(Receiver {
601                         pinned: false,
602                         ampersand: *ampersand,
603                         lifetime: lifetime.clone(),
604                         mutable: arg.mutability.is_some(),
605                         var: arg.self_token,
606                         colon_token: Token![:](arg.self_token.span),
607                         ty: NamedType::new(Ident::new("Self", arg.self_token.span)),
608                         shorthand: true,
609                         pin_tokens: None,
610                         mutability: arg.mutability,
611                     });
612                     continue;
613                 }
614                 return Err(Error::new_spanned(arg, "unsupported signature"));
615             }
616             FnArg::Typed(arg) => {
617                 let ident = match arg.pat.as_ref() {
618                     Pat::Ident(pat) => pat.ident.clone(),
619                     Pat::Wild(pat) => {
620                         Ident::new(&format!("arg{}", args.len()), pat.underscore_token.span)
621                     }
622                     _ => return Err(Error::new_spanned(arg, "unsupported signature")),
623                 };
624                 let ty = parse_type(&arg.ty)?;
625                 if ident != "self" {
626                     let cfg = CfgExpr::Unconditional;
627                     let doc = Doc::new();
628                     let attrs = OtherAttrs::none();
629                     let visibility = Token![pub](ident.span());
630                     let name = pair(Namespace::default(), &ident, None, None);
631                     let colon_token = arg.colon_token;
632                     args.push_value(Var {
633                         cfg,
634                         doc,
635                         attrs,
636                         visibility,
637                         name,
638                         colon_token,
639                         ty,
640                     });
641                     if let Some(comma) = comma {
642                         args.push_punct(*comma);
643                     }
644                     continue;
645                 }
646                 if let Type::Ref(reference) = ty {
647                     if let Type::Ident(ident) = reference.inner {
648                         receiver = Some(Receiver {
649                             pinned: reference.pinned,
650                             ampersand: reference.ampersand,
651                             lifetime: reference.lifetime,
652                             mutable: reference.mutable,
653                             var: Token![self](ident.rust.span()),
654                             colon_token: arg.colon_token,
655                             ty: ident,
656                             shorthand: false,
657                             pin_tokens: reference.pin_tokens,
658                             mutability: reference.mutability,
659                         });
660                         continue;
661                     }
662                 }
663                 return Err(Error::new_spanned(arg, "unsupported method receiver"));
664             }
665         }
666     }
667 
668     let mut throws_tokens = None;
669     let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
670     let throws = throws_tokens.is_some();
671     let asyncness = foreign_fn.sig.asyncness;
672     let unsafety = foreign_fn.sig.unsafety;
673     let fn_token = foreign_fn.sig.fn_token;
674     let inherited_span = unsafety.map_or(fn_token.span, |unsafety| unsafety.span);
675     let visibility = visibility_pub(&foreign_fn.vis, inherited_span);
676     let name = pair(namespace, &foreign_fn.sig.ident, cxx_name, rust_name);
677     let generics = generics.clone();
678     let paren_token = foreign_fn.sig.paren_token;
679     let semi_token = foreign_fn.semi_token;
680 
681     Ok(match lang {
682         Lang::Cxx => Api::CxxFunction,
683         Lang::Rust => Api::RustFunction,
684     }(ExternFn {
685         cfg,
686         lang,
687         doc,
688         attrs,
689         visibility,
690         name,
691         sig: Signature {
692             asyncness,
693             unsafety,
694             fn_token,
695             generics,
696             receiver,
697             args,
698             ret,
699             throws,
700             paren_token,
701             throws_tokens,
702         },
703         semi_token,
704         trusted,
705     }))
706 }
707 
parse_extern_verbatim( cx: &mut Errors, tokens: TokenStream, lang: Lang, trusted: bool, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Result<Api>708 fn parse_extern_verbatim(
709     cx: &mut Errors,
710     tokens: TokenStream,
711     lang: Lang,
712     trusted: bool,
713     extern_block_cfg: &CfgExpr,
714     namespace: &Namespace,
715     attrs: &OtherAttrs,
716 ) -> Result<Api> {
717     |input: ParseStream| -> Result<Api> {
718         let unparsed_attrs = input.call(Attribute::parse_outer)?;
719         let visibility: Visibility = input.parse()?;
720         if input.peek(Token![type]) {
721             parse_extern_verbatim_type(
722                 cx,
723                 unparsed_attrs,
724                 visibility,
725                 input,
726                 lang,
727                 trusted,
728                 extern_block_cfg,
729                 namespace,
730                 attrs,
731             )
732         } else if input.peek(Token![fn]) {
733             parse_extern_verbatim_fn(input)
734         } else {
735             let span = input.cursor().token_stream();
736             Err(Error::new_spanned(
737                 span,
738                 "unsupported foreign item, expected `type` or `fn`",
739             ))
740         }
741     }
742     .parse2(tokens)
743 }
744 
parse_extern_verbatim_type( cx: &mut Errors, unparsed_attrs: Vec<Attribute>, visibility: Visibility, input: ParseStream, lang: Lang, trusted: bool, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Result<Api>745 fn parse_extern_verbatim_type(
746     cx: &mut Errors,
747     unparsed_attrs: Vec<Attribute>,
748     visibility: Visibility,
749     input: ParseStream,
750     lang: Lang,
751     trusted: bool,
752     extern_block_cfg: &CfgExpr,
753     namespace: &Namespace,
754     attrs: &OtherAttrs,
755 ) -> Result<Api> {
756     let type_token: Token![type] = input.parse()?;
757     let ident: Ident = input.parse()?;
758     let generics: Generics = input.parse()?;
759     let mut lifetimes = Punctuated::new();
760     let mut has_unsupported_generic_param = false;
761     for pair in generics.params.into_pairs() {
762         let (param, punct) = pair.into_tuple();
763         match param {
764             GenericParam::Lifetime(param) => {
765                 if !param.bounds.is_empty() && !has_unsupported_generic_param {
766                     let msg = "lifetime parameter with bounds is not supported yet";
767                     cx.error(&param, msg);
768                     has_unsupported_generic_param = true;
769                 }
770                 lifetimes.push_value(param.lifetime);
771                 if let Some(punct) = punct {
772                     lifetimes.push_punct(punct);
773                 }
774             }
775             GenericParam::Type(param) => {
776                 if !has_unsupported_generic_param {
777                     let msg = "extern type with generic type parameter is not supported yet";
778                     cx.error(&param, msg);
779                     has_unsupported_generic_param = true;
780                 }
781             }
782             GenericParam::Const(param) => {
783                 if !has_unsupported_generic_param {
784                     let msg = "extern type with const generic parameter is not supported yet";
785                     cx.error(&param, msg);
786                     has_unsupported_generic_param = true;
787                 }
788             }
789         }
790     }
791     let lifetimes = Lifetimes {
792         lt_token: generics.lt_token,
793         lifetimes,
794         gt_token: generics.gt_token,
795     };
796     let lookahead = input.lookahead1();
797     if lookahead.peek(Token![=]) {
798         // type Alias = crate::path::to::Type;
799         parse_type_alias(
800             cx,
801             unparsed_attrs,
802             visibility,
803             type_token,
804             ident,
805             lifetimes,
806             input,
807             lang,
808             extern_block_cfg,
809             namespace,
810             attrs,
811         )
812     } else if lookahead.peek(Token![:]) || lookahead.peek(Token![;]) {
813         // type Opaque: Bound2 + Bound2;
814         parse_extern_type_bounded(
815             cx,
816             unparsed_attrs,
817             visibility,
818             type_token,
819             ident,
820             lifetimes,
821             input,
822             lang,
823             trusted,
824             extern_block_cfg,
825             namespace,
826             attrs,
827         )
828     } else {
829         Err(lookahead.error())
830     }
831 }
832 
parse_extern_verbatim_fn(input: ParseStream) -> Result<Api>833 fn parse_extern_verbatim_fn(input: ParseStream) -> Result<Api> {
834     input.parse::<RustSignature>()?;
835     input.parse::<Token![;]>()?;
836     unreachable!()
837 }
838 
parse_type_alias( cx: &mut Errors, unparsed_attrs: Vec<Attribute>, visibility: Visibility, type_token: Token![type], ident: Ident, generics: Lifetimes, input: ParseStream, lang: Lang, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Result<Api>839 fn parse_type_alias(
840     cx: &mut Errors,
841     unparsed_attrs: Vec<Attribute>,
842     visibility: Visibility,
843     type_token: Token![type],
844     ident: Ident,
845     generics: Lifetimes,
846     input: ParseStream,
847     lang: Lang,
848     extern_block_cfg: &CfgExpr,
849     namespace: &Namespace,
850     attrs: &OtherAttrs,
851 ) -> Result<Api> {
852     let eq_token: Token![=] = input.parse()?;
853     let ty: RustType = input.parse()?;
854     let semi_token: Token![;] = input.parse()?;
855 
856     let mut cfg = extern_block_cfg.clone();
857     let mut doc = Doc::new();
858     let mut derives = Vec::new();
859     let mut namespace = namespace.clone();
860     let mut cxx_name = None;
861     let mut rust_name = None;
862     let mut attrs = attrs.clone();
863     attrs.extend(attrs::parse(
864         cx,
865         unparsed_attrs,
866         attrs::Parser {
867             cfg: Some(&mut cfg),
868             doc: Some(&mut doc),
869             derives: Some(&mut derives),
870             namespace: Some(&mut namespace),
871             cxx_name: Some(&mut cxx_name),
872             rust_name: Some(&mut rust_name),
873             ..Default::default()
874         },
875     ));
876 
877     if lang == Lang::Rust {
878         let span = quote!(#type_token #semi_token);
879         let msg = "type alias in extern \"Rust\" block is not supported";
880         return Err(Error::new_spanned(span, msg));
881     }
882 
883     let visibility = visibility_pub(&visibility, type_token.span);
884     let name = pair(namespace, &ident, cxx_name, rust_name);
885 
886     Ok(Api::TypeAlias(TypeAlias {
887         cfg,
888         doc,
889         derives,
890         attrs,
891         visibility,
892         type_token,
893         name,
894         generics,
895         eq_token,
896         ty,
897         semi_token,
898     }))
899 }
900 
parse_extern_type_bounded( cx: &mut Errors, unparsed_attrs: Vec<Attribute>, visibility: Visibility, type_token: Token![type], ident: Ident, generics: Lifetimes, input: ParseStream, lang: Lang, trusted: bool, extern_block_cfg: &CfgExpr, namespace: &Namespace, attrs: &OtherAttrs, ) -> Result<Api>901 fn parse_extern_type_bounded(
902     cx: &mut Errors,
903     unparsed_attrs: Vec<Attribute>,
904     visibility: Visibility,
905     type_token: Token![type],
906     ident: Ident,
907     generics: Lifetimes,
908     input: ParseStream,
909     lang: Lang,
910     trusted: bool,
911     extern_block_cfg: &CfgExpr,
912     namespace: &Namespace,
913     attrs: &OtherAttrs,
914 ) -> Result<Api> {
915     let mut bounds = Vec::new();
916     let colon_token: Option<Token![:]> = input.parse()?;
917     if colon_token.is_some() {
918         loop {
919             match input.parse()? {
920                 TypeParamBound::Trait(TraitBound {
921                     paren_token: None,
922                     modifier: TraitBoundModifier::None,
923                     lifetimes: None,
924                     path,
925                 }) if if let Some(derive) = path.get_ident().and_then(Derive::from) {
926                     bounds.push(derive);
927                     true
928                 } else {
929                     false
930                 } => {}
931                 bound @ TypeParamBound::Trait(_) | bound @ TypeParamBound::Lifetime(_) => {
932                     cx.error(bound, "unsupported trait");
933                 }
934             }
935 
936             let lookahead = input.lookahead1();
937             if lookahead.peek(Token![+]) {
938                 input.parse::<Token![+]>()?;
939             } else if lookahead.peek(Token![;]) {
940                 break;
941             } else {
942                 return Err(lookahead.error());
943             }
944         }
945     }
946     let semi_token: Token![;] = input.parse()?;
947 
948     let mut cfg = extern_block_cfg.clone();
949     let mut doc = Doc::new();
950     let mut derives = Vec::new();
951     let mut namespace = namespace.clone();
952     let mut cxx_name = None;
953     let mut rust_name = None;
954     let mut attrs = attrs.clone();
955     attrs.extend(attrs::parse(
956         cx,
957         unparsed_attrs,
958         attrs::Parser {
959             cfg: Some(&mut cfg),
960             doc: Some(&mut doc),
961             derives: Some(&mut derives),
962             namespace: Some(&mut namespace),
963             cxx_name: Some(&mut cxx_name),
964             rust_name: Some(&mut rust_name),
965             ..Default::default()
966         },
967     ));
968 
969     let visibility = visibility_pub(&visibility, type_token.span);
970     let name = pair(namespace, &ident, cxx_name, rust_name);
971 
972     Ok(match lang {
973         Lang::Cxx => Api::CxxType,
974         Lang::Rust => Api::RustType,
975     }(ExternType {
976         cfg,
977         lang,
978         doc,
979         derives,
980         attrs,
981         visibility,
982         type_token,
983         name,
984         generics,
985         colon_token,
986         bounds,
987         semi_token,
988         trusted,
989     }))
990 }
991 
parse_impl(cx: &mut Errors, imp: ItemImpl) -> Result<Api>992 fn parse_impl(cx: &mut Errors, imp: ItemImpl) -> Result<Api> {
993     let impl_token = imp.impl_token;
994 
995     let mut cfg = CfgExpr::Unconditional;
996     attrs::parse(
997         cx,
998         imp.attrs,
999         attrs::Parser {
1000             cfg: Some(&mut cfg),
1001             ..Default::default()
1002         },
1003     );
1004 
1005     if !imp.items.is_empty() {
1006         let mut span = Group::new(Delimiter::Brace, TokenStream::new());
1007         span.set_span(imp.brace_token.span);
1008         return Err(Error::new_spanned(span, "expected an empty impl block"));
1009     }
1010 
1011     if let Some((bang, path, for_token)) = &imp.trait_ {
1012         let self_ty = &imp.self_ty;
1013         let span = quote!(#bang #path #for_token #self_ty);
1014         return Err(Error::new_spanned(
1015             span,
1016             "unexpected impl, expected something like `impl UniquePtr<T> {}`",
1017         ));
1018     }
1019 
1020     if let Some(where_clause) = imp.generics.where_clause {
1021         return Err(Error::new_spanned(
1022             where_clause,
1023             "where-clause on an impl is not supported yet",
1024         ));
1025     }
1026     let mut impl_generics = Lifetimes {
1027         lt_token: imp.generics.lt_token,
1028         lifetimes: Punctuated::new(),
1029         gt_token: imp.generics.gt_token,
1030     };
1031     for pair in imp.generics.params.into_pairs() {
1032         let (param, punct) = pair.into_tuple();
1033         match param {
1034             GenericParam::Lifetime(def) if def.bounds.is_empty() => {
1035                 impl_generics.lifetimes.push_value(def.lifetime);
1036                 if let Some(punct) = punct {
1037                     impl_generics.lifetimes.push_punct(punct);
1038                 }
1039             }
1040             _ => {
1041                 let span = quote!(#impl_token #impl_generics);
1042                 return Err(Error::new_spanned(
1043                     span,
1044                     "generic parameter on an impl is not supported yet",
1045                 ));
1046             }
1047         }
1048     }
1049 
1050     let mut negative_token = None;
1051     let mut self_ty = *imp.self_ty;
1052     if let RustType::Verbatim(ty) = &self_ty {
1053         let mut iter = ty.clone().into_iter();
1054         if let Some(TokenTree::Punct(punct)) = iter.next() {
1055             if punct.as_char() == '!' {
1056                 let ty = iter.collect::<TokenStream>();
1057                 if !ty.is_empty() {
1058                     negative_token = Some(Token![!](punct.span()));
1059                     self_ty = syn::parse2(ty)?;
1060                 }
1061             }
1062         }
1063     }
1064 
1065     let ty = parse_type(&self_ty)?;
1066     let ty_generics = match &ty {
1067         Type::RustBox(ty)
1068         | Type::RustVec(ty)
1069         | Type::UniquePtr(ty)
1070         | Type::SharedPtr(ty)
1071         | Type::WeakPtr(ty)
1072         | Type::CxxVector(ty) => match &ty.inner {
1073             Type::Ident(ident) => ident.generics.clone(),
1074             _ => Lifetimes::default(),
1075         },
1076         Type::Ident(_)
1077         | Type::Ref(_)
1078         | Type::Ptr(_)
1079         | Type::Str(_)
1080         | Type::Fn(_)
1081         | Type::Void(_)
1082         | Type::SliceRef(_)
1083         | Type::Array(_) => Lifetimes::default(),
1084     };
1085 
1086     let negative = negative_token.is_some();
1087     let brace_token = imp.brace_token;
1088 
1089     Ok(Api::Impl(Impl {
1090         cfg,
1091         impl_token,
1092         impl_generics,
1093         negative,
1094         ty,
1095         ty_generics,
1096         brace_token,
1097         negative_token,
1098     }))
1099 }
1100 
parse_include(input: ParseStream) -> Result<Include>1101 fn parse_include(input: ParseStream) -> Result<Include> {
1102     if input.peek(LitStr) {
1103         let lit: LitStr = input.parse()?;
1104         let span = lit.span();
1105         return Ok(Include {
1106             cfg: CfgExpr::Unconditional,
1107             path: lit.value(),
1108             kind: IncludeKind::Quoted,
1109             begin_span: span,
1110             end_span: span,
1111         });
1112     }
1113 
1114     if input.peek(Token![<]) {
1115         let mut path = String::new();
1116 
1117         let langle: Token![<] = input.parse()?;
1118         while !input.is_empty() && !input.peek(Token![>]) {
1119             let token: TokenTree = input.parse()?;
1120             match token {
1121                 TokenTree::Ident(token) => path += &token.to_string(),
1122                 TokenTree::Literal(token)
1123                     if token
1124                         .to_string()
1125                         .starts_with(|ch: char| ch.is_ascii_digit()) =>
1126                 {
1127                     path += &token.to_string();
1128                 }
1129                 TokenTree::Punct(token) => path.push(token.as_char()),
1130                 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
1131             }
1132         }
1133         let rangle: Token![>] = input.parse()?;
1134 
1135         return Ok(Include {
1136             cfg: CfgExpr::Unconditional,
1137             path,
1138             kind: IncludeKind::Bracketed,
1139             begin_span: langle.span,
1140             end_span: rangle.span,
1141         });
1142     }
1143 
1144     Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
1145 }
1146 
parse_type(ty: &RustType) -> Result<Type>1147 fn parse_type(ty: &RustType) -> Result<Type> {
1148     match ty {
1149         RustType::Reference(ty) => parse_type_reference(ty),
1150         RustType::Ptr(ty) => parse_type_ptr(ty),
1151         RustType::Path(ty) => parse_type_path(ty),
1152         RustType::Array(ty) => parse_type_array(ty),
1153         RustType::BareFn(ty) => parse_type_fn(ty),
1154         RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
1155         _ => Err(Error::new_spanned(ty, "unsupported type")),
1156     }
1157 }
1158 
parse_type_reference(ty: &TypeReference) -> Result<Type>1159 fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
1160     let ampersand = ty.and_token;
1161     let lifetime = ty.lifetime.clone();
1162     let mutable = ty.mutability.is_some();
1163     let mutability = ty.mutability;
1164 
1165     if let RustType::Slice(slice) = ty.elem.as_ref() {
1166         let inner = parse_type(&slice.elem)?;
1167         let bracket = slice.bracket_token;
1168         return Ok(Type::SliceRef(Box::new(SliceRef {
1169             ampersand,
1170             lifetime,
1171             mutable,
1172             bracket,
1173             inner,
1174             mutability,
1175         })));
1176     }
1177 
1178     let inner = parse_type(&ty.elem)?;
1179     let pinned = false;
1180     let pin_tokens = None;
1181 
1182     Ok(match &inner {
1183         Type::Ident(ident) if ident.rust == "str" => {
1184             if ty.mutability.is_some() {
1185                 return Err(Error::new_spanned(ty, "unsupported type"));
1186             } else {
1187                 Type::Str
1188             }
1189         }
1190         _ => Type::Ref,
1191     }(Box::new(Ref {
1192         pinned,
1193         ampersand,
1194         lifetime,
1195         mutable,
1196         inner,
1197         pin_tokens,
1198         mutability,
1199     })))
1200 }
1201 
parse_type_ptr(ty: &TypePtr) -> Result<Type>1202 fn parse_type_ptr(ty: &TypePtr) -> Result<Type> {
1203     let star = ty.star_token;
1204     let mutable = ty.mutability.is_some();
1205     let constness = ty.const_token;
1206     let mutability = ty.mutability;
1207 
1208     let inner = parse_type(&ty.elem)?;
1209 
1210     Ok(Type::Ptr(Box::new(Ptr {
1211         star,
1212         mutable,
1213         inner,
1214         mutability,
1215         constness,
1216     })))
1217 }
1218 
parse_type_path(ty: &TypePath) -> Result<Type>1219 fn parse_type_path(ty: &TypePath) -> Result<Type> {
1220     let path = &ty.path;
1221     if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1222         let segment = &path.segments[0];
1223         let ident = segment.ident.clone();
1224         match &segment.arguments {
1225             PathArguments::None => return Ok(Type::Ident(NamedType::new(ident))),
1226             PathArguments::AngleBracketed(generic) => {
1227                 if ident == "UniquePtr" && generic.args.len() == 1 {
1228                     if let GenericArgument::Type(arg) = &generic.args[0] {
1229                         let inner = parse_type(arg)?;
1230                         return Ok(Type::UniquePtr(Box::new(Ty1 {
1231                             name: ident,
1232                             langle: generic.lt_token,
1233                             inner,
1234                             rangle: generic.gt_token,
1235                         })));
1236                     }
1237                 } else if ident == "SharedPtr" && generic.args.len() == 1 {
1238                     if let GenericArgument::Type(arg) = &generic.args[0] {
1239                         let inner = parse_type(arg)?;
1240                         return Ok(Type::SharedPtr(Box::new(Ty1 {
1241                             name: ident,
1242                             langle: generic.lt_token,
1243                             inner,
1244                             rangle: generic.gt_token,
1245                         })));
1246                     }
1247                 } else if ident == "WeakPtr" && generic.args.len() == 1 {
1248                     if let GenericArgument::Type(arg) = &generic.args[0] {
1249                         let inner = parse_type(arg)?;
1250                         return Ok(Type::WeakPtr(Box::new(Ty1 {
1251                             name: ident,
1252                             langle: generic.lt_token,
1253                             inner,
1254                             rangle: generic.gt_token,
1255                         })));
1256                     }
1257                 } else if ident == "CxxVector" && generic.args.len() == 1 {
1258                     if let GenericArgument::Type(arg) = &generic.args[0] {
1259                         let inner = parse_type(arg)?;
1260                         return Ok(Type::CxxVector(Box::new(Ty1 {
1261                             name: ident,
1262                             langle: generic.lt_token,
1263                             inner,
1264                             rangle: generic.gt_token,
1265                         })));
1266                     }
1267                 } else if ident == "Box" && generic.args.len() == 1 {
1268                     if let GenericArgument::Type(arg) = &generic.args[0] {
1269                         let inner = parse_type(arg)?;
1270                         return Ok(Type::RustBox(Box::new(Ty1 {
1271                             name: ident,
1272                             langle: generic.lt_token,
1273                             inner,
1274                             rangle: generic.gt_token,
1275                         })));
1276                     }
1277                 } else if ident == "Vec" && generic.args.len() == 1 {
1278                     if let GenericArgument::Type(arg) = &generic.args[0] {
1279                         let inner = parse_type(arg)?;
1280                         return Ok(Type::RustVec(Box::new(Ty1 {
1281                             name: ident,
1282                             langle: generic.lt_token,
1283                             inner,
1284                             rangle: generic.gt_token,
1285                         })));
1286                     }
1287                 } else if ident == "Pin" && generic.args.len() == 1 {
1288                     if let GenericArgument::Type(arg) = &generic.args[0] {
1289                         let inner = parse_type(arg)?;
1290                         let pin_token = kw::Pin(ident.span());
1291                         if let Type::Ref(mut inner) = inner {
1292                             inner.pinned = true;
1293                             inner.pin_tokens =
1294                                 Some((pin_token, generic.lt_token, generic.gt_token));
1295                             return Ok(Type::Ref(inner));
1296                         }
1297                     }
1298                 } else {
1299                     let mut lifetimes = Punctuated::new();
1300                     let mut only_lifetimes = true;
1301                     for pair in generic.args.pairs() {
1302                         let (param, punct) = pair.into_tuple();
1303                         if let GenericArgument::Lifetime(param) = param {
1304                             lifetimes.push_value(param.clone());
1305                             if let Some(punct) = punct {
1306                                 lifetimes.push_punct(*punct);
1307                             }
1308                         } else {
1309                             only_lifetimes = false;
1310                             break;
1311                         }
1312                     }
1313                     if only_lifetimes {
1314                         return Ok(Type::Ident(NamedType {
1315                             rust: ident,
1316                             generics: Lifetimes {
1317                                 lt_token: Some(generic.lt_token),
1318                                 lifetimes,
1319                                 gt_token: Some(generic.gt_token),
1320                             },
1321                         }));
1322                     }
1323                 }
1324             }
1325             PathArguments::Parenthesized(_) => {}
1326         }
1327     }
1328 
1329     Err(Error::new_spanned(ty, "unsupported type"))
1330 }
1331 
parse_type_array(ty: &TypeArray) -> Result<Type>1332 fn parse_type_array(ty: &TypeArray) -> Result<Type> {
1333     let inner = parse_type(&ty.elem)?;
1334 
1335     let len_expr = if let Expr::Lit(lit) = &ty.len {
1336         lit
1337     } else {
1338         let msg = "unsupported expression, array length must be an integer literal";
1339         return Err(Error::new_spanned(&ty.len, msg));
1340     };
1341 
1342     let len_token = if let Lit::Int(int) = &len_expr.lit {
1343         int.clone()
1344     } else {
1345         let msg = "array length must be an integer literal";
1346         return Err(Error::new_spanned(len_expr, msg));
1347     };
1348 
1349     let len = len_token.base10_parse::<usize>()?;
1350     if len == 0 {
1351         let msg = "array with zero size is not supported";
1352         return Err(Error::new_spanned(ty, msg));
1353     }
1354 
1355     let bracket = ty.bracket_token;
1356     let semi_token = ty.semi_token;
1357 
1358     Ok(Type::Array(Box::new(Array {
1359         bracket,
1360         inner,
1361         semi_token,
1362         len,
1363         len_token,
1364     })))
1365 }
1366 
parse_type_fn(ty: &TypeBareFn) -> Result<Type>1367 fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
1368     if ty.lifetimes.is_some() {
1369         return Err(Error::new_spanned(
1370             ty,
1371             "function pointer with lifetime parameters is not supported yet",
1372         ));
1373     }
1374 
1375     if ty.variadic.is_some() {
1376         return Err(Error::new_spanned(
1377             ty,
1378             "variadic function pointer is not supported yet",
1379         ));
1380     }
1381 
1382     let args = ty
1383         .inputs
1384         .iter()
1385         .enumerate()
1386         .map(|(i, arg)| {
1387             let (ident, colon_token) = match &arg.name {
1388                 Some((ident, colon_token)) => (ident.clone(), *colon_token),
1389                 None => {
1390                     let fn_span = ty.paren_token.span;
1391                     let ident = format_ident!("arg{}", i, span = fn_span);
1392                     let colon_token = Token![:](fn_span);
1393                     (ident, colon_token)
1394                 }
1395             };
1396             let ty = parse_type(&arg.ty)?;
1397             let cfg = CfgExpr::Unconditional;
1398             let doc = Doc::new();
1399             let attrs = OtherAttrs::none();
1400             let visibility = Token![pub](ident.span());
1401             let name = pair(Namespace::default(), &ident, None, None);
1402             Ok(Var {
1403                 cfg,
1404                 doc,
1405                 attrs,
1406                 visibility,
1407                 name,
1408                 colon_token,
1409                 ty,
1410             })
1411         })
1412         .collect::<Result<_>>()?;
1413 
1414     let mut throws_tokens = None;
1415     let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
1416     let throws = throws_tokens.is_some();
1417 
1418     let asyncness = None;
1419     let unsafety = ty.unsafety;
1420     let fn_token = ty.fn_token;
1421     let generics = Generics::default();
1422     let receiver = None;
1423     let paren_token = ty.paren_token;
1424 
1425     Ok(Type::Fn(Box::new(Signature {
1426         asyncness,
1427         unsafety,
1428         fn_token,
1429         generics,
1430         receiver,
1431         args,
1432         ret,
1433         throws,
1434         paren_token,
1435         throws_tokens,
1436     })))
1437 }
1438 
parse_return_type( ty: &ReturnType, throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>, ) -> Result<Option<Type>>1439 fn parse_return_type(
1440     ty: &ReturnType,
1441     throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
1442 ) -> Result<Option<Type>> {
1443     let mut ret = match ty {
1444         ReturnType::Default => return Ok(None),
1445         ReturnType::Type(_, ret) => ret.as_ref(),
1446     };
1447 
1448     if let RustType::Path(ty) = ret {
1449         let path = &ty.path;
1450         if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1451             let segment = &path.segments[0];
1452             let ident = segment.ident.clone();
1453             if let PathArguments::AngleBracketed(generic) = &segment.arguments {
1454                 if ident == "Result" && generic.args.len() == 1 {
1455                     if let GenericArgument::Type(arg) = &generic.args[0] {
1456                         ret = arg;
1457                         *throws_tokens =
1458                             Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
1459                     }
1460                 }
1461             }
1462         }
1463     }
1464 
1465     match parse_type(ret)? {
1466         Type::Void(_) => Ok(None),
1467         ty => Ok(Some(ty)),
1468     }
1469 }
1470 
visibility_pub(vis: &Visibility, inherited: Span) -> Token![pub]1471 fn visibility_pub(vis: &Visibility, inherited: Span) -> Token![pub] {
1472     Token![pub](match vis {
1473         Visibility::Public(vis) => vis.pub_token.span,
1474         Visibility::Crate(vis) => vis.crate_token.span,
1475         Visibility::Restricted(vis) => vis.pub_token.span,
1476         Visibility::Inherited => inherited,
1477     })
1478 }
1479 
pair( namespace: Namespace, default: &Ident, cxx: Option<ForeignName>, rust: Option<Ident>, ) -> Pair1480 fn pair(
1481     namespace: Namespace,
1482     default: &Ident,
1483     cxx: Option<ForeignName>,
1484     rust: Option<Ident>,
1485 ) -> Pair {
1486     Pair {
1487         namespace,
1488         cxx: cxx
1489             .unwrap_or_else(|| ForeignName::parse(&default.to_string(), default.span()).unwrap()),
1490         rust: rust.unwrap_or_else(|| default.clone()),
1491     }
1492 }
1493