1use proc_macro2::TokenStream;
116use quote::{ToTokens, format_ident};
117use syn::ItemImpl;
118
119use crate::miniextendr_impl::{ClassSystem, ImplAttrs};
120
121#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TraitMethod {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["inherited_signature", "ident", "sig", "invisible", "has_self",
"is_mut", "worker", "unsafe_main_thread", "coerce",
"check_interrupt", "rng", "unwrap_in_r", "serialize",
"return_wrap", "param_defaults", "doc_tags", "skip",
"r_name", "strict", "lifecycle", "r_entry", "r_post_checks",
"r_on_exit", "no_shortcut", "generic", "receiver",
"no_dispatch_dots", "per_param", "preconditions"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.inherited_signature, &self.ident, &self.sig,
&self.invisible, &self.has_self, &self.is_mut, &self.worker,
&self.unsafe_main_thread, &self.coerce,
&self.check_interrupt, &self.rng, &self.unwrap_in_r,
&self.serialize, &self.return_wrap, &self.param_defaults,
&self.doc_tags, &self.skip, &self.r_name, &self.strict,
&self.lifecycle, &self.r_entry, &self.r_post_checks,
&self.r_on_exit, &self.no_shortcut, &self.generic,
&self.receiver, &self.no_dispatch_dots, &self.per_param,
&&self.preconditions];
::core::fmt::Formatter::debug_struct_fields_finish(f, "TraitMethod",
names, values)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TraitMethod {
#[inline]
fn clone(&self) -> Self {
TraitMethod {
inherited_signature: ::core::clone::Clone::clone(&self.inherited_signature),
ident: ::core::clone::Clone::clone(&self.ident),
sig: ::core::clone::Clone::clone(&self.sig),
invisible: ::core::clone::Clone::clone(&self.invisible),
has_self: ::core::clone::Clone::clone(&self.has_self),
is_mut: ::core::clone::Clone::clone(&self.is_mut),
worker: ::core::clone::Clone::clone(&self.worker),
unsafe_main_thread: ::core::clone::Clone::clone(&self.unsafe_main_thread),
coerce: ::core::clone::Clone::clone(&self.coerce),
check_interrupt: ::core::clone::Clone::clone(&self.check_interrupt),
rng: ::core::clone::Clone::clone(&self.rng),
unwrap_in_r: ::core::clone::Clone::clone(&self.unwrap_in_r),
serialize: ::core::clone::Clone::clone(&self.serialize),
return_wrap: ::core::clone::Clone::clone(&self.return_wrap),
param_defaults: ::core::clone::Clone::clone(&self.param_defaults),
doc_tags: ::core::clone::Clone::clone(&self.doc_tags),
skip: ::core::clone::Clone::clone(&self.skip),
r_name: ::core::clone::Clone::clone(&self.r_name),
strict: ::core::clone::Clone::clone(&self.strict),
lifecycle: ::core::clone::Clone::clone(&self.lifecycle),
r_entry: ::core::clone::Clone::clone(&self.r_entry),
r_post_checks: ::core::clone::Clone::clone(&self.r_post_checks),
r_on_exit: ::core::clone::Clone::clone(&self.r_on_exit),
no_shortcut: ::core::clone::Clone::clone(&self.no_shortcut),
generic: ::core::clone::Clone::clone(&self.generic),
receiver: ::core::clone::Clone::clone(&self.receiver),
no_dispatch_dots: ::core::clone::Clone::clone(&self.no_dispatch_dots),
per_param: ::core::clone::Clone::clone(&self.per_param),
preconditions: ::core::clone::Clone::clone(&self.preconditions),
}
}
}Clone)]
126struct TraitMethod {
127 inherited_signature: bool,
130 ident: syn::Ident,
132 sig: syn::Signature,
135 invisible: Option<bool>,
139 has_self: bool,
142 is_mut: bool,
144 worker: bool,
147 unsafe_main_thread: bool,
149 coerce: bool,
151 check_interrupt: bool,
153 rng: bool,
155 unwrap_in_r: bool,
157 serialize: bool,
159 return_wrap: Option<crate::return_wrap::ReturnWrap>,
161 param_defaults: std::collections::HashMap<String, String>,
165 doc_tags: Vec<String>,
175 skip: bool,
178 r_name: Option<String>,
181 strict: bool,
183 lifecycle: Option<crate::lifecycle::LifecycleSpec>,
185 r_entry: Option<String>,
187 r_post_checks: Option<String>,
189 r_on_exit: Option<crate::miniextendr_fn::ROnExit>,
191 no_shortcut: bool,
195 generic: Option<String>,
197 receiver: Option<String>,
198 no_dispatch_dots: bool,
199 per_param: std::collections::HashMap<String, crate::miniextendr_fn::ParamAttrs>,
205 preconditions: Option<bool>,
210}
211
212impl TraitMethod {
213 fn r_method_name(&self) -> String {
217 self.r_name
218 .clone()
219 .unwrap_or_else(|| crate::naming::ident_name(&self.ident))
220 }
221
222 fn c_wrapper_ident(&self, type_ident: &syn::Ident, trait_name: &syn::Ident) -> syn::Ident {
229 crate::naming::trait_member_c_wrapper_ident(type_ident, trait_name, &self.ident)
230 }
231
232 fn c_wrapper_ident_string(&self, type_ident: &syn::Ident, trait_name: &syn::Ident) -> String {
237 crate::naming::trait_member_c_wrapper_string(type_ident, trait_name, &self.ident)
238 }
239
240 fn is_invisible(&self) -> bool {
244 self.invisible == Some(true)
245 }
246
247 fn returns_unit(&self) -> bool {
252 match &self.sig.output {
253 syn::ReturnType::Default => true,
254 syn::ReturnType::Type(_, ty) => {
255 #[allow(non_exhaustive_omitted_patterns)] match ty.as_ref() {
syn::Type::Tuple(t) if t.elems.is_empty() => true,
_ => false,
}matches!(ty.as_ref(), syn::Type::Tuple(t) if t.elems.is_empty())
256 }
257 }
258 }
259
260 fn returns_self(&self) -> bool {
267 #[allow(non_exhaustive_omitted_patterns)] match &self.sig.output {
syn::ReturnType::Type(_, ty) if
#[allow(non_exhaustive_omitted_patterns)] match ty.as_ref() {
syn::Type::Path(p) if
p.path.segments.last().map(|s|
s.ident == "Self").unwrap_or(false) => true,
_ => false,
} => true,
_ => false,
}matches!(&self.sig.output, syn::ReturnType::Type(_, ty)
268 if matches!(ty.as_ref(), syn::Type::Path(p)
269 if p.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false)))
270 }
271
272 fn returns_result_self(&self) -> bool {
277 self.first_generic_arg_is_self("Result")
278 }
279
280 fn returns_option_self(&self) -> bool {
285 self.first_generic_arg_is_self("Option")
286 }
287
288 fn first_generic_arg_is_self(&self, wrapper: &str) -> bool {
292 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
293 return false;
294 };
295 let syn::Type::Path(p) = ty.as_ref() else {
296 return false;
297 };
298 let Some(seg) = p.path.segments.last() else {
299 return false;
300 };
301 if seg.ident != wrapper {
302 return false;
303 }
304 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
305 return false;
306 };
307 #[allow(non_exhaustive_omitted_patterns)] match ab.args.first() {
Some(syn::GenericArgument::Type(syn::Type::Path(ip))) if
ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false) =>
true,
_ => false,
}matches!(ab.args.first(), Some(syn::GenericArgument::Type(syn::Type::Path(ip)))
308 if ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false))
309 }
310
311 fn call_method_def_ident(
315 &self,
316 type_ident: &syn::Ident,
317 trait_name: &syn::Ident,
318 ) -> syn::Ident {
319 match ::quote::__private::IdentFragmentAdapter(&type_ident) {
arg =>
match ::quote::__private::IdentFragmentAdapter(&trait_name) {
arg =>
match ::quote::__private::IdentFragmentAdapter(&self.ident) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("call_method_def_{0}__{1}_{2}",
arg, arg, arg))
}),
::quote::__private::Option::None.or(arg.span()).or(arg.span()).or(arg.span())),
},
},
}format_ident!(
320 "call_method_def_{}__{}_{}",
321 type_ident,
322 trait_name,
323 self.ident
324 )
325 }
326}
327
328#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TraitConst {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "TraitConst",
"ident", &self.ident, "ty", &&self.ty)
}
}Debug)]
333struct TraitConst {
334 ident: syn::Ident,
336 ty: syn::Type,
338}
339
340impl TraitConst {
341 fn c_wrapper_ident(&self, type_ident: &syn::Ident, trait_name: &syn::Ident) -> syn::Ident {
347 crate::naming::trait_member_c_wrapper_ident(type_ident, trait_name, &self.ident)
348 }
349
350 fn c_wrapper_ident_string(&self, type_ident: &syn::Ident, trait_name: &syn::Ident) -> String {
352 crate::naming::trait_member_c_wrapper_string(type_ident, trait_name, &self.ident)
353 }
354
355 fn call_method_def_ident(
357 &self,
358 type_ident: &syn::Ident,
359 trait_name: &syn::Ident,
360 ) -> syn::Ident {
361 match ::quote::__private::IdentFragmentAdapter(&type_ident) {
arg =>
match ::quote::__private::IdentFragmentAdapter(&trait_name) {
arg =>
match ::quote::__private::IdentFragmentAdapter(&self.ident) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("call_method_def_{0}__{1}_{2}",
arg, arg, arg))
}),
::quote::__private::Option::None.or(arg.span()).or(arg.span()).or(arg.span())),
},
},
}format_ident!(
362 "call_method_def_{}__{}_{}",
363 type_ident,
364 trait_name,
365 self.ident
366 )
367 }
368}
369
370pub fn expand_miniextendr_impl_trait(
389 attr: proc_macro::TokenStream,
390 item: proc_macro::TokenStream,
391) -> proc_macro::TokenStream {
392 let attr_tokens = TokenStream::from(attr.clone());
394 let impl_attrs: ImplAttrs = match ::syn::parse::<ImplAttrs>(attr) {
::syn::__private::Ok(data) => data,
::syn::__private::Err(err) => {
return ::syn::__private::TokenStream::from(err.to_compile_error());
}
}syn::parse_macro_input!(attr as ImplAttrs);
395 let impl_item = match ::syn::parse::<ItemImpl>(item) {
::syn::__private::Ok(data) => data,
::syn::__private::Err(err) => {
return ::syn::__private::TokenStream::from(err.to_compile_error());
}
}syn::parse_macro_input!(item as ItemImpl);
396
397 let (trait_path, concrete_type) = match extract_trait_and_type(&impl_item) {
399 Ok(result) => result,
400 Err(e) => return e.into_compile_error().into(),
401 };
402
403 if impl_item.items.is_empty() && !impl_attrs.blanket {
405 let raw_tags = crate::roxygen::roxygen_tags_from_attrs(
408 &impl_item.attrs,
409 crate::roxygen::RdPage::suppressed_if(impl_attrs.noexport && !impl_attrs.internal),
410 );
411 let (doc_tags, param_warnings) = crate::roxygen::strip_method_tags(
412 &raw_tags,
413 &concrete_type.to_token_stream().to_string(),
414 impl_item.impl_token.span,
415 );
416 let no_rd = crate::roxygen::has_roxygen_tag(&doc_tags, "noRd");
417 let mut output = generate_tpie_invocation(
418 &trait_path,
419 &concrete_type,
420 impl_attrs.class_system,
421 no_rd,
422 impl_attrs.internal,
423 impl_attrs.noexport,
424 !crate::r_preconditions::resolve_item_type_checks(
428 None,
429 impl_attrs.preconditions,
430 crate::crate_config::preconditions_default(),
431 falsecfg!(feature = "no-preconditions-default"),
432 ),
433 );
434 output.extend(param_warnings);
435 return output.into();
436 }
437
438 let mut macro_path = trait_path;
441 macro_path.segments.last_mut().unwrap().arguments = syn::PathArguments::None;
442 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(¯o_path, &mut _s);
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_at(&mut _s);
::quote::__private::push_ident(&mut _s, "impl");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&attr_tokens, &mut _s);
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&impl_item, &mut _s);
_s
});
_s
});
_s
}quote::quote! {
443 #macro_path! { @impl { #attr_tokens } { #impl_item } }
444 }
445 .into()
446}
447
448fn extract_trait_and_type(impl_item: &ItemImpl) -> syn::Result<(syn::Path, syn::Type)> {
454 let (_, trait_path, _) = impl_item.trait_.as_ref().ok_or_else(|| {
456 syn::Error::new_spanned(
457 impl_item,
458 "#[miniextendr] must be applied to a trait implementation (impl Trait for Type), \
459 not an inherent impl (impl Type)",
460 )
461 })?;
462
463 let concrete_type = (*impl_item.self_ty).clone();
464
465 Ok((trait_path.clone(), concrete_type))
466}
467
468mod defaults;
471mod method_context;
472mod r_wrappers;
473mod vtable;
474
475use r_wrappers::TraitWrapperOpts;
476use r_wrappers::generate_trait_r_wrapper;
477use vtable::generate_trait_method_c_wrapper;
478use vtable::generate_vtable_static;
479
480fn trait_method_body_lines(call_expr: &str, indent: &str, raise_default: &str) -> Vec<String> {
485 let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.val <- {1}", indent,
call_expr))
})]))vec![format!("{}.val <- {}", indent, call_expr)];
486 lines.extend(
487 crate::method_return_builder::condition_check_lines_with_default(indent, raise_default),
488 );
489 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.val", indent))
})format!("{}.val", indent));
490 lines
491}
492
493fn type_to_symbol_name(ty: &syn::Type) -> String {
512 fn fnv1a_64(data: &[u8]) -> u64 {
517 const OFFSET_BASIS: u64 = 0xcbf29ce484222325;
518 const PRIME: u64 = 0x00000100000001b3;
519 let mut h = OFFSET_BASIS;
520 for &b in data {
521 h ^= b as u64;
522 h = h.wrapping_mul(PRIME);
523 }
524 h
525 }
526
527 match ty {
528 syn::Type::Path(type_path) => {
529 let last = type_path.path.segments.last();
530 let base = last
531 .map(|s| crate::naming::ident_name(&s.ident))
532 .unwrap_or_else(|| "UNKNOWN".to_string());
533
534 let has_generics = last
537 .map(|s| !#[allow(non_exhaustive_omitted_patterns)] match s.arguments {
syn::PathArguments::None => true,
_ => false,
}matches!(s.arguments, syn::PathArguments::None))
538 .unwrap_or(false);
539
540 if has_generics {
541 let token_str = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ty, &mut _s);
_s
}quote::quote!(#ty).to_string();
544 let hash = fnv1a_64(token_str.as_bytes());
545 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_{1:016x}", base, hash))
})format!("{}_{:016x}", base, hash)
546 } else {
547 base
548 }
549 }
550 _ => "UNKNOWN".to_string(),
551 }
552}
553struct TraitAbiMetadata {
560 name: syn::Ident,
561 generic: bool,
562 tag: syn::LitStr,
563 fields: syn::FieldsNamed,
564}
565
566impl syn::parse::Parse for TraitAbiMetadata {
567 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
568 let keyword: syn::Ident = input.parse()?;
569 if keyword != "abi" {
570 return Err(syn::Error::new_spanned(
571 keyword,
572 "expected trait ABI metadata",
573 ));
574 }
575 Ok(Self {
576 name: input.parse()?,
577 generic: input.parse::<syn::LitBool>()?.value,
578 tag: input.parse()?,
579 fields: input.parse()?,
580 })
581 }
582}
583
584struct ImplWithMetadata {
588 attrs: ImplAttrs,
589 implementation: ItemImpl,
590 methods: Vec<syn::TraitItemFn>,
591 generics: syn::Generics,
592 abi: TraitAbiMetadata,
593}
594
595impl syn::parse::Parse for ImplWithMetadata {
596 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
597 input.parse::<::syn::token::Atsyn::Token![@]>()?;
598 input.parse::<::syn::token::Implsyn::Token![impl]>()?;
599 let attrs;
600 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
attrs = braces.content;
_ = attrs;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(attrs in input);
601 let attrs = attrs.parse()?;
602 let implementation;
603 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
implementation = braces.content;
_ = implementation;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(implementation in input);
604 let implementation = implementation.parse()?;
605 let metadata;
606 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
metadata = braces.content;
_ = metadata;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(metadata in input);
607 let mut methods = Vec::new();
608 while !metadata.is_empty() {
609 methods.push(metadata.parse()?);
610 }
611 let generics;
612 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
generics = braces.content;
_ = generics;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(generics in input);
613 Ok(Self {
614 attrs,
615 implementation,
616 methods,
617 generics: generics.parse()?,
618 abi: input.parse()?,
619 })
620 }
621}
622
623impl ImplWithMetadata {
624 fn expand(mut self) -> syn::Result<TokenStream> {
625 vtable::inherit_method_metadata(&mut self.implementation, &self.methods)?;
626 let (trait_path, concrete_type) = extract_trait_and_type(&self.implementation)?;
627 let defaults = defaults::inherited_methods(
628 &self.implementation,
629 &self.methods,
630 &self.generics,
631 &trait_path,
632 )?;
633 Ok(generate_vtable_static(
634 &self.implementation,
635 &trait_path,
636 &concrete_type,
637 &self.attrs,
638 &self.abi,
639 &self.methods,
640 &defaults,
641 ))
642 }
643}
644
645struct TpieInput {
668 concrete_type: syn::Type,
670 trait_path: syn::Path,
672 class_system: ClassSystem,
674 no_rd: bool,
676 internal: bool,
678 noexport: bool,
680 no_preconditions: bool,
685 methods: Vec<TpieMethod>,
687 abi: TraitAbiMetadata,
688}
689
690struct TpieMethod {
694 r_name: String,
696 sig: syn::Signature,
698}
699
700impl syn::parse::Parse for TpieInput {
701 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
702 let kw: syn::Ident = input.parse()?;
704 if kw != "concrete_type" {
705 return Err(syn::Error::new_spanned(
706 &kw,
707 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'concrete_type\', got \'{0}\'",
kw))
})format!("expected 'concrete_type', got '{}'", kw),
708 ));
709 }
710 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
711 let concrete_type: syn::Type = input.parse()?;
712 input.parse::<::syn::token::Semisyn::Token![;]>()?;
713
714 let kw: syn::Ident = input.parse()?;
716 if kw != "trait_path" {
717 return Err(syn::Error::new_spanned(
718 &kw,
719 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'trait_path\', got \'{0}\'",
kw))
})format!("expected 'trait_path', got '{}'", kw),
720 ));
721 }
722 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
723 let trait_path: syn::Path = input.parse()?;
724 input.parse::<::syn::token::Semisyn::Token![;]>()?;
725
726 let kw: syn::Ident = input.parse()?;
728 if kw != "class_system" {
729 return Err(syn::Error::new_spanned(
730 &kw,
731 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'class_system\', got \'{0}\'",
kw))
})format!("expected 'class_system', got '{}'", kw),
732 ));
733 }
734 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
735 let cs_ident: syn::Ident = input.parse()?;
736 input.parse::<::syn::token::Semisyn::Token![;]>()?;
737
738 let class_system = ClassSystem::from_ident(&cs_ident).ok_or_else(|| {
739 syn::Error::new_spanned(&cs_ident, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown class system: {0}",
cs_ident))
})format!("unknown class system: {}", cs_ident))
740 })?;
741
742 let kw: syn::Ident = input.parse()?;
744 if kw != "no_rd" {
745 return Err(syn::Error::new_spanned(
746 &kw,
747 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'no_rd\', got \'{0}\'",
kw))
})format!("expected 'no_rd', got '{}'", kw),
748 ));
749 }
750 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
751 let no_rd_lit: syn::LitBool = input.parse()?;
752 input.parse::<::syn::token::Semisyn::Token![;]>()?;
753 let no_rd = no_rd_lit.value;
754
755 let kw: syn::Ident = input.parse()?;
757 if kw != "internal" {
758 return Err(syn::Error::new_spanned(
759 &kw,
760 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'internal\', got \'{0}\'",
kw))
})format!("expected 'internal', got '{}'", kw),
761 ));
762 }
763 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
764 let internal_lit: syn::LitBool = input.parse()?;
765 input.parse::<::syn::token::Semisyn::Token![;]>()?;
766 let internal = internal_lit.value;
767
768 let kw: syn::Ident = input.parse()?;
770 if kw != "noexport" {
771 return Err(syn::Error::new_spanned(
772 &kw,
773 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'noexport\', got \'{0}\'",
kw))
})format!("expected 'noexport', got '{}'", kw),
774 ));
775 }
776 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
777 let noexport_lit: syn::LitBool = input.parse()?;
778 input.parse::<::syn::token::Semisyn::Token![;]>()?;
779 let noexport = noexport_lit.value;
780
781 let kw: syn::Ident = input.parse()?;
783 if kw != "no_preconditions" {
784 return Err(syn::Error::new_spanned(
785 &kw,
786 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'no_preconditions\', got \'{0}\'",
kw))
})format!("expected 'no_preconditions', got '{}'", kw),
787 ));
788 }
789 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
790 let no_preconditions_lit: syn::LitBool = input.parse()?;
791 input.parse::<::syn::token::Semisyn::Token![;]>()?;
792 let no_preconditions = no_preconditions_lit.value;
793
794 let abi = input.parse()?;
795
796 let mut methods = Vec::new();
798 while !input.is_empty() {
799 let kw: syn::Ident = input.parse()?;
800 if kw != "method" {
801 return Err(syn::Error::new_spanned(
802 &kw,
803 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'method\', got \'{0}\'",
kw))
})format!("expected 'method', got '{}'", kw),
804 ));
805 }
806 let content;
807 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
content = braces.content;
_ = content;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(content in input);
808 methods.push(content.parse::<TpieMethod>()?);
809 }
810
811 Ok(TpieInput {
812 concrete_type,
813 trait_path,
814 class_system,
815 no_rd,
816 internal,
817 noexport,
818 no_preconditions,
819 methods,
820 abi,
821 })
822 }
823}
824
825impl syn::parse::Parse for TpieMethod {
826 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
827 let kw: syn::Ident = input.parse()?;
829 if kw != "r_name" {
830 return Err(syn::Error::new_spanned(
831 &kw,
832 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected \'r_name\', got \'{0}\'",
kw))
})format!("expected 'r_name', got '{}'", kw),
833 ));
834 }
835 input.parse::<::syn::token::Eqsyn::Token![=]>()?;
836 let r_name_ident: syn::Ident = input.parse()?;
837 input.parse::<::syn::token::Semisyn::Token![;]>()?;
838
839 let sig: syn::Signature = input.parse()?;
841 input.parse::<::syn::token::Semisyn::Token![;]>()?;
842
843 Ok(TpieMethod {
844 r_name: crate::naming::ident_name(&r_name_ident),
845 sig,
846 })
847 }
848}
849
850fn rewrite_self_in_params(sig: &mut syn::Signature, concrete_type: &syn::Type) {
861 for input in &mut sig.inputs {
862 if let syn::FnArg::Typed(pt) = input {
863 if crate::type_inspect::self_ref_mutability(&pt.ty).is_some() {
865 continue;
866 }
867 let rewritten = rewrite_self_type(&pt.ty, concrete_type);
868 *pt.ty = rewritten;
869 }
870 }
871}
872
873fn rewrite_self_type(ty: &syn::Type, concrete_type: &syn::Type) -> syn::Type {
875 match ty {
876 syn::Type::Path(tp) => {
877 if tp.path.is_ident("Self") {
878 return concrete_type.clone();
879 }
880 let mut new_tp = tp.clone();
881 for seg in &mut new_tp.path.segments {
882 if let syn::PathArguments::AngleBracketed(args) = &mut seg.arguments {
883 for arg in &mut args.args {
884 if let syn::GenericArgument::Type(inner) = arg {
885 *inner = rewrite_self_type(inner, concrete_type);
886 }
887 }
888 }
889 }
890 syn::Type::Path(new_tp)
891 }
892 syn::Type::Reference(r) => {
893 let mut new_r = r.clone();
894 new_r.elem = Box::new(rewrite_self_type(&r.elem, concrete_type));
895 syn::Type::Reference(new_r)
896 }
897 syn::Type::Tuple(t) => {
898 let mut new_t = t.clone();
899 for elem in &mut new_t.elems {
900 *elem = rewrite_self_type(elem, concrete_type);
901 }
902 syn::Type::Tuple(new_t)
903 }
904 _ => ty.clone(),
905 }
906}
907
908fn unwrap_group_type(ty: &syn::Type) -> syn::Type {
914 match ty {
915 syn::Type::Group(g) => unwrap_group_type(&g.elem),
916 _ => ty.clone(),
917 }
918}
919
920pub fn expand_tpie(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
925 if #[allow(non_exhaustive_omitted_patterns)] match input.clone().into_iter().next()
{
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '@' => true,
_ => false,
}matches!(input.clone().into_iter().next(), Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '@')
926 {
927 let metadata = match ::syn::parse::<ImplWithMetadata>(input) {
::syn::__private::Ok(data) => data,
::syn::__private::Err(err) => {
return ::syn::__private::TokenStream::from(err.to_compile_error());
}
}syn::parse_macro_input!(input as ImplWithMetadata);
928 return metadata
929 .expand()
930 .unwrap_or_else(syn::Error::into_compile_error)
931 .into();
932 }
933 let tpie_input = match ::syn::parse::<TpieInput>(input) {
::syn::__private::Ok(data) => data,
::syn::__private::Err(err) => {
return ::syn::__private::TokenStream::from(err.to_compile_error());
}
}syn::parse_macro_input!(input as TpieInput);
934
935 let concrete_type = unwrap_group_type(&tpie_input.concrete_type);
938 let trait_path = &tpie_input.trait_path;
939 let class_system = tpie_input.class_system;
940
941 let trait_name = &tpie_input.abi.name;
942
943 let type_ident = match &concrete_type {
944 syn::Type::Path(tp) => tp
945 .path
946 .segments
947 .last()
948 .map(|s| s.ident.clone())
949 .unwrap_or_else(|| ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unknown"))
}), ::quote::__private::Option::None)format_ident!("Unknown")),
950 _ => ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unknown"))
}), ::quote::__private::Option::None)format_ident!("Unknown"),
951 };
952
953 let methods: Vec<TraitMethod> = tpie_input
955 .methods
956 .iter()
957 .map(|tm| {
958 let mut sig = tm.sig.clone();
959 rewrite_self_in_params(&mut sig, &concrete_type);
960
961 let (has_self, is_mut) = sig.inputs.first().map_or((false, false), |arg| {
962 if let syn::FnArg::Receiver(_) = arg {
963 (true, crate::trait_receiver::is_mut(&sig))
964 } else {
965 (false, false)
966 }
967 });
968
969 let (invisible, sig) = {
972 let (marker, output) = crate::type_inspect::peel_return_visibility(&sig.output);
973 let mut sig = sig;
974 sig.output = output;
975 (marker, sig)
976 };
977 TraitMethod {
978 inherited_signature: true,
979 ident: sig.ident.clone(),
980 sig,
981 invisible,
982 has_self,
983 is_mut,
984 worker: falsecfg!(feature = "worker-default"),
985 unsafe_main_thread: false,
986 coerce: false,
987 check_interrupt: false,
988 rng: false,
989 unwrap_in_r: false,
990 serialize: false,
991 return_wrap: None,
992 param_defaults: Default::default(),
993 doc_tags: ::alloc::vec::Vec::new()vec![],
994 skip: false,
995 strict: false,
996 lifecycle: None,
997 r_entry: None,
998 r_post_checks: None,
999 r_on_exit: None,
1000 no_shortcut: false,
1001 generic: None,
1002 receiver: None,
1003 no_dispatch_dots: false,
1004 per_param: Default::default(),
1005 preconditions: None,
1006 r_name: if tm.sig.ident == tm.r_name {
1007 None } else {
1009 Some(tm.r_name.clone())
1010 },
1011 }
1012 })
1013 .collect();
1014
1015 let c_wrappers: Vec<TokenStream> = methods
1017 .iter()
1018 .map(|m| generate_trait_method_c_wrapper(m, &type_ident, trait_name, trait_path))
1019 .collect();
1020
1021 let r_wrapper_string = match generate_trait_r_wrapper(
1023 &type_ident,
1024 trait_name,
1025 &methods,
1026 &[], TraitWrapperOpts {
1028 class_system,
1029 class_has_no_rd: tpie_input.no_rd,
1030 internal: tpie_input.internal,
1031 noexport: tpie_input.noexport,
1032 impl_preconditions: Some(!tpie_input.no_preconditions),
1033 },
1034 ) {
1035 Ok(s) => s,
1036 Err(e) => return e.into_compile_error().into(),
1037 };
1038
1039 let type_name_str = type_to_symbol_name(&concrete_type);
1041 let r_wrappers_const = crate::naming::trait_impl_wrappers_ident(&type_name_str, trait_name);
1042
1043 let dispatch_entry_name = crate::naming::trait_dispatch_ident(trait_name, &type_name_str);
1045
1046 let trait_tag = &tpie_input.abi.tag;
1047
1048 let vtable_static_name = crate::naming::vtable_static_ident(trait_name, &type_name_str);
1051
1052 let vtable = match vtable::generate_impl_vtable(
1053 &tpie_input.abi,
1054 &concrete_type,
1055 trait_path,
1056 &methods,
1057 &[],
1058 ) {
1059 Ok(tokens) => tokens,
1060 Err(error) => return error.into_compile_error().into(),
1061 };
1062
1063 let r_wrapper_str = crate::r_wrapper_raw_literal(
1065 &r_wrapper_string,
1066 &crate::r_shadowing::formal_names(
1067 methods.iter().map(|m| (&m.sig.inputs, Default::default())),
1068 ),
1069 );
1070 let source_start = type_ident.span().start();
1071 let source_line_lit = syn::LitInt::new(&source_start.line.to_string(), type_ident.span());
1072 let source_col_lit =
1073 syn::LitInt::new(&(source_start.column + 1).to_string(), type_ident.span());
1074
1075 let expanded = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&vtable, &mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut c_wrappers, i) = c_wrappers.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let c_wrappers =
match c_wrappers.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&c_wrappers, &mut _s);
}
}
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "doc");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "hidden");
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "cfg_attr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "not");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "target_arch");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s, "\"wasm32\"");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"distributed_slice");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "MX_R_WRAPPERS");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "crate");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
_s
});
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"non_upper_case_globals");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "static");
::quote::ToTokens::to_tokens(&r_wrappers_const, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RWrapperEntry");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RWrapperEntry");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "priority");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RWrapperPriority");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TraitImpl");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "source_file");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "file");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "source_line");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&source_line_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "content");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "concat");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::parse(&mut _s,
"\"# Generated from Rust impl `\"");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&trait_name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"` for `\"");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"` (\"");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "file");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\":\"");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&source_line_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\":\"");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&source_col_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\")\"");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&r_wrapper_str, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "doc");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "hidden");
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "cfg_attr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "not");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "target_arch");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s, "\"wasm32\"");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"distributed_slice");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"MX_TRAIT_DISPATCH");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "crate");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "linkme");
_s
});
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"non_upper_case_globals");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "static");
::quote::ToTokens::to_tokens(&dispatch_entry_name, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TraitDispatchEntry");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TraitDispatchEntry");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "concrete_tag");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_tag_from_path");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "concat");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "module_path");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"::\"");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
_s
});
_s
});
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "trait_tag");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_tag_from_path");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&trait_tag, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "vtable");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_ref");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&vtable_static_name, &mut _s);
_s
});
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "cast");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "os");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "raw");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "c_void");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "vtable_symbol");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&vtable_static_name, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1076 #vtable
1077 #(#c_wrappers)*
1079
1080 #[doc(hidden)]
1082 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_R_WRAPPERS), linkme(crate = ::miniextendr_api::linkme))]
1083 #[allow(non_upper_case_globals)]
1084 static #r_wrappers_const: ::miniextendr_api::registry::RWrapperEntry =
1085 ::miniextendr_api::registry::RWrapperEntry {
1086 priority: ::miniextendr_api::registry::RWrapperPriority::TraitImpl,
1087 source_file: ::core::file!(),
1088 source_line: #source_line_lit,
1089 content: ::core::concat!(
1090 "# Generated from Rust impl `",
1091 ::core::stringify!(#trait_name),
1092 "` for `",
1093 ::core::stringify!(#type_ident),
1094 "` (",
1095 ::core::file!(),
1096 ":",
1097 #source_line_lit,
1098 ":",
1099 #source_col_lit,
1100 ")",
1101 #r_wrapper_str
1102 ),
1103 };
1104
1105 #[doc(hidden)]
1107 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_TRAIT_DISPATCH), linkme(crate = ::miniextendr_api::linkme))]
1108 #[allow(non_upper_case_globals)]
1109 static #dispatch_entry_name: ::miniextendr_api::registry::TraitDispatchEntry =
1110 ::miniextendr_api::registry::TraitDispatchEntry {
1111 concrete_tag: ::miniextendr_api::abi::mx_tag_from_path(
1112 ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#type_ident))
1113 ),
1114 trait_tag: ::miniextendr_api::abi::mx_tag_from_path(#trait_tag),
1115 vtable: unsafe {
1116 ::std::ptr::from_ref(&#vtable_static_name).cast::<::std::os::raw::c_void>()
1117 },
1118 vtable_symbol: ::core::stringify!(#vtable_static_name),
1119 };
1120 };
1121
1122 expanded.into()
1123}
1124
1125fn generate_tpie_invocation(
1131 trait_path: &syn::Path,
1132 concrete_type: &syn::Type,
1133 class_system: ClassSystem,
1134 class_has_no_rd: bool,
1135 internal: bool,
1136 noexport: bool,
1137 no_preconditions: bool,
1138) -> TokenStream {
1139 let mut macro_path = trait_path.clone();
1142 macro_path.segments.last_mut().unwrap().arguments = syn::PathArguments::None;
1143 let class_system_ident = class_system.to_ident();
1144 let no_rd_ident = if class_has_no_rd {
1145 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("true"))
}), ::quote::__private::Option::None)format_ident!("true")
1146 } else {
1147 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("false"))
}), ::quote::__private::Option::None)format_ident!("false")
1148 };
1149 let internal_ident = if internal {
1150 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("true"))
}), ::quote::__private::Option::None)format_ident!("true")
1151 } else {
1152 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("false"))
}), ::quote::__private::Option::None)format_ident!("false")
1153 };
1154 let noexport_ident = if noexport {
1155 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("true"))
}), ::quote::__private::Option::None)format_ident!("true")
1156 } else {
1157 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("false"))
}), ::quote::__private::Option::None)format_ident!("false")
1158 };
1159 let no_preconditions_ident = if no_preconditions {
1160 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("true"))
}), ::quote::__private::Option::None)format_ident!("true")
1161 } else {
1162 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("false"))
}), ::quote::__private::Option::None)format_ident!("false")
1163 };
1164
1165 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(¯o_path, &mut _s);
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&class_system_ident, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&no_rd_ident, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&internal_ident, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&noexport_ident, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&no_preconditions_ident, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1166 #macro_path !(#concrete_type, #trait_path, #class_system_ident, #no_rd_ident, #internal_ident, #noexport_ident, #no_preconditions_ident);
1167 }
1168}
1169
1170#[cfg(test)]
1171mod tests;
1172