1use proc_macro2::TokenStream;
8use quote::format_ident;
9use syn::ItemImpl;
10
11use super::r_wrappers::{TraitWrapperOpts, generate_trait_r_wrapper};
12use super::{TraitAbiMetadata, TraitConst, TraitMethod, type_to_symbol_name};
13use crate::miniextendr_impl::{ClassSystem, ImplAttrs};
14
15pub(super) fn generate_vtable_static(
38 impl_item: &ItemImpl,
39 trait_path: &syn::Path,
40 concrete_type: &syn::Type,
41 impl_attrs: &ImplAttrs,
42 abi: &TraitAbiMetadata,
43 declaration: &[syn::TraitItemFn],
44 defaults: &[syn::ImplItemFn],
45) -> TokenStream {
46 let trait_name = &abi.name;
47
48 let type_ident = match concrete_type {
50 syn::Type::Path(type_path) => {
51 let Some(last_seg) = type_path.path.segments.last() else {
52 return syn::Error::new_spanned(
53 concrete_type,
54 "type path must have at least one segment",
55 )
56 .into_compile_error();
57 };
58 last_seg.ident.clone()
59 }
60 _ => ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unknown"))
}), ::quote::__private::Option::None)format_ident!("Unknown"),
61 };
62
63 let type_name_str = type_to_symbol_name(concrete_type);
65
66 let vtable_static_name = crate::naming::vtable_static_ident(trait_name, &type_name_str);
70
71 let impl_page = crate::roxygen::RdPage::suppressed_if(
75 crate::roxygen::attrs_have_roxygen_tag(&impl_item.attrs, "noRd")
76 || (impl_attrs.noexport && !impl_attrs.internal),
77 );
78
79 let mut wrapper_impl = impl_item.clone();
81 wrapper_impl
82 .items
83 .extend(defaults.iter().cloned().map(syn::ImplItem::Fn));
84 let mut all_methods = match extract_methods(&wrapper_impl, impl_page, declaration) {
85 Ok(m) => m,
86 Err(e) => return e.into_compile_error(),
87 };
88 for method in &mut all_methods {
89 method.inherited_signature = defaults
90 .iter()
91 .any(|default| default.sig.ident == method.ident);
92 }
93 let consts = extract_consts(impl_item);
94
95 let methods: Vec<&TraitMethod> = all_methods.iter().filter(|m| !m.skip).collect();
99
100 let method_c_wrappers: Vec<TokenStream> = methods
102 .iter()
103 .map(|m| generate_trait_method_c_wrapper(m, &type_ident, trait_name, trait_path))
104 .collect();
105
106 let const_c_wrappers: Vec<TokenStream> = consts
108 .iter()
109 .map(|c| generate_trait_const_c_wrapper(c, &type_ident, trait_name, trait_path))
110 .collect();
111
112 let c_wrappers: Vec<TokenStream> = method_c_wrappers
114 .into_iter()
115 .chain(const_c_wrappers)
116 .collect();
117
118 let raw_impl_tags = crate::roxygen::roxygen_tags_from_attrs(&impl_item.attrs, impl_page);
120 let (impl_doc_tags, param_warnings) = crate::roxygen::strip_method_tags(
121 &raw_impl_tags,
122 &type_ident.to_string(),
123 impl_item.impl_token.span,
124 );
125 let class_has_no_rd = crate::roxygen::has_roxygen_tag(&impl_doc_tags, "noRd");
126
127 let methods_owned: Vec<TraitMethod> = methods.iter().map(|m| (*m).clone()).collect();
129 let r_wrapper_string = match generate_trait_r_wrapper(
130 &type_ident,
131 trait_name,
132 &methods_owned,
133 &consts,
134 TraitWrapperOpts {
135 class_system: impl_attrs.class_system,
136 class_has_no_rd,
137 internal: impl_attrs.internal,
138 noexport: impl_attrs.noexport,
139 impl_preconditions: impl_attrs.preconditions,
140 },
141 ) {
142 Ok(s) => s,
143 Err(e) => return e.into_compile_error(),
144 };
145
146 let r_wrappers_const = crate::naming::trait_impl_wrappers_ident(&type_name_str, trait_name);
148
149 let dispatch_entry_name = crate::naming::trait_dispatch_ident(trait_name, &type_name_str);
151
152 let trait_tag = &abi.tag;
153
154 let r_wrapper_str = crate::r_wrapper_raw_literal(
156 &r_wrapper_string,
157 &crate::r_shadowing::formal_names(
158 methods_owned
159 .iter()
160 .map(|m| (&m.sig.inputs, Default::default())),
161 ),
162 );
163 let source_loc_doc = crate::source_location_doc(type_ident.span());
164 let source_start = type_ident.span().start();
165 let source_line_lit = syn::LitInt::new(&source_start.line.to_string(), type_ident.span());
166 let source_col_lit =
167 syn::LitInt::new(&(source_start.column + 1).to_string(), type_ident.span());
168
169 let has_items = !all_methods.is_empty() || !consts.is_empty();
177 let clean_impl_tokens = if has_items && !impl_attrs.blanket {
178 let mut clean_impl = impl_item.clone();
179 for item in &mut clean_impl.items {
180 if let syn::ImplItem::Fn(method) = item {
181 method
182 .attrs
183 .retain(|attr| !attr.path().is_ident("miniextendr"));
184 crate::trait_receiver::rewrite(&mut method.sig, Some(&mut method.block));
185 }
186 }
187 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&clean_impl, &mut _s);
_s
}quote::quote! { #clean_impl }
188 } else {
189 ::quote::__private::TokenStream::new();quote::quote! {}
190 };
191
192 let vtable_static_tokens =
193 match generate_impl_vtable(abi, concrete_type, trait_path, &all_methods, declaration) {
194 Ok(tokens) => tokens,
195 Err(error) => return error.into_compile_error(),
196 };
197
198 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&clean_impl_tokens, &mut _s);
::quote::ToTokens::to_tokens(¶m_warnings, &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_eq(&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, "\"Vtable 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(&concrete_type, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"` implementing `\"");
::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_path, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _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, "doc");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s,
"\"Generated by `#[miniextendr]` on the trait impl block.\"");
_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_eq(&mut _s);
::quote::ToTokens::to_tokens(&source_loc_doc, &mut _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, "doc");
::quote::__private::push_eq(&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 source file `\"");
::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, "\"`.\"");
_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, "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::ToTokens::to_tokens(&vtable_static_tokens, &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_eq(&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,
"\"R wrapper code 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, "\"` implementing `\"");
::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, "\"`.\"");
_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, "doc");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&source_loc_doc, &mut _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, "doc");
::quote::__private::push_eq(&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 source file `\"");
::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, "\"`.\"");
_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, "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_eq(&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,
"\"Trait dispatch entry: `\"");
::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, "\"`.\"");
_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, "doc");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&source_loc_doc, &mut _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, "doc");
::quote::__private::push_eq(&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 source file `\"");
::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, "\"`.\"");
_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, "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! {
199 #clean_impl_tokens
202
203 #param_warnings
205
206 #[doc = ::core::concat!(
207 "Vtable for `",
208 ::core::stringify!(#concrete_type),
209 "` implementing `",
210 ::core::stringify!(#trait_path),
211 "`."
212 )]
213 #[doc = "Generated by `#[miniextendr]` on the trait impl block."]
214 #[doc = #source_loc_doc]
215 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
216 #[doc(hidden)]
217 #vtable_static_tokens
218
219 #(#c_wrappers)*
221
222 #[doc = ::core::concat!(
224 "R wrapper code for `",
225 ::core::stringify!(#type_ident),
226 "` implementing `",
227 ::core::stringify!(#trait_name),
228 "`."
229 )]
230 #[doc = #source_loc_doc]
231 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
232 #[doc(hidden)]
233 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_R_WRAPPERS), linkme(crate = ::miniextendr_api::linkme))]
234 #[allow(non_upper_case_globals)]
235 static #r_wrappers_const: ::miniextendr_api::registry::RWrapperEntry =
236 ::miniextendr_api::registry::RWrapperEntry {
237 priority: ::miniextendr_api::registry::RWrapperPriority::TraitImpl,
238 source_file: ::core::file!(),
239 source_line: #source_line_lit,
240 content: ::core::concat!(
241 "# Generated from Rust impl `",
242 ::core::stringify!(#trait_name),
243 "` for `",
244 ::core::stringify!(#type_ident),
245 "` (",
246 ::core::file!(),
247 ":",
248 #source_line_lit,
249 ":",
250 #source_col_lit,
251 ")",
252 #r_wrapper_str
253 ),
254 };
255
256 #[doc = ::core::concat!(
258 "Trait dispatch entry: `",
259 ::core::stringify!(#trait_name),
260 "` for `",
261 ::core::stringify!(#type_ident),
262 "`."
263 )]
264 #[doc = #source_loc_doc]
265 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
266 #[doc(hidden)]
267 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_TRAIT_DISPATCH), linkme(crate = ::miniextendr_api::linkme))]
268 #[allow(non_upper_case_globals)]
269 static #dispatch_entry_name: ::miniextendr_api::registry::TraitDispatchEntry =
270 ::miniextendr_api::registry::TraitDispatchEntry {
271 concrete_tag: ::miniextendr_api::abi::mx_tag_from_path(
272 ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#type_ident))
273 ),
274 trait_tag: ::miniextendr_api::abi::mx_tag_from_path(#trait_tag),
275 vtable: unsafe {
276 ::std::ptr::from_ref(&#vtable_static_name).cast::<::std::os::raw::c_void>()
278 },
279 vtable_symbol: ::core::stringify!(#vtable_static_name),
280 };
281 }
282}
283
284pub(super) fn generate_impl_vtable(
293 abi: &TraitAbiMetadata,
294 concrete_type: &syn::Type,
295 trait_path: &syn::Path,
296 methods: &[TraitMethod],
297 declaration: &[syn::TraitItemFn],
298) -> syn::Result<TokenStream> {
299 let trait_name = &abi.name;
300 let type_name = type_to_symbol_name(concrete_type);
301 let static_name = crate::naming::vtable_static_ident(trait_name, &type_name);
302 let layout_name = crate::naming::vtable_layout_ident(trait_name, &type_name);
303 let fields = &abi.fields;
304 let type_ident = match concrete_type {
305 syn::Type::Path(path) => path.path.segments.last().unwrap().ident.clone(),
306 _ => ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unknown"))
}), ::quote::__private::Option::None)format_ident!("Unknown"),
307 };
308 let mut concrete_methods = Vec::new();
309 let mut initializers = Vec::new();
310 for field in &fields.named {
311 let name = field.ident.as_ref().unwrap();
312 let callback = if abi.generic {
313 let Some(method) = methods.iter().find(|method| method.ident == *name) else {
314 let message = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this impl must define the required trait method `{0}`",
name))
})format!("this impl must define the required trait method `{name}`");
315 return Err(syn::Error::new_spanned(trait_path, message));
316 };
317 concrete_methods.push(method.clone());
318 let shim = crate::naming::vtshim_ident(&type_ident, trait_name, name);
319 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&shim, &mut _s);
_s
}quote::quote!(#shim)
320 } else {
321 let shim = crate::naming::trait_method_shim_ident(trait_name, name);
322 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&shim, &mut _s);
_s
}quote::quote!(<#concrete_type as #trait_path>::#shim)
323 };
324 initializers.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&callback, &mut _s);
_s
}quote::quote!(#name: #callback));
325 }
326 let shims = generate_concrete_vtable_shims(
327 &concrete_methods,
328 &type_ident,
329 trait_name,
330 trait_path,
331 concrete_type,
332 declaration,
333 );
334 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::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, "repr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "C");
_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_camel_case_types");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "pub");
::quote::__private::push_ident(&mut _s, "struct");
::quote::ToTokens::to_tokens(&layout_name, &mut _s);
::quote::ToTokens::to_tokens(&fields, &mut _s);
::quote::ToTokens::to_tokens(&shims, &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, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "no_mangle");
_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, "pub");
::quote::__private::push_ident(&mut _s, "static");
::quote::ToTokens::to_tokens(&static_name, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&layout_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&layout_name, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut initializers, i) = initializers.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let initializers =
match initializers.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&initializers, &mut _s);
}
}
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
335 #[doc(hidden)]
336 #[repr(C)]
337 #[allow(non_camel_case_types)]
338 pub struct #layout_name #fields
339
340 #shims
341 #[doc(hidden)]
342 #[unsafe(no_mangle)]
343 #[allow(non_upper_case_globals)]
344 pub static #static_name: #layout_name = #layout_name {
345 #(#initializers),*
346 };
347 })
348}
349
350fn generate_concrete_vtable_shims(
369 methods: &[TraitMethod],
370 type_ident: &syn::Ident,
371 trait_name: &syn::Ident,
372 trait_path: &syn::Path,
373 concrete_type: &syn::Type,
374 declaration: &[syn::TraitItemFn],
375) -> TokenStream {
376 let mut shims = Vec::new();
377
378 for method in methods {
379 if !method.has_self {
380 continue; }
382
383 let method_ident = &method.ident;
384 let shim_name = crate::naming::vtshim_ident(type_ident, trait_name, method_ident);
385 let data = syn::Ident::new("data", proc_macro2::Span::mixed_site());
388 let argc = syn::Ident::new("argc", proc_macro2::Span::mixed_site());
389 let argv = syn::Ident::new("argv", proc_macro2::Span::mixed_site());
390 let self_ref = syn::Ident::new("self_ref", proc_macro2::Span::mixed_site());
391 let cell = syn::Ident::new("__mx_cell", proc_macro2::Span::mixed_site());
392 let guard = syn::Ident::new("__mx_guard", proc_macro2::Span::mixed_site());
393 let owner_kind = crate::trait_receiver::owner_receiver(&method.sig);
394 let owner = syn::Ident::new("owner", proc_macro2::Span::mixed_site());
395 let owner_parameter = owner_kind.map(|_| {
396 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &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, "SEXP");
::quote::__private::push_comma(&mut _s);
_s
}quote::quote! {
397 #owner: ::miniextendr_api::SEXP,
398 }
399 });
400
401 let param_count = method
403 .sig
404 .inputs
405 .iter()
406 .filter(|a| !#[allow(non_exhaustive_omitted_patterns)] match a {
syn::FnArg::Receiver(_) => true,
_ => false,
}matches!(a, syn::FnArg::Receiver(_)))
407 .count();
408 let expected_argc = param_count as i32;
409
410 let diagnostic_names = declared_param_names(declaration, method_ident)
411 .expect("trait metadata includes each callback's argument names");
412
413 let arg_extractions: Vec<TokenStream> = method
415 .sig
416 .inputs
417 .iter()
418 .filter(|a| !#[allow(non_exhaustive_omitted_patterns)] match a {
syn::FnArg::Receiver(_) => true,
_ => false,
}matches!(a, syn::FnArg::Receiver(_)))
419 .enumerate()
420 .map(|(i, arg)| {
421 if let syn::FnArg::Typed(pt) = arg {
422 let name = if let syn::Pat::Ident(pat_ident) = pt.pat.as_ref() {
423 pat_ident.ident.clone()
424 } else {
425 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::None.or(arg.span())),
}format_ident!("arg{}", i)
426 };
427 crate::trait_self_ref::argument(
428 &name,
429 &diagnostic_names[i],
430 &pt.ty,
431 concrete_type,
432 i,
433 &argv,
434 method
435 .inherited_signature
436 .then(|| crate::trait_signature::argument_ident(&name))
437 .as_ref(),
438 )
439 } else {
440 ::quote::__private::TokenStream::new();quote::quote! {}
441 }
442 })
443 .collect();
444
445 let param_names: Vec<syn::Ident> = method
447 .sig
448 .inputs
449 .iter()
450 .filter(|a| !#[allow(non_exhaustive_omitted_patterns)] match a {
syn::FnArg::Receiver(_) => true,
_ => false,
}matches!(a, syn::FnArg::Receiver(_)))
451 .enumerate()
452 .map(|(i, arg)| {
453 if let syn::FnArg::Typed(pt) = arg
454 && let syn::Pat::Ident(pat_ident) = pt.pat.as_ref()
455 {
456 return pat_ident.ident.clone();
457 }
458 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::None.or(arg.span())),
}format_ident!("arg{}", i)
459 })
460 .collect();
461
462 let targets = method.inherited_signature.then(|| {
463 param_names
464 .iter()
465 .map(crate::trait_signature::argument_ident)
466 .collect::<Vec<_>>()
467 });
468 let type_setup = method.inherited_signature.then(|| {
469 crate::trait_signature::setup(
470 &method.sig.inputs,
471 method.has_self,
472 &crate::trait_signature::callable(
473 &method.sig,
474 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
_s
}quote::quote!(<#concrete_type as #trait_path>::#method_ident),
475 ),
476 )
477 });
478 let native_borrow_checks = crate::trait_self_ref::native_borrow_checks(
479 param_names
480 .iter()
481 .zip(method.sig.inputs.iter().filter_map(|arg| match arg {
482 syn::FnArg::Typed(pt) => Some(pt.ty.as_ref()),
483 syn::FnArg::Receiver(_) => None,
484 }))
485 .enumerate()
486 .map(|(index, (_, ty))| (index, diagnostic_names[index].clone(), ty)),
487 &argv,
488 targets.as_deref(),
489 );
490
491 let self_refs: Vec<_> = param_names
492 .iter()
493 .zip(method.sig.inputs.iter().filter_map(|arg| match arg {
494 syn::FnArg::Typed(pt) => Some(pt.ty.as_ref()),
495 syn::FnArg::Receiver(_) => None,
496 }))
497 .enumerate()
498 .filter_map(|(index, (name, ty))| {
499 crate::type_inspect::self_ref_mutability(ty).map(|mutable| (name, mutable, index))
500 })
501 .collect();
502 let handles: Vec<_> = self_refs
503 .iter()
504 .map(|(name, mutable, index)| {
505 (
506 crate::trait_self_ref::handle_ident(name),
507 *mutable,
508 diagnostic_names[*index].clone(),
509 )
510 })
511 .collect();
512 let alias_checks = crate::trait_self_ref::alias_checks(
513 concrete_type,
514 &handles,
515 Some((crate::trait_self_ref::cell_address(&cell), method.is_mut)),
516 );
517 let self_borrows = self_refs
518 .iter()
519 .map(|(name, mutable, _)| crate::trait_self_ref::borrow(name, *mutable));
520
521 let unwrap_marker = |call: TokenStream| -> TokenStream {
528 let call =
529 crate::type_inspect::prepare_return_value(call, method.invisible, method.serialize);
530 match &method.return_wrap {
531 Some(wrap) => wrap.prepare_value(call),
532 None => call,
533 }
534 };
535 let invocation = unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut param_names, i) = param_names.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let param_names =
match param_names.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(¶m_names, &mut _s);
}
}
_s
});
_s
}quote::quote! {
536 <#concrete_type as #trait_path>::#method_ident(#self_ref, #(#param_names),*)
537 });
538 let receiver = if let Some(kind) = owner_kind {
541 let handle = kind.type_path();
542 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&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::ToTokens::to_tokens(&handle, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_raw_parts");
::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(&owner, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
543 let #self_ref = unsafe {
544 #handle::<#concrete_type>::from_raw_parts(
545 &#owner,
546 #cell,
547 )
548 };
549 }
550 } else {
551 crate::trait_self_ref::receiver_borrow(&cell, &guard, &self_ref, method.is_mut)
552 };
553
554 let has_return = match &method.sig.output {
556 syn::ReturnType::Default => false,
557 syn::ReturnType::Type(_, ty) => {
558 !#[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())
559 }
560 };
561 let result_conversion = if has_return {
562 {
let mut _s = ::quote::__private::TokenStream::new();
::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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "trait_abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "to_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "result");
_s
});
_s
});
_s
}quote::quote! {
563 unsafe { ::miniextendr_api::trait_abi::to_sexp(result) }
564 }
565 } else {
566 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_semi(&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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "trait_abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "nil");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
}quote::quote! {
567 let _ = result;
568 unsafe { ::miniextendr_api::trait_abi::nil() }
569 }
570 };
571
572 let method_name_str = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", trait_name,
method_ident))
})format!("{}::{}", trait_name, method_ident);
573
574 shims.push({
let mut _s = ::quote::__private::TokenStream::new();
::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, "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_snake_case");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_ident(&mut _s, "extern");
::quote::__private::parse(&mut _s, "\"C\"");
::quote::__private::push_ident(&mut _s, "fn");
::quote::ToTokens::to_tokens(&shim_name, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&data, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::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_comma(&mut _s);
::quote::ToTokens::to_tokens(&owner_parameter, &mut _s);
::quote::ToTokens::to_tokens(&argc, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "i32");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&argv, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::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, "SEXP");
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_rarrow(&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, "SEXP");
::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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "unwind_protect");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"with_r_unwind_protect_shim");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or_or(&mut _s);
::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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "trait_abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "check_arity");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&argc, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&expected_argc, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&method_name_str, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_eq(&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_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&data, &mut _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, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "cell");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RefCell");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete_type, &mut _s);
::quote::__private::push_shr(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&type_setup, &mut _s);
::quote::ToTokens::to_tokens(&native_borrow_checks,
&mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut arg_extractions, i) =
arg_extractions.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let arg_extractions =
match arg_extractions.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&arg_extractions, &mut _s);
}
}
::quote::ToTokens::to_tokens(&alias_checks, &mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut self_borrows, i) = self_borrows.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let self_borrows =
match self_borrows.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&self_borrows, &mut _s);
}
}
::quote::ToTokens::to_tokens(&receiver, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&invocation, &mut _s);
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&result_conversion, &mut _s);
_s
});
_s
});
_s
});
_s
}quote::quote! {
575 #[doc(hidden)]
576 #[allow(non_snake_case)]
577 unsafe extern "C" fn #shim_name(
578 #data: *mut ::std::os::raw::c_void,
579 #owner_parameter
580 #argc: i32,
581 #argv: *const ::miniextendr_api::SEXP,
582 ) -> ::miniextendr_api::SEXP {
583 ::miniextendr_api::unwind_protect::with_r_unwind_protect_shim(|| {
587 ::miniextendr_api::trait_abi::check_arity(#argc, #expected_argc, #method_name_str);
588 let #cell = unsafe { &*#data.cast::<::core::cell::RefCell<#concrete_type>>() };
589 #type_setup
590 #native_borrow_checks
591 #(#arg_extractions)*
592 #alias_checks
593 #(#self_borrows)*
594 #receiver
595 let result = #invocation;
596 #result_conversion
597 })
598 }
599 });
600 }
601
602 {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut shims, i) = shims.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let shims =
match shims.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&shims, &mut _s);
}
}
_s
}quote::quote! { #(#shims)* }
603}
604
605pub(super) fn inherit_method_metadata(
609 implementation: &mut ItemImpl,
610 declaration: &[syn::TraitItemFn],
611) -> syn::Result<()> {
612 for item in &mut implementation.items {
613 let syn::ImplItem::Fn(method) = item else {
614 continue;
615 };
616 let Some(declared) = declaration
617 .iter()
618 .find(|declared| declared.sig.ident == method.sig.ident)
619 else {
620 continue; };
622 let inherited = parse_trait_method_attrs(&declared.attrs)?;
623 let own = parse_trait_method_attrs(&method.attrs)?;
624 if own.r_name.is_none()
625 && let Some(r_name) = inherited.r_name
626 {
627 method
628 .attrs
629 .push(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::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, "miniextendr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "r_name");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&r_name, &mut _s);
_s
});
_s
});
_s
})syn::parse_quote!(#[miniextendr(r_name = #r_name)]));
630 }
631 if inherited.skip && !own.skip {
632 method.attrs.push(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::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, "miniextendr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "skip");
_s
});
_s
});
_s
})syn::parse_quote!(#[miniextendr(skip)]));
633 }
634 }
635 Ok(())
636}
637
638fn declared_param_names(
641 declaration: &[syn::TraitItemFn],
642 method: &syn::Ident,
643) -> Option<Vec<String>> {
644 let declared = declaration
645 .iter()
646 .find(|declared| declared.sig.ident == *method)?;
647 Some(
648 declared
649 .sig
650 .inputs
651 .iter()
652 .filter_map(|arg| match arg {
653 syn::FnArg::Typed(arg) => Some(arg),
654 syn::FnArg::Receiver(_) => None,
655 })
656 .map(|arg| {
657 let syn::Pat::Ident(name) = arg.pat.as_ref() else {
658 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("metadata has named arguments")));
}unreachable!("metadata has named arguments")
659 };
660 crate::naming::ident_name(&name.ident)
661 })
662 .collect(),
663 )
664}
665
666pub(super) fn extract_methods(
674 impl_item: &ItemImpl,
675 impl_page: crate::roxygen::RdPage,
676 declaration: &[syn::TraitItemFn],
677) -> syn::Result<Vec<TraitMethod>> {
678 let mut methods = Vec::new();
679 for item in &impl_item.items {
680 if let syn::ImplItem::Fn(method) = item {
681 let (has_self, is_mut) = method.sig.inputs.first().map_or((false, false), |arg| {
683 if let syn::FnArg::Receiver(_) = arg {
684 (true, crate::trait_receiver::is_mut(&method.sig))
685 } else {
686 (false, false)
687 }
688 });
689 crate::miniextendr_fn::refuse_lazy_dots_in_trait_method(&method.sig.inputs)?;
692 crate::miniextendr_fn::refuse_rng_guard_in_trait_method(&method.sig.inputs)?;
693 let mut attrs = parse_trait_method_attrs(&method.attrs)?;
694 crate::miniextendr_fn::finalize_method_param_attrs(
699 &mut attrs.per_param,
700 &method.sig.inputs,
701 &[],
702 &attrs.defaults,
703 attrs
704 .per_param_span
705 .unwrap_or_else(|| method.sig.ident.span()),
706 )?;
707 check_trait_method_defaults(
708 &attrs.defaults,
709 &method.sig.inputs,
710 attrs
711 .defaults_span
712 .unwrap_or_else(|| method.sig.ident.span()),
713 )?;
714
715 let doc_tags = crate::roxygen::roxygen_tags_from_attrs(&method.attrs, impl_page);
720
721 if let syn::ReturnType::Type(_, ty) = &method.sig.output
724 && let Some(err) = crate::type_inspect::visibility_marker_error(ty, "return")
725 {
726 return Err(err);
727 }
728 let (invisible, output) =
729 crate::type_inspect::peel_return_visibility(&method.sig.output);
730 let mut sig = method.sig.clone();
731 let declared = declared_param_names(declaration, &method.sig.ident);
737 let mut used_names: std::collections::HashSet<_> = sig
738 .inputs
739 .iter()
740 .filter_map(|arg| match arg {
741 syn::FnArg::Typed(arg) => match arg.pat.as_ref() {
742 syn::Pat::Ident(pat) => Some(crate::naming::ident_name(&pat.ident)),
743 _ => None,
744 },
745 _ => None,
746 })
747 .collect();
748 for (index, arg) in sig
749 .inputs
750 .iter_mut()
751 .filter_map(|arg| match arg {
752 syn::FnArg::Typed(arg) => Some(arg),
753 _ => None,
754 })
755 .enumerate()
756 {
757 if !#[allow(non_exhaustive_omitted_patterns)] match arg.pat.as_ref() {
syn::Pat::Ident(_) => true,
_ => false,
}matches!(arg.pat.as_ref(), syn::Pat::Ident(_)) {
758 let mut name = declared
759 .as_ref()
760 .and_then(|names| names.get(index).cloned())
761 .unwrap_or_else(|| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", index))
})format!("arg{index}"));
762 while !used_names.insert(name.clone()) {
763 name.push('_');
764 }
765 let name = crate::naming::name_ident(&name);
766 arg.pat = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
})syn::parse_quote!(#name);
767 }
768 }
769 let (return_wrap, output) = crate::return_wrap::resolve(&output, attrs.wrap)?;
770 if return_wrap
771 .as_ref()
772 .is_some_and(|wrap| wrap.conversion.is_some())
773 {
774 return Err(syn::Error::new_spanned(
775 &method.sig.output,
776 "ConvertTo/ConvertFrom require an inherent S7 impl method",
777 ));
778 }
779 if return_wrap.is_some() && (attrs.serialize || attrs.unwrap_in_r) {
780 return Err(syn::Error::new_spanned(
781 &method.sig.output,
782 "explicit class wrapping cannot be combined with serialize or unwrap_in_r",
783 ));
784 }
785 sig.output = crate::type_inspect::serialize_return_type(&output, attrs.serialize);
786
787 methods.push(TraitMethod {
788 inherited_signature: false,
789 ident: method.sig.ident.clone(),
790 sig,
791 invisible,
792 has_self,
793 is_mut,
794 worker: attrs.worker,
795 unsafe_main_thread: attrs.unsafe_main_thread,
796 coerce: attrs.coerce,
797 check_interrupt: attrs.check_interrupt,
798 rng: attrs.rng,
799 unwrap_in_r: attrs.unwrap_in_r,
800 serialize: attrs.serialize,
801 return_wrap,
802 param_defaults: attrs.defaults,
803 doc_tags,
804 skip: attrs.skip,
805 r_name: attrs.r_name,
806 strict: attrs.strict,
807 lifecycle: attrs.lifecycle,
808 r_entry: attrs.r_entry,
809 r_post_checks: attrs.r_post_checks,
810 r_on_exit: attrs.r_on_exit,
811 no_shortcut: attrs.no_shortcut,
812 generic: attrs.generic,
813 receiver: attrs.receiver,
814 no_dispatch_dots: attrs.no_dispatch_dots,
815 per_param: attrs.per_param,
816 preconditions: attrs.preconditions,
817 });
818 }
819 }
820 Ok(methods)
821}
822
823fn check_trait_method_defaults(
827 defaults: &std::collections::HashMap<String, String>,
828 inputs: &syn::punctuated::Punctuated<syn::FnArg, ::syn::token::Commasyn::Token![,]>,
829 span: proc_macro2::Span,
830) -> syn::Result<()> {
831 let names: std::collections::HashSet<String> = inputs
832 .iter()
833 .filter_map(|arg| match arg {
834 syn::FnArg::Typed(pt) => match pt.pat.as_ref() {
835 syn::Pat::Ident(pat_ident) => Some(crate::naming::ident_name(&pat_ident.ident)),
836 _ => None,
837 },
838 syn::FnArg::Receiver(_) => None,
839 })
840 .collect();
841 let mut invalid: Vec<&str> = defaults
842 .keys()
843 .map(String::as_str)
844 .filter(|key| !names.contains(key.strip_prefix("r#").unwrap_or(key)))
845 .collect();
846 if invalid.is_empty() {
847 return Ok(());
848 }
849 invalid.sort_unstable();
850 Err(syn::Error::new(
851 span,
852 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("defaults(...) references non-existent parameter(s): {0}",
invalid.join(", ")))
})format!(
853 "defaults(...) references non-existent parameter(s): {}",
854 invalid.join(", ")
855 ),
856 ))
857}
858
859struct TraitMethodAttrs {
864 worker: bool,
866 unsafe_main_thread: bool,
868 coerce: bool,
871 check_interrupt: bool,
873 rng: bool,
875 unwrap_in_r: bool,
877 serialize: bool,
879 wrap: Option<ClassSystem>,
880 skip: bool,
882 defaults: std::collections::HashMap<String, String>,
884 r_name: Option<String>,
886 strict: bool,
889 lifecycle: Option<crate::lifecycle::LifecycleSpec>,
891 r_entry: Option<String>,
893 r_post_checks: Option<String>,
895 r_on_exit: Option<crate::miniextendr_fn::ROnExit>,
897 no_shortcut: bool,
899 generic: Option<String>,
900 receiver: Option<String>,
901 no_dispatch_dots: bool,
902 preconditions: Option<bool>,
905 per_param: std::collections::HashMap<String, crate::miniextendr_fn::ParamAttrs>,
908 per_param_span: Option<proc_macro2::Span>,
912 defaults_span: Option<proc_macro2::Span>,
915}
916
917fn parse_trait_method_attrs(attrs: &[syn::Attribute]) -> syn::Result<TraitMethodAttrs> {
928 use syn::spanned::Spanned;
929 let mut worker = false;
930 let mut unsafe_main_thread = false;
931 let mut coerce: Option<bool> = None;
932 let mut check_interrupt = false;
933 let mut rng = false;
934 let mut unwrap_in_r = false;
935 let mut serialize = false;
936 let mut wrap = None;
937 let mut skip = false;
938 let mut strict: Option<bool> = None;
939 let mut defaults = std::collections::HashMap::new();
940 let mut r_name: Option<String> = None;
941 let mut lifecycle: Option<crate::lifecycle::LifecycleSpec> = None;
942 let mut r_entry: Option<String> = None;
943 let mut r_post_checks: Option<String> = None;
944 let mut r_on_exit: Option<crate::miniextendr_fn::ROnExit> = None;
945 let mut no_shortcut = false;
946 let mut generic = None;
947 let mut receiver = None;
948 let mut no_dispatch_dots = false;
949 let mut preconditions: Option<bool> = None;
950 let mut per_param: std::collections::HashMap<String, crate::miniextendr_fn::ParamAttrs> =
951 std::collections::HashMap::new();
952 let mut per_param_span: Option<proc_macro2::Span> = None;
953 let mut defaults_span: Option<proc_macro2::Span> = None;
954
955 for attr in attrs {
956 if !attr.path().is_ident("miniextendr") {
957 continue;
958 }
959
960 attr.parse_nested_meta(|meta| {
961 let is_class_meta = meta.path.is_ident("env")
962 || meta.path.is_ident("r6")
963 || meta.path.is_ident("s7")
964 || meta.path.is_ident("s3")
965 || meta.path.is_ident("s4");
966
967 if is_class_meta {
968 meta.parse_nested_meta(|inner| {
969 if inner.path.is_ident("worker") {
970 worker = true;
971 crate::deprecation::worker_option(inner.path.span());
972 } else if inner.path.is_ident("main_thread") {
973 unsafe_main_thread = true;
974 } else if inner.path.is_ident("coerce") {
975 coerce = Some(true);
976 } else if inner.path.is_ident("no_coerce") {
977 coerce = Some(false);
978 } else if inner.path.is_ident("check_interrupt") {
979 check_interrupt = true;
980 } else if inner.path.is_ident("unwrap_in_r") {
981 unwrap_in_r = true;
982 } else if inner.path.is_ident("wrap") {
983 let value: syn::LitStr = inner.value()?.parse()?;
984 wrap = Some(crate::return_wrap::parse_system(&value)?);
985 } else if inner.path.is_ident("serialize") {
986 serialize = true;
987 } else if inner.path.is_ident("no_shortcut") {
988 no_shortcut = true;
989 } else if (meta.path.is_ident("s3") || meta.path.is_ident("s4"))
990 && inner.path.is_ident("generic")
991 {
992 let value: syn::LitStr = inner.value()?.parse()?;
993 if generic
994 .replace(crate::naming::parse_generic(&value)?)
995 .is_some()
996 {
997 return Err(inner.error("generic may be specified only once"));
998 }
999 } else if (meta.path.is_ident("s3") || meta.path.is_ident("s4"))
1000 && inner.path.is_ident("receiver")
1001 {
1002 let value: syn::LitStr = inner.value()?.parse()?;
1003 if receiver.replace(crate::naming::parse_r_receiver(&value)?).is_some() {
1004 return Err(inner.error("receiver may be specified only once"));
1005 }
1006 } else if (meta.path.is_ident("s3") || meta.path.is_ident("s4"))
1007 && inner.path.is_ident("no_dots")
1008 {
1009 no_dispatch_dots = true;
1010 } else {
1011 return Err(inner.error(
1012 "unknown nested option; expected `worker`, `main_thread`, `coerce`, \
1013 `no_coerce`, `check_interrupt`, `unwrap_in_r`, `serialize`, or \
1014 `no_shortcut` (S3/S4 also accept `generic`, `receiver`, `no_dots`)",
1015 ));
1016 }
1017 Ok(())
1018 })?;
1019 } else if meta.path.is_ident("worker") {
1020 worker = true;
1021 crate::deprecation::worker_option(meta.path.span());
1022 } else if meta.path.is_ident("main_thread") {
1023 unsafe_main_thread = true;
1024 } else if meta.path.is_ident("coerce") {
1025 coerce = Some(true);
1026 } else if meta.path.is_ident("no_coerce") {
1027 coerce = Some(false);
1028 } else if meta.path.is_ident("check_interrupt") {
1029 check_interrupt = true;
1030 } else if meta.path.is_ident("rng") {
1031 if meta.input.peek(syn::token::Paren) {
1032 return crate::miniextendr_fn::refuse_rng_seed_on_method(
1033 &meta,
1034 "a trait method",
1035 );
1036 }
1037 rng = true;
1038 } else if meta.path.is_ident("unwrap_in_r") {
1039 unwrap_in_r = true;
1040 } else if meta.path.is_ident("wrap") {
1041 let value: syn::LitStr = meta.value()?.parse()?;
1042 wrap = Some(crate::return_wrap::parse_system(&value)?);
1043 } else if meta.path.is_ident("serialize") {
1044 serialize = true;
1045 } else if meta.path.is_ident("skip") {
1046 skip = true;
1047 } else if meta.path.is_ident("no_shortcut") {
1048 no_shortcut = true;
1049 } else if meta.path.is_ident("r_name") {
1050 let value: syn::LitStr = meta.value()?.parse()?;
1051 r_name = Some(value.value());
1052 } else if meta.path.is_ident("strict") {
1053 strict = Some(true);
1054 } else if meta.path.is_ident("no_strict") {
1055 strict = Some(false);
1056 } else if meta.path.is_ident("defaults") {
1057 defaults_span.get_or_insert(meta.path.span());
1059 meta.parse_nested_meta(|inner| {
1060 let param_name = inner
1061 .path
1062 .get_ident()
1063 .map(|i| i.to_string())
1064 .unwrap_or_default();
1065 let value: syn::LitStr = inner.value()?.parse()?;
1066 defaults.insert(param_name, value.value());
1067 Ok(())
1068 })?;
1069 } else if meta.path.is_ident("lifecycle") {
1070 if meta.input.peek(::syn::token::Eqsyn::Token![=]) {
1071 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1073 let value: syn::LitStr = meta.input.parse()?;
1074 let stage = crate::lifecycle::LifecycleStage::from_str(&value.value())
1075 .ok_or_else(|| {
1076 syn::Error::new(
1077 value.span(),
1078 "invalid lifecycle stage; expected one of: experimental, stable, superseded, soft-deprecated, deprecated, defunct",
1079 )
1080 })?;
1081 lifecycle = Some(crate::lifecycle::LifecycleSpec::new(stage));
1082 } else {
1083 let mut spec = crate::lifecycle::LifecycleSpec::default();
1085 meta.parse_nested_meta(|inner| {
1086 let key = inner.path.get_ident()
1087 .ok_or_else(|| inner.error("expected identifier"))?
1088 .to_string();
1089 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1090 let value: syn::LitStr = inner.input.parse()?;
1091 match key.as_str() {
1092 "stage" => {
1093 spec.stage = crate::lifecycle::LifecycleStage::from_str(&value.value())
1094 .ok_or_else(|| syn::Error::new(value.span(), "invalid lifecycle stage"))?;
1095 }
1096 "when" => spec.when = Some(value.value()),
1097 "what" => spec.what = Some(value.value()),
1098 "with" => spec.with = Some(value.value()),
1099 "details" => spec.details = Some(value.value()),
1100 "id" => spec.id = Some(value.value()),
1101 _ => return Err(inner.error(
1102 "unknown lifecycle option; expected: stage, when, what, with, details, id"
1103 )),
1104 }
1105 Ok(())
1106 })?;
1107 lifecycle = Some(spec);
1108 }
1109 } else if meta.path.is_ident("r_entry") {
1110 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1111 let value: syn::LitStr = meta.input.parse()?;
1112 r_entry = Some(value.value());
1113 } else if meta.path.is_ident("r_post_checks") {
1114 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1115 let value: syn::LitStr = meta.input.parse()?;
1116 r_post_checks = Some(value.value());
1117 } else if meta.path.is_ident("r_on_exit") {
1118 if meta.input.peek(::syn::token::Eqsyn::Token![=]) {
1119 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1121 let value: syn::LitStr = meta.input.parse()?;
1122 r_on_exit = Some(crate::miniextendr_fn::ROnExit {
1123 expr: value.value(),
1124 add: true,
1125 after: true,
1126 });
1127 } else {
1128 let mut expr = None;
1130 let mut add = true;
1131 let mut after = true;
1132 meta.parse_nested_meta(|inner| {
1133 if inner.path.is_ident("expr") {
1134 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1135 let value: syn::LitStr = inner.input.parse()?;
1136 expr = Some(value.value());
1137 } else if inner.path.is_ident("add") {
1138 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1139 let value: syn::LitBool = inner.input.parse()?;
1140 add = value.value;
1141 } else if inner.path.is_ident("after") {
1142 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1143 let value: syn::LitBool = inner.input.parse()?;
1144 after = value.value;
1145 } else {
1146 return Err(inner.error(
1147 "unknown r_on_exit option; expected `expr`, `add`, or `after`",
1148 ));
1149 }
1150 Ok(())
1151 })?;
1152 let expr = expr.ok_or_else(|| {
1153 meta.error("r_on_exit(...) requires `expr = \"...\"` specifying the R expression")
1154 })?;
1155 r_on_exit = Some(crate::miniextendr_fn::ROnExit { expr, add, after });
1156 }
1157 } else if meta.path.is_ident("choices") {
1158 per_param_span.get_or_insert(meta.path.span());
1159 meta.parse_nested_meta(|inner| {
1175 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1176 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1177 let value: syn::LitStr = inner.input.parse()?;
1178 let choices = crate::r_wrapper_builder::split_choice_list(&value.value());
1179 per_param.entry(name).or_default().choices = Some(choices);
1180 Ok(())
1181 })?;
1182 } else if meta.path.is_ident("choices_several_ok") {
1183 per_param_span.get_or_insert(meta.path.span());
1184 meta.parse_nested_meta(|inner| {
1186 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1187 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1188 let value: syn::LitStr = inner.input.parse()?;
1189 let choices = crate::r_wrapper_builder::split_choice_list(&value.value());
1190 let entry = per_param.entry(name).or_default();
1191 entry.choices = Some(choices);
1192 entry.several_ok = true;
1193 Ok(())
1194 })?;
1195 } else if meta.path.is_ident("no_default") {
1196 per_param_span.get_or_insert(meta.path.span());
1197 crate::miniextendr_fn::parse_method_no_default(&meta, &mut per_param)?;
1200 } else if meta.path.is_ident("preconditions") || meta.path.is_ident("no_preconditions")
1201 {
1202 let keep = meta.path.is_ident("preconditions");
1206 if meta.input.peek(syn::token::Paren) {
1207 per_param_span.get_or_insert(meta.path.span());
1208 crate::miniextendr_fn::parse_method_preconditions(&meta, &mut per_param, keep)?;
1209 } else {
1210 preconditions = Some(keep);
1211 }
1212 } else if meta.path.is_ident("no_na") {
1213 per_param_span.get_or_insert(meta.path.span());
1214 crate::miniextendr_fn::parse_method_no_na(&meta, &mut per_param)?;
1216 } else if let Some(check) = crate::miniextendr_fn::ClassCheck::of(&meta.path) {
1217 per_param_span.get_or_insert(meta.path.span());
1218 crate::miniextendr_fn::parse_method_class_check(&meta, &mut per_param, check)?;
1222 } else if meta.path.is_ident("formal") {
1223 return Err(meta.error(crate::miniextendr_fn::TRAIT_FORMAL_UNSUPPORTED));
1224 } else {
1225 return Err(meta.error(
1226 "unknown #[miniextendr] option on trait impl method; expected one of: \
1227 `env`, `r6`, `s7`, `s3`, `s4`, `worker`, `main_thread`, `coerce`, `no_coerce`, \
1228 `check_interrupt`, `rng`, `unwrap_in_r`, `serialize`, `skip`, `no_shortcut`, `r_name`, \
1229 `defaults`, `strict`, `no_strict`, `lifecycle`, `r_entry`, `r_post_checks`, `r_on_exit`, \
1230 `choices`, `choices_several_ok`, `no_default`, `inherits`, `not_inherits`, `no_na`, \
1231 `preconditions`, `no_preconditions`",
1232 ));
1233 }
1234 Ok(())
1235 })?;
1236 }
1237
1238 if serialize && unwrap_in_r {
1239 return Err(syn::Error::new(
1240 proc_macro2::Span::call_site(),
1241 "`serialize` cannot be combined with `unwrap_in_r`: it serializes the complete return value, including any Result variant",
1242 ));
1243 }
1244
1245 Ok(TraitMethodAttrs {
1246 worker: worker || falsecfg!(feature = "worker-default"),
1247 unsafe_main_thread,
1248 coerce: coerce.unwrap_or(falsecfg!(feature = "coerce-default")),
1249 check_interrupt,
1250 rng,
1251 unwrap_in_r,
1252 serialize,
1253 wrap,
1254 skip,
1255 strict: strict.unwrap_or(falsecfg!(feature = "strict-default")),
1256 defaults,
1257 r_name,
1258 lifecycle,
1259 r_entry,
1260 r_post_checks,
1261 r_on_exit,
1262 no_shortcut,
1263 generic,
1264 receiver,
1265 no_dispatch_dots,
1266 preconditions,
1267 per_param,
1268 per_param_span,
1269 defaults_span,
1270 })
1271}
1272
1273fn extract_consts(impl_item: &ItemImpl) -> Vec<TraitConst> {
1278 impl_item
1279 .items
1280 .iter()
1281 .filter_map(|item| {
1282 if let syn::ImplItem::Const(const_item) = item {
1283 Some(TraitConst {
1284 ident: const_item.ident.clone(),
1285 ty: const_item.ty.clone(),
1286 })
1287 } else {
1288 None
1289 }
1290 })
1291 .collect()
1292}
1293
1294pub(super) fn generate_trait_method_c_wrapper(
1308 method: &TraitMethod,
1309 type_ident: &syn::Ident,
1310 trait_name: &syn::Ident,
1311 trait_path: &syn::Path,
1312) -> TokenStream {
1313 use crate::c_wrapper_builder::{CWrapperContext, ReturnHandling, ThreadStrategy};
1314
1315 let method_ident = &method.ident;
1316 let c_ident = method.c_wrapper_ident(type_ident, trait_name);
1317 let call_method_def_ident = method.call_method_def_ident(type_ident, trait_name);
1318
1319 let thread_strategy = if method.has_self
1324 || method.unsafe_main_thread
1325 || method.check_interrupt
1326 || crate::type_inspect::signature_holds_r_values(&method.sig)
1327 {
1328 ThreadStrategy::MainThread
1329 } else if method.worker {
1330 ThreadStrategy::WorkerThread
1331 } else {
1332 ThreadStrategy::MainThread
1333 };
1334
1335 let rust_args: Vec<syn::Ident> = method
1337 .sig
1338 .inputs
1339 .iter()
1340 .filter_map(|arg| {
1341 if let syn::FnArg::Typed(pt) = arg {
1342 if let syn::Pat::Ident(pat_ident) = pt.pat.as_ref() {
1343 Some(pat_ident.ident.clone())
1344 } else {
1345 None
1346 }
1347 } else {
1348 None
1349 }
1350 })
1351 .collect();
1352
1353 let mut self_ref_params = Vec::new();
1357 let filtered_inputs: syn::punctuated::Punctuated<syn::FnArg, ::syn::token::Commasyn::Token![,]> = method
1358 .sig
1359 .inputs
1360 .iter()
1361 .filter(|arg| !#[allow(non_exhaustive_omitted_patterns)] match arg {
syn::FnArg::Receiver(_) => true,
_ => false,
}matches!(arg, syn::FnArg::Receiver(_)))
1362 .inspect(|arg| {
1363 if let syn::FnArg::Typed(pt) = arg
1364 && let Some(mutable) = crate::type_inspect::self_ref_mutability(&pt.ty)
1365 && let syn::Pat::Ident(pat_ident) = pt.pat.as_ref()
1366 {
1367 self_ref_params.push((pat_ident.ident.clone(), mutable));
1368 }
1369 })
1370 .cloned()
1371 .collect();
1372 let call_args = &rust_args;
1373
1374 let return_handling = if method.unwrap_in_r
1376 && crate::return_type_analysis::output_is_result(&method.sig.output)
1377 {
1378 ReturnHandling::IntoR
1379 } else {
1380 crate::c_wrapper_builder::detect_return_handling(
1381 &method.sig.output,
1382 method.return_wrap.as_ref(),
1383 )
1384 };
1385
1386 let r_wrappers_const = crate::naming::trait_impl_wrappers_ident(
1388 &crate::naming::ident_name(type_ident),
1389 trait_name,
1390 );
1391
1392 let mut builder = CWrapperContext::builder(method_ident.clone(), c_ident)
1396 .r_name(method.r_method_name())
1397 .r_wrapper_const(r_wrappers_const)
1398 .inputs(filtered_inputs)
1399 .output(method.sig.output.clone())
1400 .thread_strategy(thread_strategy)
1401 .return_handling(return_handling)
1402 .type_context(type_ident.clone())
1403 .call_method_def_ident(call_method_def_ident);
1404
1405 if method.inherited_signature {
1406 builder = builder.inferred_signature(crate::trait_signature::callable(
1407 &method.sig,
1408 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
_s
}quote::quote!(<#type_ident as #trait_path>::#method_ident),
1409 ));
1410 }
1411
1412 let mut post_conversion = Vec::new();
1413 let handles: Vec<_> = self_ref_params
1414 .iter()
1415 .map(|(name, mutable)| {
1416 (
1417 crate::externalptr_args::handle_ident(name),
1418 *mutable,
1419 crate::naming::ident_name(name),
1420 )
1421 })
1422 .collect();
1423 let receiver = method
1424 .has_self
1425 .then(|| ({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__miniextendr_receiver_addr");
_s
}quote::quote!(__miniextendr_receiver_addr), method.is_mut));
1426 post_conversion.push(crate::trait_self_ref::alias_checks(
1427 type_ident, &handles, receiver,
1428 ));
1429
1430 if method.has_self {
1431 let self_sexp = crate::naming::self_sexp_ident();
1432 let owner = syn::Ident::new("__mx_owner", proc_macro2::Span::mixed_site());
1433 let self_ptr = syn::Ident::new("self_ptr", proc_macro2::Span::mixed_site());
1434 let self_ref = syn::Ident::new("self_ref", proc_macro2::Span::mixed_site());
1435 let cell = syn::Ident::new("__mx_cell", proc_macro2::Span::mixed_site());
1436 let guard = syn::Ident::new("__mx_guard", proc_macro2::Span::mixed_site());
1437 let resolve = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&owner, &mut _s);
::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, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ReceiverOwner");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "resolve");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_sexp, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1438 let #owner =
1439 ::miniextendr_api::externalptr::ReceiverOwner::resolve::<#type_ident>(#self_sexp);
1440 };
1441 let self_extraction = if let Some(kind) = crate::trait_receiver::owner_receiver(&method.sig)
1442 {
1443 let receiver_mutability = method.is_mut.then(|| {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "mut");
_s
}quote::quote!(mut));
1444 let borrow = match kind {
1445 crate::trait_receiver::OwnerReceiver::Shared => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "borrow");
_s
}quote::quote!(borrow),
1446 crate::trait_receiver::OwnerReceiver::Mutable => {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "borrow_mut");
_s
}quote::quote!(borrow_mut),
1447 };
1448 let address = (!self_ref_params.is_empty()).then(|| {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__miniextendr_receiver_addr");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_ptr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::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, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ffi");
::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());
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1449 let __miniextendr_receiver_addr = #self_ptr.as_ptr().cast::<::core::ffi::c_void>();
1450 });
1451 post_conversion.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&borrow, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1455 let #self_ref = #self_ptr.#borrow();
1456 });
1457 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&resolve, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&receiver_mutability, &mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_eq(&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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "wrap_receiver");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&address, &mut _s);
_s
}quote::quote! {
1458 #resolve
1459 let #receiver_mutability #self_ptr = unsafe {
1460 ::miniextendr_api::externalptr::wrap_receiver::<#type_ident>(#owner.get())
1461 };
1462 #address
1463 }
1464 } else {
1465 let trait_method_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}()", trait_name,
method.r_method_name()))
})format!("{}::{}()", trait_name, method.r_method_name());
1466 post_conversion.push(crate::trait_self_ref::receiver_borrow(
1470 &cell,
1471 &guard,
1472 &self_ref,
1473 method.is_mut,
1474 ));
1475 let self_setup = (!self_ref_params.is_empty()).then(|| {
1476 let address = crate::trait_self_ref::cell_address(&cell);
1477 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__miniextendr_receiver_addr");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&address, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1478 let __miniextendr_receiver_addr = #address;
1479 }
1480 });
1481 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&resolve, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_eq(&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, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedExternalPtr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "downcast_cell");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::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, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "cell");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "cell");
::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, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_fat_arrow(&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, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"handle_downcast_failed_in");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::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(&self_ptr, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&trait_method_name, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&self_setup, &mut _s);
_s
}quote::quote! {
1482 #resolve
1483 let #self_ptr = unsafe {
1484 ::miniextendr_api::externalptr::ErasedExternalPtr::from_sexp(#owner.get())
1485 };
1486 let #cell = match #self_ptr.downcast_cell::<#type_ident>() {
1487 ::core::option::Option::Some(cell) => cell,
1488 ::core::option::Option::None => ::miniextendr_api::externalptr::handle_downcast_failed_in::<#type_ident>(
1489 &#self_ptr, #trait_method_name,
1490 ),
1491 };
1492 #self_setup
1493 }
1494 };
1495
1496 let call_expr = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut call_args, i) = call_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let call_args =
match call_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&call_args, &mut _s);
}
}
_s
});
_s
}quote::quote! {
1500 <#type_ident as #trait_path>::#method_ident(#self_ref, #(#call_args),*)
1501 };
1502 let call_expr = crate::type_inspect::prepare_return_value(
1504 call_expr,
1505 method.invisible,
1506 method.serialize,
1507 );
1508 let call_expr = match &method.return_wrap {
1509 Some(wrap) => wrap.prepare_value(call_expr),
1510 None => call_expr,
1511 };
1512
1513 builder = builder
1514 .pre_call(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self_extraction]))vec![self_extraction])
1515 .call_expr(call_expr)
1516 .has_self();
1517 } else {
1518 let call_expr = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut call_args, i) = call_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let call_args =
match call_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&call_args, &mut _s);
}
}
_s
});
_s
}quote::quote! {
1520 <#type_ident as #trait_path>::#method_ident(#(#call_args),*)
1521 };
1522 let call_expr = crate::type_inspect::prepare_return_value(
1523 call_expr,
1524 method.invisible,
1525 method.serialize,
1526 );
1527 let call_expr = match &method.return_wrap {
1528 Some(wrap) => wrap.prepare_value(call_expr),
1529 None => call_expr,
1530 };
1531
1532 builder = builder.call_expr(call_expr);
1533 }
1534
1535 if method.coerce {
1537 builder = builder.coerce_all();
1538 }
1539
1540 if method.check_interrupt {
1542 builder = builder.check_interrupt();
1543 }
1544
1545 if method.rng {
1547 builder = builder.rng();
1548 }
1549
1550 if method.strict {
1552 builder = builder.strict();
1553 }
1554
1555 for (rust_name, attrs) in &method.per_param {
1561 if let Some(leaf) = attrs.layered_leaf() {
1562 builder = builder.layered_choice(rust_name.clone(), leaf);
1563 }
1564 if attrs.checks.no_na {
1565 builder = builder.no_na(rust_name.clone(), attrs.checks.no_na_message.clone());
1566 }
1567 }
1568
1569 builder.post_conversion(post_conversion).build().generate()
1571}
1572
1573pub(super) fn generate_trait_const_c_wrapper(
1579 trait_const: &TraitConst,
1580 type_ident: &syn::Ident,
1581 trait_name: &syn::Ident,
1582 trait_path: &syn::Path,
1583) -> TokenStream {
1584 use crate::c_wrapper_builder::{CWrapperContext, ThreadStrategy};
1585
1586 let const_ident = &trait_const.ident;
1587 let c_ident = trait_const.c_wrapper_ident(type_ident, trait_name);
1588 let call_method_def_ident = trait_const.call_method_def_ident(type_ident, trait_name);
1589 let const_ty = &trait_const.ty;
1590
1591 let r_wrappers_const = crate::naming::trait_impl_wrappers_ident(
1593 &crate::naming::ident_name(type_ident),
1594 trait_name,
1595 );
1596
1597 let call_expr = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&const_ident, &mut _s);
_s
}quote::quote! {
1599 <#type_ident as #trait_path>::#const_ident
1600 };
1601
1602 let return_type: syn::ReturnType = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_rarrow(&mut _s);
::quote::ToTokens::to_tokens(&const_ty, &mut _s);
_s
})syn::parse_quote!(-> #const_ty);
1605 let return_handling = crate::c_wrapper_builder::detect_return_handling(&return_type, None);
1606
1607 let builder = CWrapperContext::builder(const_ident.clone(), c_ident)
1609 .r_wrapper_const(r_wrappers_const)
1610 .inputs(Default::default()) .output(return_type)
1612 .call_expr(call_expr)
1613 .thread_strategy(ThreadStrategy::MainThread)
1614 .return_handling(return_handling)
1615 .type_context(type_ident.clone())
1616 .call_method_def_ident(call_method_def_ident);
1617
1618 builder.build().generate()
1619}