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