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