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