Skip to main content

miniextendr_macros/
miniextendr_trait.rs

1//! # Trait Support for `#[miniextendr]`
2//!
3//! This module handles `#[miniextendr]` applied to trait definitions,
4//! generating the ABI infrastructure for cross-package trait dispatch.
5//!
6//! ## Overview
7//!
8//! When `#[miniextendr]` is applied to a trait, it generates:
9//!
10//! 1. **Type tag constant** (`TAG_<TraitName>`) - 128-bit identifier for runtime type checking
11//! 2. **Vtable struct** (`<TraitName>VTable`) - Function pointer table for method dispatch
12//! 3. **View struct** (`<TraitName>View`) - Runtime wrapper combining data pointer and vtable
13//! 4. **Method shims** - `extern "C"` functions that convert SEXP arguments and call methods
14//! 5. **Vtable builder** - `__<trait>_build_vtable::<T>()` for impl blocks
15//!
16//! ## Usage
17//!
18//! ```ignore
19//! #[miniextendr]
20//! pub trait Counter {
21//!     fn value(&self) -> i32;
22//!     fn increment(&mut self);
23//!     fn add(&mut self, n: i32);
24//! }
25//! ```
26//!
27//! Generates (conceptually):
28//!
29//! ```text
30//! // Original trait (passed through)
31//! pub trait Counter {
32//!     fn value(&self) -> i32;
33//!     fn increment(&mut self);
34//!     fn add(&mut self, n: i32);
35//! }
36//!
37//! // Type tag for runtime identification
38//! pub const TAG_Counter: mx_tag = mx_tag::new(0x..., 0x...);
39//!
40//! // Vtable with one entry per method
41//! #[repr(C)]
42//! pub struct CounterVTable {
43//!     pub value: mx_meth,
44//!     pub increment: mx_meth,
45//!     pub add: mx_meth,
46//! }
47//!
48//! // View over the data and vtable pointers; roots its R receiver
49//! pub struct CounterView {
50//!     __mx_view: miniextendr_api::trait_abi::TraitViewData<CounterVTable>,
51//! }
52//!
53//! // Shim for each method
54//! unsafe extern "C" fn __Counter_value_shim<T: Counter>(
55//!     data: *mut c_void, argc: i32, argv: *const SEXP
56//! ) -> SEXP {
57//!     // 1. Check arity
58//!     // 2. Cast data to &T
59//!     // 3. Call method
60//!     // 4. Convert result to SEXP
61//!     // 5. Catch panics
62//! }
63//!
64//! // Builder to create vtable for a concrete type
65//! pub const fn __Counter_build_vtable<T: Counter>() -> CounterVTable {
66//!     CounterVTable {
67//!         value: __Counter_value_shim::<T>,
68//!         increment: __Counter_increment_shim::<T>,
69//!         add: __Counter_add_shim::<T>,
70//!     }
71//! }
72//! ```
73//!
74//! ## Supported Method Signatures
75//!
76//! Methods must follow these constraints:
77//!
78//! - **Receiver**: `&self`, `&mut self`, `self: ExternalPtrRef<'_, Self>` or
79//!   `self: ExternalPtrMut<'_, Self>` for instance methods, or none for static methods.
80//!   Borrowed-owner receivers require `Self: TypedExternal`; their emitted Rust
81//!   signatures are associated functions accepting the handle by value.
82//! - **Arguments**: Types that implement `TryFromSexp`
83//! - **Return**: Types that implement `IntoR`, or `()`
84//! - **No generics**: Methods cannot have generic type parameters
85//! - **No async**: Async methods are not supported
86//! - **Static methods**: Methods without a receiver are allowed and resolved at compile time
87//!   (they don't go through the vtable)
88//!
89//! ## Default Methods
90//!
91//! Default method implementations are supported. The vtable builder will
92//! use the default implementation if the concrete type doesn't override it.
93//!
94//! ```ignore
95//! #[miniextendr]
96//! pub trait Counter {
97//!     fn value(&self) -> i32;
98//!
99//!     // Default implementation - included in vtable
100//!     fn is_zero(&self) -> bool {
101//!         self.value() == 0
102//!     }
103//! }
104//! ```
105//!
106//! ## Error Handling
107//!
108//! A method shim runs inside `with_r_unwind_protect_shim`, which turns a Rust
109//! panic into a tagged condition SEXP; the View re-panics with it in the
110//! caller's guard. These panic:
111//!
112//! - **Arity mismatch**: "expected N arguments, got M"
113//! - **Aliased native borrows**: two arguments (or two elements of one) that
114//!   borrow the same R vector, at least one mutably, checked before any
115//!   argument is converted
116//! - **Type conversion failure**: the converter's error message
117//! - **The method itself**
118//!
119//! ## GC Protection
120//!
121//! A View method converts each argument to a fresh SEXP, and the next
122//! conversion allocates, so it protects every converted argument in a
123//! `ProtectScope` as soon as it exists and keeps it protected across the
124//! vtable call. The returned SEXP is protected across the tagged-error check
125//! and its conversion back to Rust.
126//!
127//! ## Thread Safety
128//!
129//! All generated shims are **main-thread only**. They do not route through
130//! `with_r_thread` because R invokes `.Call` on the main thread.
131
132use proc_macro2::TokenStream;
133use syn::ItemTrait;
134
135/// Expand `#[miniextendr]` applied to a trait definition.
136///
137/// # Arguments
138///
139/// * `attr` - Attribute arguments (currently unused, reserved for future options)
140/// * `item` - The trait definition token stream
141///
142/// # Returns
143///
144/// Expanded token stream containing:
145/// - Original trait definition
146/// - Type tag constant
147/// - Vtable struct
148/// - View struct
149/// - Method shims
150/// - Vtable builder function
151///
152/// # Errors
153///
154/// Returns a compile error if:
155/// - Methods have unsupported signatures
156/// - Methods are async
157pub fn expand_trait(
158    _attr: proc_macro::TokenStream,
159    item: proc_macro::TokenStream,
160) -> proc_macro::TokenStream {
161    let trait_item = match ::syn::parse::<ItemTrait>(item) {
    ::syn::__private::Ok(data) => data,
    ::syn::__private::Err(err) => {
        return ::syn::__private::TokenStream::from(err.to_compile_error());
    }
}syn::parse_macro_input!(item as ItemTrait);
162
163    // Validate trait constraints
164    if let Err(e) = validate_trait(&trait_item) {
165        return e.into_compile_error().into();
166    }
167
168    // Generate the expanded code
169    let expanded = generate_trait_abi(&trait_item);
170
171    expanded.into()
172}
173
174/// Validate that the trait meets requirements for ABI generation.
175///
176/// # Constraints
177///
178/// - Instance methods use shared/mutable references or explicit borrowed-owner receivers
179/// - Methods cannot be async
180/// - Methods cannot have generic parameters
181/// - Generic type parameters on the trait itself are allowed
182fn validate_trait(trait_item: &ItemTrait) -> syn::Result<()> {
183    let trait_name = &trait_item.ident;
184
185    // Validate each method
186    for item in &trait_item.items {
187        if let syn::TraitItem::Fn(method) = item {
188            validate_method(method, trait_name)?;
189        }
190    }
191
192    Ok(())
193}
194
195/// Validate a single trait method for ABI compatibility.
196///
197/// Rejects async methods, methods with generic type parameters, and methods
198/// that take `self` by value (only `&self` and `&mut self` are allowed).
199/// Static methods (no receiver) are permitted.
200fn validate_method(method: &syn::TraitItemFn, trait_name: &syn::Ident) -> syn::Result<()> {
201    let method_name = &method.sig.ident;
202
203    // Check for async
204    if method.sig.asyncness.is_some() {
205        return Err(syn::Error::new_spanned(
206            method.sig.asyncness,
207            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#[miniextendr] trait `{0}::{1}` cannot be async",
                trait_name, method_name))
    })format!(
208                "#[miniextendr] trait `{}::{}` cannot be async",
209                trait_name, method_name
210            ),
211        ));
212    }
213
214    // Check for type/const generics on method.
215    // Lifetime params are allowed (erased at codegen); type/const params would require
216    // monomorphization and are incompatible with the vtable-shim codegen path.
217    {
218        let has_type_or_const = method
219            .sig
220            .generics
221            .params
222            .iter()
223            .any(|p| #[allow(non_exhaustive_omitted_patterns)] match p {
    syn::GenericParam::Type(_) | syn::GenericParam::Const(_) => true,
    _ => false,
}matches!(p, syn::GenericParam::Type(_) | syn::GenericParam::Const(_)));
224        if has_type_or_const {
225            return Err(syn::Error::new_spanned(
226                &method.sig.generics,
227                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#[miniextendr] trait method `{0}::{1}` cannot have generic type or const parameters",
                trait_name, method_name))
    })format!(
228                    "#[miniextendr] trait method `{}::{}` cannot have generic type or const parameters",
229                    trait_name, method_name
230                ),
231            ));
232        }
233    }
234
235    // Instance receivers borrow Self directly or carry an explicit borrowed owner.
236    // Static methods are allowed but won't be included in the vtable
237    // (they're resolved at compile time via <Type as Trait>::method())
238    let receiver = method.sig.inputs.first();
239    if let Some(syn::FnArg::Receiver(r)) = receiver {
240        // Accept either:
241        // - `&self` / `&mut self` (r.reference is Some)
242        // - `self: &Self` / `self: &mut Self` (r.colon_token is Some with reference type)
243        let is_ref = if r.reference.is_some() {
244            true
245        } else if r.colon_token.is_some() {
246            // Check if the type is a reference type (&Self or &mut Self)
247            #[allow(non_exhaustive_omitted_patterns)] match r.ty.as_ref() {
    syn::Type::Reference(_) => true,
    _ => false,
}matches!(r.ty.as_ref(), syn::Type::Reference(_))
248        } else {
249            false
250        };
251
252        if !is_ref && crate::trait_receiver::owner_receiver(&method.sig).is_none() {
253            return Err(syn::Error::new_spanned(
254                r,
255                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#[miniextendr] trait method `{0}::{1}` receiver must be `&self` or `&mut self`, not `self` by value",
                trait_name, method_name))
    })format!(
256                    "#[miniextendr] trait method `{}::{}` receiver must be `&self` or `&mut self`, not `self` by value",
257                    trait_name, method_name
258                ),
259            ));
260        }
261    }
262    // If receiver is None or FnArg::Typed (no self), it's a static method - allowed
263
264    // The unforced dots (#1892) cannot cross the vtable, nor can the RNG
265    // guard (#2002).
266    crate::miniextendr_fn::refuse_lazy_dots_in_trait_method(&method.sig.inputs)?;
267    crate::miniextendr_fn::refuse_rng_guard_in_trait_method(&method.sig.inputs)?;
268
269    Ok(())
270}
271
272/// Generate the ABI infrastructure for a trait.
273///
274/// This is the main code generation function that produces:
275/// - Type tag constant
276/// - Vtable struct
277/// - View struct (skipped for generic traits)
278/// - Method shims (with trait type params threaded through)
279/// - Vtable builder (with trait type params threaded through)
280fn generate_trait_abi(trait_item: &ItemTrait) -> TokenStream {
281    let trait_name = &trait_item.ident;
282    let vis = &trait_item.vis;
283
284    // Generate names for generated items
285    let tag_name = crate::naming::trait_tag_ident(trait_name);
286    let vtable_name = match ::quote::__private::IdentFragmentAdapter(&trait_name) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}VTable", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("{}VTable", trait_name);
287    let view_name = match ::quote::__private::IdentFragmentAdapter(&trait_name) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}View", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("{}View", trait_name);
288    let build_vtable_fn = crate::naming::trait_vtable_builder_ident(trait_name);
289
290    // Collect trait-level generic type parameters
291    let trait_type_params: Vec<&syn::GenericParam> = trait_item.generics.params.iter().collect();
292    let trait_param_idents: Vec<&syn::Ident> = trait_type_params
293        .iter()
294        .filter_map(|p| {
295            if let syn::GenericParam::Type(tp) = p {
296                Some(&tp.ident)
297            } else {
298                None
299            }
300        })
301        .collect();
302    let has_generics = !trait_item.generics.params.is_empty();
303
304    // Collect associated types
305    let assoc_types: Vec<&syn::Ident> = trait_item
306        .items
307        .iter()
308        .filter_map(|item| {
309            if let syn::TraitItem::Type(t) = item {
310                Some(&t.ident)
311            } else {
312                None
313            }
314        })
315        .collect();
316
317    // Collect trait where clause
318    let trait_where_clause = &trait_item.generics.where_clause;
319
320    // Collect method information
321    // Filter to only include instance methods (with &self or &mut self) that aren't skipped
322    let methods: Vec<_> = {
323        let mut collected = Vec::new();
324        for item in &trait_item.items {
325            if let syn::TraitItem::Fn(method) = item {
326                let info = match extract_method_info(method) {
327                    Ok(info) => info,
328                    Err(e) => return e.into_compile_error(),
329                };
330                if info.has_self && !info.skip {
331                    collected.push(info);
332                }
333            }
334        }
335        collected
336    }
337    .into_iter()
338    .collect();
339
340    // Query must reject incompatible declarations before a View reads a slot.
341    // Package/module paths must not enter the tag: independently compiled
342    // declarations of the same interface need to agree across DLLs.
343    let tag_path = trait_abi_tag_path(trait_name, &methods);
344
345    // Generate vtable fields
346    let vtable_fields: Vec<_> = methods
347        .iter()
348        .map(|m| {
349            let name = &m.name;
350            let abi = if m.owner_receiver.is_some() {
351                {
    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, "abi");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "mx_owner_meth");
    _s
}quote::quote!(::miniextendr_api::abi::mx_owner_meth)
352            } else {
353                {
    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, "abi");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "mx_meth");
    _s
}quote::quote!(::miniextendr_api::abi::mx_meth)
354            };
355            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "pub");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::ToTokens::to_tokens(&abi, &mut _s);
    _s
}quote::quote! { pub #name: #abi }
356        })
357        .collect();
358
359    // Compute extra bounds needed for shims
360    let extra_bounds =
361        compute_extra_bounds(&methods, trait_name, &assoc_types, &trait_param_idents);
362
363    // Build trait bound for __ImplT
364    let impl_t = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__ImplT"))
            }), ::quote::__private::Option::None)quote::format_ident!("__ImplT");
365    let trait_bound = if trait_param_idents.is_empty() {
366        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    _s
}quote::quote! { #trait_name }
367    } else {
368        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut trait_param_idents, i) =
            trait_param_idents.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let trait_param_idents =
                match trait_param_idents.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&trait_param_idents, &mut _s);
        }
    }
    ::quote::__private::push_gt(&mut _s);
    _s
}quote::quote! { #trait_name<#(#trait_param_idents),*> }
369    };
370
371    // Build combined where clause
372    let all_where_predicates = build_where_predicates(trait_where_clause, &extra_bounds);
373    let where_clause = if all_where_predicates.is_empty() {
374        ::quote::__private::TokenStream::new();quote::quote! {}
375    } else {
376        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut all_where_predicates, i) =
            all_where_predicates.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let all_where_predicates =
                match all_where_predicates.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&all_where_predicates, &mut _s);
        }
    }
    _s
}quote::quote! { where #(#all_where_predicates),* }
377    };
378
379    // Declaration-side builders select the same associated callbacks as impls.
380    let vtable_inits: Vec<_> = methods
381        .iter()
382        .map(|m| {
383            let name = &m.name;
384            let shim_name = crate::naming::trait_method_shim_ident(trait_name, name);
385            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::ToTokens::to_tokens(&trait_bound, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&shim_name, &mut _s);
    _s
}quote::quote! {
386                #name: <#impl_t as #trait_bound>::#shim_name
387            }
388        })
389        .collect();
390
391    // Generate method wrappers for the View struct
392    // Skip entirely for generic traits (type-erased view can't know type params)
393    let view_methods: Vec<_> = if has_generics {
394        ::alloc::vec::Vec::new()vec![]
395    } else {
396        methods.iter().filter_map(generate_view_method).collect()
397    };
398
399    // Strip #[miniextendr(...)] attrs from trait items before emitting
400    let mut clean_trait = trait_item.clone();
401    for item in &mut clean_trait.items {
402        if let syn::TraitItem::Fn(method) = item {
403            method
404                .attrs
405                .retain(|attr| !attr.path().is_ident("miniextendr"));
406            crate::trait_receiver::rewrite(&mut method.sig, method.default.as_mut());
407        }
408    }
409
410    // Non-generic shims are hidden trait methods, so an impl reaches them
411    // through any path to the trait. A generic trait's impls generate their
412    // own concrete shims from their signatures.
413    if !has_generics {
414        clean_trait.items.extend(methods.iter().map(|m| {
415            syn::TraitItem::Fn(associated_method_shim(generate_method_shim(
416                trait_name,
417                m,
418                &extra_bounds,
419                &trait_param_idents,
420                &trait_type_params,
421                trait_where_clause,
422            )))
423        }));
424    }
425
426    let trait_name_str = trait_name.to_string();
427    let source_loc_doc = crate::source_location_doc(trait_name.span());
428
429    let impl_bounds = &extra_bounds.impl_bounds;
430
431    // View struct and its impls (skipped for generic traits)
432    let view_tokens = if has_generics {
433        ::quote::__private::TokenStream::new();quote::quote! {}
434    } else {
435        {
    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_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,
                        "\"Runtime view for objects 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_eq(&mut _s);
            ::quote::__private::parse(&mut _s, "r\"\"");
            _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,
                "r\" Keeps the receiver alive for method dispatch. Use `try_from_sexp`\"");
            _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,
                "r\" to create a view with its own root for the R external pointer.\"");
            _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,
                "r\" Construction, use and drop belong on R\'s main thread.\"");
            _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::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "struct");
    ::quote::ToTokens::to_tokens(&view_name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "__mx_view");
            ::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, "trait_abi");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "TraitViewData");
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&vtable_name, &mut _s);
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::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, "TraitView");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&view_name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "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");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&tag_name, &mut _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, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::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_ident(&mut _s, "data");
                    ::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::__private::push_ident(&mut _s, "vtable");
                    ::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, "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::__private::push_ident(&mut _s, "owner");
                    ::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, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_lt(&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_gt(&mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "Self");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "__mx_view");
                            ::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, "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, "TraitViewData");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "new");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "data");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "vtable");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "owner");
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_comma(&mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&view_name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            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_eq(&mut _s);
                    ::quote::__private::parse(&mut _s,
                        "r\" Try to create a view from an R SEXP.\"");
                    _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, "r\"\"");
                    _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,
                        "r\" Returns `Some(Self)` if the object implements this trait,\"");
                    _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,
                        "r\" `None` otherwise.\"");
                    _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, "r\"\"");
                    _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, "r\" # Safety\"");
                    _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, "r\"\"");
                    _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,
                        "r\" - `sexp` must be a valid R external pointer (EXTPTRSXP)\"");
                    _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,
                        "r\" - The object must stay live through construction; the view then roots it\"");
                    _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,
                        "r\" - A call that conflicts with one still running on the same object\"");
                    _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,
                        "r\"   raises the `miniextendr_borrow_conflict` error\"");
                    _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,
                        "r\" - Construction, use and drop must all run on R\'s main thread\"");
                    _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, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "pub");
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "try_from_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    ::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");
                    _s
                });
            ::quote::__private::push_rarrow(&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_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    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_lt(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "Self");
                            ::quote::__private::push_ident(&mut _s, "as");
                            ::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, "TraitView");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "try_from_sexp");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "sexp");
                                    _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,
                        "r\" Try to create a view, panicking with error message on failure.\"");
                    _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, "r\"\"");
                    _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, "r\" # Safety\"");
                    _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, "r\"\"");
                    _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,
                        "r\" Same as `try_from_sexp`.\"");
                    _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, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "pub");
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::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::__private::push_ident(&mut _s, "sexp");
                    ::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");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    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_ident(&mut _s, "Self");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "try_from_sexp");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "sexp");
                                    _s
                                });
                            _s
                        });
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "expect");
                    ::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::parse(&mut _s,
                                        "\"Object does not implement \"");
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::ToTokens::to_tokens(&trait_name_str, &mut _s);
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::__private::parse(&mut _s, "\" trait\"");
                                    _s
                                });
                            _s
                        });
                    _s
                });
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut view_methods, i) = view_methods.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let view_methods =
                        match view_methods.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&view_methods, &mut _s);
                }
            }
            _s
        });
    _s
}quote::quote! {
436            #[doc = ::core::concat!(
437                "Runtime view for objects implementing `",
438                ::core::stringify!(#trait_name),
439                "`."
440            )]
441            #[doc = #source_loc_doc]
442            #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
443            ///
444            /// Keeps the receiver alive for method dispatch. Use `try_from_sexp`
445            /// to create a view with its own root for the R external pointer.
446            /// Construction, use and drop belong on R's main thread.
447            #[allow(non_camel_case_types)]
448            #vis struct #view_name {
449                __mx_view: ::miniextendr_api::trait_abi::TraitViewData<#vtable_name>,
450            }
451
452            // TraitView implementation
453            impl ::miniextendr_api::TraitView for #view_name {
454                const TAG: ::miniextendr_api::abi::mx_tag = #tag_name;
455
456                #[inline]
457                unsafe fn from_raw_parts(
458                    data: *mut ::std::os::raw::c_void,
459                    vtable: *const ::std::os::raw::c_void,
460                    owner: ::core::option::Option<::miniextendr_api::SEXP>,
461                ) -> Self {
462                    Self {
463                        __mx_view: unsafe {
464                            ::miniextendr_api::trait_abi::TraitViewData::new(data, vtable, owner)
465                        },
466                    }
467                }
468            }
469
470            // Method wrappers on View
471            impl #view_name {
472                /// Try to create a view from an R SEXP.
473                ///
474                /// Returns `Some(Self)` if the object implements this trait,
475                /// `None` otherwise.
476                ///
477                /// # Safety
478                ///
479                /// - `sexp` must be a valid R external pointer (EXTPTRSXP)
480                /// - The object must stay live through construction; the view then roots it
481                /// - A call that conflicts with one still running on the same object
482                ///   raises the `miniextendr_borrow_conflict` error
483                /// - Construction, use and drop must all run on R's main thread
484                #[inline]
485                pub unsafe fn try_from_sexp(sexp: ::miniextendr_api::SEXP) -> ::core::option::Option<Self> {
486                    unsafe { <Self as ::miniextendr_api::TraitView>::try_from_sexp(sexp) }
487                }
488
489                /// Try to create a view, panicking with error message on failure.
490                ///
491                /// # Safety
492                ///
493                /// Same as `try_from_sexp`.
494                #[inline]
495                pub unsafe fn from_sexp(sexp: ::miniextendr_api::SEXP) -> Self {
496                    unsafe { Self::try_from_sexp(sexp) }
497                        .expect(::core::concat!("Object does not implement ", #trait_name_str, " trait"))
498                }
499
500                #(#view_methods)*
501            }
502        }
503    };
504
505    // For generic traits (with type params like <T>), skip shim and builder generation.
506    // These are generated at the impl site with concrete types to avoid recursive trait
507    // resolution overflow (e.g., `Vec<T>: TryFromSexp` triggers infinite recursion through
508    // `impl<T> TryFromSexp for Vec<Vec<T>>`).
509    let shim_and_builder = if has_generics {
510        ::quote::__private::TokenStream::new();quote::quote! {}
511    } else {
512        {
    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_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,
                        "\"Build a vtable for a concrete type 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, "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::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "const");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&build_vtable_fn, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut trait_type_params, i) = trait_type_params.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let trait_type_params =
                match trait_type_params.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&trait_type_params, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::ToTokens::to_tokens(&trait_bound, &mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut impl_bounds, i) = impl_bounds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let impl_bounds =
                match impl_bounds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::__private::push_add(&mut _s);
            ::quote::ToTokens::to_tokens(&impl_bounds, &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_rarrow(&mut _s);
    ::quote::ToTokens::to_tokens(&vtable_name, &mut _s);
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&vtable_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 vtable_inits, i) = vtable_inits.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let vtable_inits =
                                match vtable_inits.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            if !_first { ::quote::__private::push_comma(&mut _s); }
                            _first = false;
                            ::quote::ToTokens::to_tokens(&vtable_inits, &mut _s);
                        }
                    }
                    _s
                });
            _s
        });
    _s
}quote::quote! {
513            #[doc = ::core::concat!(
514                "Build a vtable for a concrete type implementing `",
515                ::core::stringify!(#trait_name),
516                "`."
517            )]
518            #[doc = #source_loc_doc]
519            #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
520            #[allow(non_snake_case)]
521            #vis const fn #build_vtable_fn<#(#trait_type_params,)* #impl_t: #trait_bound #(+ #impl_bounds)*>() -> #vtable_name
522            #where_clause
523            {
524                #vtable_name {
525                    #(#vtable_inits),*
526                }
527            }
528        }
529    };
530
531    // All impls receive the declaration's R metadata, including generic traits
532    // and traits with associated types. Signatures for empty impls still use
533    // the established non-generic TPIE path.
534    let mut method_metadata = Vec::new();
535    let mut tpie_method_metadata = Vec::new();
536    for item in &trait_item.items {
537        if let syn::TraitItem::Fn(method) = item {
538            let info = match extract_method_info(method) {
539                Ok(info) => info,
540                Err(e) => return e.into_compile_error(),
541            };
542            let name = &method.sig.ident;
543            let r_name_attr = info
544                .r_name
545                .as_ref()
546                .map(|name| {
    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(&name, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote::quote!(#[miniextendr(r_name = #name)]));
547            let skip_attr = info.skip.then(|| {
    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
}quote::quote!(#[miniextendr(skip)]));
548            // Copied signatures name every parameter as the declaration's
549            // metadata does (`arg<i>` for a pattern), since the generated
550            // wrappers pass each argument by name.
551            let mut sig = method.sig.clone();
552            for (arg, name) in sig
553                .inputs
554                .iter_mut()
555                .filter_map(|arg| match arg {
556                    syn::FnArg::Typed(arg) => Some(arg),
557                    syn::FnArg::Receiver(_) => None,
558                })
559                .zip(&info.param_names)
560            {
561                *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);
562            }
563            // Keep default signatures, but never copy their bodies into an
564            // implementation. Generated wrappers call the trait's own default,
565            // so an impl that omits a default still gets its R wrapper, generic
566            // trait or not. Required methods carry names only, preserving
567            // impl-local types.
568            if method.default.is_some() {
569                let docs = method
570                    .attrs
571                    .iter()
572                    .filter(|attr| attr.path().is_ident("doc"));
573                method_metadata.push({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut docs, i) = docs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let docs =
                match docs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&docs, &mut _s);
        }
    }
    ::quote::ToTokens::to_tokens(&r_name_attr, &mut _s);
    ::quote::ToTokens::to_tokens(&skip_attr, &mut _s);
    ::quote::ToTokens::to_tokens(&sig, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    _s
}quote::quote! {
574                    #(#docs)* #r_name_attr #skip_attr #sig {}
575                });
576            } else {
577                let params = &info.param_names;
578                method_metadata.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&r_name_attr, &mut _s);
    ::quote::ToTokens::to_tokens(&skip_attr, &mut _s);
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&name, &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 params, i) = params.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let params =
                        match params.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&params, &mut _s);
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                }
            }
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
579                    #r_name_attr #skip_attr fn #name(#(#params: ()),*);
580                });
581            }
582            if !has_generics && assoc_types.is_empty() && !info.skip {
583                let r_name = info
584                    .r_name
585                    .as_deref()
586                    .map(crate::naming::name_ident)
587                    .unwrap_or_else(|| name.clone());
588                tpie_method_metadata.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "method");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            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);
            ::quote::__private::push_semi(&mut _s);
            ::quote::ToTokens::to_tokens(&sig, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            _s
        });
    _s
}quote::quote! {
589                    method { r_name = #r_name; #sig; }
590                });
591            }
592        }
593    }
594    // The impl receives the exact declaration layout and fingerprint, never
595    // a guessed path to companion items. No caller-scope types occur here.
596    let abi_metadata = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "abi");
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    ::quote::ToTokens::to_tokens(&has_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&tag_path, &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 vtable_fields, i) = vtable_fields.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let vtable_fields =
                        match vtable_fields.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&vtable_fields, &mut _s);
                }
            }
            _s
        });
    _s
}quote::quote! {
597        abi #trait_name #has_generics #tag_path { #(#vtable_fields),* }
598    };
599    let empty_impl_arm = if !has_generics && assoc_types.is_empty() {
600        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "concrete_type");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ty");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "trait_path");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "path");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "class_system");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ident");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "no_rd");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "tt");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "internal");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "tt");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "noexport");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "tt");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "$");
            ::quote::__private::push_ident(&mut _s, "no_preconditions");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "tt");
            _s
        });
    ::quote::__private::push_fat_arrow(&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, "__mx_trait_impl_expand");
            ::quote::__private::push_bang(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "concrete_type");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "concrete_type");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "trait_path");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "trait_path");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "class_system");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "class_system");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "no_rd");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "no_rd");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "internal");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "internal");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "noexport");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "noexport");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "no_preconditions");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "$");
                    ::quote::__private::push_ident(&mut _s, "no_preconditions");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::ToTokens::to_tokens(&abi_metadata, &mut _s);
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut tpie_method_metadata, i) =
                            tpie_method_metadata.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let tpie_method_metadata =
                                match tpie_method_metadata.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&tpie_method_metadata,
                                &mut _s);
                        }
                    }
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
601            ($concrete_type:ty, $trait_path:path, $class_system:ident, $no_rd:tt, $internal:tt, $noexport:tt, $no_preconditions:tt) => {
602                ::miniextendr_api::__mx_trait_impl_expand! {
603                    concrete_type = $concrete_type;
604                    trait_path = $trait_path;
605                    class_system = $class_system;
606                    no_rd = $no_rd;
607                    internal = $internal;
608                    noexport = $noexport;
609                    no_preconditions = $no_preconditions;
610                    #abi_metadata
611                    #(#tpie_method_metadata)*
612                }
613            };
614        }
615    } else {
616        ::quote::__private::TokenStream::new();quote::quote! {}
617    };
618    let declaration_generics = &trait_item.generics;
619    let metadata_macro_name = crate::naming::trait_metadata_macro_ident(trait_name);
620    let metadata_macro = {
    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, "macro_export");
            _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_ident(&mut _s, "macro_rules");
    ::quote::__private::push_bang(&mut _s);
    ::quote::ToTokens::to_tokens(&metadata_macro_name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_at(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "impl");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::parse(&mut _s, "$");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s, "$");
                                    ::quote::__private::push_ident(&mut _s, "attrs");
                                    ::quote::__private::push_colon(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "tt");
                                    _s
                                });
                            ::quote::__private::push_star(&mut _s);
                            _s
                        });
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::parse(&mut _s, "$");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s, "$");
                                    ::quote::__private::push_ident(&mut _s, "implementation");
                                    ::quote::__private::push_colon(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "tt");
                                    _s
                                });
                            ::quote::__private::push_star(&mut _s);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_fat_arrow(&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,
                        "__mx_trait_impl_expand");
                    ::quote::__private::push_bang(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_at(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "impl");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s, "$");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::parse(&mut _s, "$");
                                            ::quote::__private::push_ident(&mut _s, "attrs");
                                            _s
                                        });
                                    ::quote::__private::push_star(&mut _s);
                                    _s
                                });
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s, "$");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::parse(&mut _s, "$");
                                            ::quote::__private::push_ident(&mut _s, "implementation");
                                            _s
                                        });
                                    ::quote::__private::push_star(&mut _s);
                                    _s
                                });
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut method_metadata, i) =
                                            method_metadata.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let method_metadata =
                                                match method_metadata.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&method_metadata, &mut _s);
                                        }
                                    }
                                    _s
                                });
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::ToTokens::to_tokens(&declaration_generics,
                                        &mut _s);
                                    _s
                                });
                            ::quote::ToTokens::to_tokens(&abi_metadata, &mut _s);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::ToTokens::to_tokens(&empty_impl_arm, &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_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, "unused_imports");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "use");
    ::quote::ToTokens::to_tokens(&metadata_macro_name, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
621        #[macro_export]
622        #[doc(hidden)]
623        macro_rules! #metadata_macro_name {
624            (@impl { $($attrs:tt)* } { $($implementation:tt)* }) => {
625                ::miniextendr_api::__mx_trait_impl_expand! {
626                    @impl { $($attrs)* } { $($implementation)* }
627                    { #(#method_metadata)* }
628                    { #declaration_generics }
629                    #abi_metadata
630                }
631            };
632            #empty_impl_arm
633        }
634        #[doc(hidden)]
635        #[allow(unused_imports)]
636        #vis use #metadata_macro_name as #trait_name;
637    };
638
639    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&clean_trait, &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,
                        "\"Type tag for runtime identification of the `\"");
                    ::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, "\"` trait.\"");
                    _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, "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::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "const");
    ::quote::ToTokens::to_tokens(&tag_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, "abi");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "mx_tag");
    ::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, "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(&tag_path, &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, "\"Vtable for the `\"");
                    ::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, "\"` trait.\"");
                    _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_eq(&mut _s);
            ::quote::__private::parse(&mut _s, "r\"\"");
            _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,
                "r\" Contains one `mx_meth` function pointer per trait method.\"");
            _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, "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_camel_case_types");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "struct");
    ::quote::ToTokens::to_tokens(&vtable_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 vtable_fields, i) = vtable_fields.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let vtable_fields =
                        match vtable_fields.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&vtable_fields, &mut _s);
                }
            }
            _s
        });
    ::quote::ToTokens::to_tokens(&view_tokens, &mut _s);
    ::quote::ToTokens::to_tokens(&shim_and_builder, &mut _s);
    ::quote::ToTokens::to_tokens(&metadata_macro, &mut _s);
    _s
}quote::quote! {
640        // Pass through the original trait (with #[miniextendr] attrs stripped from items)
641        #clean_trait
642
643        #[doc = ::core::concat!(
644            "Type tag for runtime identification of the `",
645            ::core::stringify!(#trait_name),
646            "` trait."
647        )]
648        #[doc = #source_loc_doc]
649        #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
650        #[allow(non_upper_case_globals)]
651        #vis const #tag_name: ::miniextendr_api::abi::mx_tag =
652            ::miniextendr_api::abi::mx_tag_from_path(#tag_path);
653
654        #[doc = ::core::concat!("Vtable for the `", ::core::stringify!(#trait_name), "` trait.")]
655        #[doc = #source_loc_doc]
656        #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
657        ///
658        /// Contains one `mx_meth` function pointer per trait method.
659        #[repr(C)]
660        #[doc(hidden)]
661        #[allow(non_camel_case_types)]
662        #vis struct #vtable_name {
663            #(#vtable_fields),*
664        }
665
666        #view_tokens
667
668        #shim_and_builder
669
670        #metadata_macro
671    }
672}
673
674/// Encode the exported interface, in vtable order, for `mx_tag_from_path`.
675///
676/// Types use syn's token rendering, not their source whitespace. This is a
677/// syntactic contract: the macro cannot resolve aliases or imported names.
678/// Length-prefix every component so custom R names cannot change its framing.
679fn trait_abi_tag_path(trait_name: &syn::Ident, methods: &[MethodInfo]) -> String {
680    fn push(out: &mut String, component: &str) {
681        use std::fmt::Write;
682        out.write_fmt(format_args!("{0}:{1}", component.len(), component))write!(out, "{}:{component}", component.len()).unwrap();
683    }
684
685    let mut tag = String::from("miniextendr::trait-abi/v2;");
686    push(&mut tag, &crate::naming::ident_name(trait_name));
687    push(&mut tag, &methods.len().to_string());
688    for method in methods {
689        let name = crate::naming::ident_name(&method.name);
690        push(&mut tag, &name);
691        push(&mut tag, method.r_name.as_deref().unwrap_or(&name));
692        push(
693            &mut tag,
694            match method.owner_receiver {
695                Some(crate::trait_receiver::OwnerReceiver::Shared) => "owner-ref",
696                Some(crate::trait_receiver::OwnerReceiver::Mutable) => "owner-mut",
697                None if method.is_mut => "mut",
698                None => "ref",
699            },
700        );
701        push(&mut tag, &method.param_types.len().to_string());
702        for ty in &method.param_types {
703            push(&mut tag, &quote::ToTokens::to_token_stream(ty).to_string());
704        }
705        let result = method
706            .return_type
707            .as_ref()
708            .map(|ty| quote::ToTokens::to_token_stream(ty).to_string())
709            .unwrap_or_else(|| "()".to_owned());
710        push(&mut tag, &result);
711    }
712    tag
713}
714
715/// Generate a method wrapper for the View struct.
716///
717/// This creates a method on the View that calls through the vtable.
718/// Returns None for methods with `Self` in return types or `&Self` in parameters,
719/// since these can't be meaningfully expressed on the type-erased View.
720fn generate_view_method(method: &MethodInfo) -> Option<TokenStream> {
721    // Skip methods where Self appears in return type or parameters.
722    // In the View context, Self refers to the View struct, not the concrete type,
723    // so these methods can't work through the type-erased vtable dispatch.
724    if method.return_type.as_ref().is_some_and(type_contains_self) {
725        return None;
726    }
727    if method.param_types.iter().any(type_contains_self) {
728        return None;
729    }
730
731    let method_name = &method.name;
732    let param_names = &method.param_names;
733    let param_types = &method.param_types;
734
735    // Generate function parameters
736    let params: Vec<_> = param_names
737        .iter()
738        .zip(param_types.iter())
739        .map(|(name, ty)| {
740            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    _s
}quote::quote! { #name: #ty }
741        })
742        .collect();
743
744    // Generate self receiver
745    let self_param = if method.is_mut {
746        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_ident(&mut _s, "mut");
    ::quote::__private::push_ident(&mut _s, "self");
    _s
}quote::quote! { &mut self }
747    } else {
748        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_ident(&mut _s, "self");
    _s
}quote::quote! { &self }
749    };
750
751    // Generate argument array for vtable call. A `Missing<T>` argument (an
752    // omittable parameter, e.g. a choice, #1551) crosses as R's
753    // missing-argument sentinel when absent, which the shim's
754    // `TryFromSexp for Missing<T>` reads back; `Missing` has no `IntoR`.
755    let argc = param_types.len() as i32;
756    let arg_conversions: Vec<_> = param_names
757        .iter()
758        .zip(param_types.iter())
759        .map(|(name, ty)| {
760            if crate::miniextendr_fn::get_missing_inner_type(ty).is_some() {
761                {
    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, "missing_to_sexp");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&name, &mut _s);
            _s
        });
    _s
}quote::quote! {
762                    ::miniextendr_api::trait_abi::missing_to_sexp(#name)
763                }
764            } else {
765                {
    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::ToTokens::to_tokens(&name, &mut _s);
            _s
        });
    _s
}quote::quote! {
766                    ::miniextendr_api::trait_abi::to_sexp(#name)
767                }
768            }
769        })
770        .collect();
771
772    // Generate vtable call. Each converted argument is rooted before the next
773    // conversion allocates, and stays rooted for the whole call: the shim reads
774    // every `argv` entry back, and SEXP-backed parameters live on in the method
775    // body (the `mx_meth` contract).
776    let owner_argument = method.owner_receiver.map(|_| {
777        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__mx_view");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "owner");
    ::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, "expect");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::parse(&mut _s,
                "\"this trait method requires an R-owned receiver\"");
            _s
        });
    ::quote::__private::push_comma(&mut _s);
    _s
}quote::quote! {
778            self.__mx_view.owner().expect("this trait method requires an R-owned receiver"),
779        }
780    });
781    let vtable_call = if argc > 0 {
782        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "args");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            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, "SEXP");
            ::quote::__private::push_semi(&mut _s);
            ::quote::ToTokens::to_tokens(&argc, &mut _s);
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "usize");
            _s
        });
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            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 arg_conversions, i) =
                    arg_conversions.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let arg_conversions =
                        match arg_conversions.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::__private::push_ident(&mut _s, "__mx_roots");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "protect_raw");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&arg_conversions, &mut _s);
                            _s
                        });
                }
            }
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_star(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__mx_view");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "vtable");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    _s
                });
            ::quote::__private::push_dot(&mut _s);
            ::quote::ToTokens::to_tokens(&method_name, &mut _s);
            _s
        });
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "__mx_view");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "data");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&owner_argument, &mut _s);
            ::quote::ToTokens::to_tokens(&argc, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "args");
            ::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());
            _s
        });
    _s
}quote::quote! {
783            let args: [::miniextendr_api::SEXP; #argc as usize] =
784                [#(__mx_roots.protect_raw(#arg_conversions)),*];
785            ((*self.__mx_view.vtable()).#method_name)(self.__mx_view.data(), #owner_argument #argc, args.as_ptr())
786        }
787    } else {
788        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_star(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__mx_view");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "vtable");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    _s
                });
            ::quote::__private::push_dot(&mut _s);
            ::quote::ToTokens::to_tokens(&method_name, &mut _s);
            _s
        });
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "__mx_view");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "data");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&owner_argument, &mut _s);
            ::quote::__private::parse(&mut _s, "0");
            ::quote::__private::push_comma(&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, "ptr");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "null");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            _s
        });
    _s
}quote::quote! {
789            ((*self.__mx_view.vtable()).#method_name)(self.__mx_view.data(), #owner_argument 0, ::std::ptr::null())
790        }
791    };
792
793    // Generate return type handling. A returned value is rooted across the
794    // tagged-error check and its conversion back to Rust.
795    let return_type = &method.return_type;
796    let (return_sig, result_binding, result_conversion) = if let Some(ret_ty) = return_type {
797        (
798            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::ToTokens::to_tokens(&ret_ty, &mut _s);
    _s
}quote::quote! { -> #ret_ty },
799            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "result");
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__mx_roots");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "protect_raw");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&vtable_call, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! { let result = __mx_roots.protect_raw({ #vtable_call }); },
800            {
    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, "from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ret_ty, &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_ident(&mut _s, "result");
            _s
        });
    _s
}quote::quote! {
801                ::miniextendr_api::trait_abi::from_sexp::<#ret_ty>(result)
802            },
803        )
804    } else {
805        (
806            ::quote::__private::TokenStream::new()quote::quote! {},
807            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "result");
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&vtable_call, &mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! { let result = { #vtable_call }; },
808            {
    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);
    _s
}quote::quote! {
809                let _ = result;
810            },
811        )
812    };
813
814    // The scope owns the argument and result protections; a method with
815    // neither has nothing to root.
816    let roots = if argc > 0 || return_type.is_some() {
817        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "__mx_roots");
    ::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, "gc_protect");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ProtectScope");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "new");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
818            let __mx_roots = ::miniextendr_api::gc_protect::ProtectScope::new();
819        }
820    } else {
821        ::quote::__private::TokenStream::new();quote::quote! {}
822    };
823
824    // The view keeps the trait's parameter names, so a `_self` parameter (R
825    // formal `self`) sits beside the `self` receiver here too.
826    Some({
    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_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, "\"Call `\"");
                    ::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(&method_name, &mut _s);
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::parse(&mut _s,
                        "\"` through the vtable.\"");
                    _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, "inline");
            _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, "clippy");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "duplicate_underscore_argument");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "pub");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&method_name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&self_param, &mut _s);
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut params, i) = params.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let params =
                        match params.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::ToTokens::to_tokens(&params, &mut _s);
                }
            }
            _s
        });
    ::quote::ToTokens::to_tokens(&return_sig, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            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::ToTokens::to_tokens(&roots, &mut _s);
                    ::quote::ToTokens::to_tokens(&result_binding, &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, "trait_abi");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "repanic_if_rust_error");
                    ::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
                        });
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::ToTokens::to_tokens(&result_conversion, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote::quote! {
827        #[doc = ::core::concat!("Call `", ::core::stringify!(#method_name), "` through the vtable.")]
828        #[inline]
829        #[allow(clippy::duplicate_underscore_argument)]
830        pub fn #method_name(#self_param #(, #params)*) #return_sig {
831            unsafe {
832                #roots
833                #result_binding
834                // Approach 1 (issue #345): if the shim returned a tagged error SEXP,
835                // re-panic with the reconstructed RCondition so the consumer's outer
836                // `with_r_unwind_protect` guard can apply rust_* class layering.
837                ::miniextendr_api::trait_abi::repanic_if_rust_error(result);
838                #result_conversion
839            }
840        }
841    })
842}
843
844/// Generate a method shim function for a trait method.
845///
846/// The shim is an `extern "C"` function that, inside `with_r_unwind_protect_shim`:
847/// 1. Checks argument arity
848/// 2. Refuses aliased native borrows among the arguments
849/// 3. Converts SEXP arguments to Rust types
850/// 4. Calls the actual method on the concrete type
851/// 5. Converts the result back to SEXP
852///
853/// A panic in any step comes back as a tagged condition SEXP, which the View
854/// re-panics with. `generate_concrete_vtable_shims` emits the same steps for
855/// a generic trait's impls.
856///
857/// For generic traits, the shim carries the trait's type parameters plus `__ImplT`.
858fn generate_method_shim(
859    trait_name: &syn::Ident,
860    method: &MethodInfo,
861    extra_bounds: &ExtraBounds,
862    trait_param_idents: &[&syn::Ident],
863    trait_type_params: &[&syn::GenericParam],
864    trait_where_clause: &Option<syn::WhereClause>,
865) -> TokenStream {
866    let method_name = &method.name;
867    let shim_name = crate::naming::trait_method_shim_ident(trait_name, method_name);
868    let impl_t = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__ImplT"))
            }), ::quote::__private::Option::None)quote::format_ident!("__ImplT");
869    // User argument bindings keep their source spans. The shim's own
870    // bindings must remain distinct even when a parameter has the same name.
871    let data = syn::Ident::new("data", proc_macro2::Span::mixed_site());
872    let argc = syn::Ident::new("argc", proc_macro2::Span::mixed_site());
873    let argv = syn::Ident::new("argv", proc_macro2::Span::mixed_site());
874    let self_ref = syn::Ident::new("self_ref", proc_macro2::Span::mixed_site());
875    let cell = syn::Ident::new("__mx_cell", proc_macro2::Span::mixed_site());
876    let guard = syn::Ident::new("__mx_guard", proc_macro2::Span::mixed_site());
877    let owner = syn::Ident::new("owner", proc_macro2::Span::mixed_site());
878    let owner_parameter = method.owner_receiver.map(|_| {
879        {
    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! {
880            #owner: ::miniextendr_api::SEXP,
881        }
882    });
883
884    let param_count = method.param_types.len();
885    let expected_argc = param_count as i32;
886
887    // Generate argument extraction
888    // For &Self params, extract ExternalPtr<__ImplT> and borrow from it
889    let arg_extractions: Vec<_> = method
890        .param_names
891        .iter()
892        .zip(method.param_types.iter())
893        .enumerate()
894        .map(|(i, (name, ty))| {
895            crate::trait_self_ref::argument(
896                name,
897                &crate::naming::ident_name(name),
898                ty,
899                &impl_t,
900                i,
901                &argv,
902                None,
903            )
904        })
905        .collect();
906
907    let native_borrow_checks = crate::trait_self_ref::native_borrow_checks(
908        method
909            .param_names
910            .iter()
911            .zip(&method.param_types)
912            .enumerate()
913            .map(|(index, (name, ty))| (index, crate::naming::ident_name(name), ty)),
914        &argv,
915        None,
916    );
917
918    let self_refs: Vec<_> = method
919        .param_names
920        .iter()
921        .zip(&method.param_types)
922        .enumerate()
923        .filter_map(|(index, (name, ty))| {
924            crate::type_inspect::self_ref_mutability(ty).map(|mutable| (name, mutable, index))
925        })
926        .collect();
927    let handles: Vec<_> = self_refs
928        .iter()
929        .map(|(name, mutable, _)| {
930            (
931                crate::trait_self_ref::handle_ident(name),
932                *mutable,
933                crate::naming::ident_name(name),
934            )
935        })
936        .collect();
937    let alias_checks = crate::trait_self_ref::alias_checks(
938        &impl_t,
939        &handles,
940        Some((crate::trait_self_ref::cell_address(&cell), method.is_mut)),
941    );
942    let self_borrows = self_refs
943        .iter()
944        .map(|(name, mutable, _)| crate::trait_self_ref::borrow(name, *mutable));
945
946    // Generate method call (uses __ImplT). The receiver borrows the value's
947    // RefCell for the rest of the shim, through the result conversion.
948    let param_names = &method.param_names;
949    let (receiver, method_call) = if let Some(kind) = method.owner_receiver {
950        let handle = kind.type_path();
951        let trait_args =
952            (!trait_param_idents.is_empty()).then(|| {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut trait_param_idents, i) =
            trait_param_idents.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let trait_param_idents =
                match trait_param_idents.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&trait_param_idents, &mut _s);
        }
    }
    ::quote::__private::push_gt(&mut _s);
    _s
}quote::quote!(<#(#trait_param_idents),*>));
953        (
954            {
    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(&impl_t, &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! {
955                let #self_ref = unsafe {
956                    #handle::<#impl_t>::from_raw_parts(
957                        &#owner,
958                        #cell,
959                    )
960                };
961            },
962            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    ::quote::ToTokens::to_tokens(&trait_args, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&method_name, &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(&param_names, &mut _s);
                }
            }
            _s
        });
    _s
}quote::quote! {
963                <#impl_t as #trait_name #trait_args>::#method_name(#self_ref, #(#param_names),*)
964            },
965        )
966    } else {
967        (
968            crate::trait_self_ref::receiver_borrow(&cell, &guard, &self_ref, method.is_mut),
969            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&self_ref, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&method_name, &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 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(&param_names, &mut _s);
                }
            }
            _s
        });
    _s
}quote::quote! { #self_ref.#method_name(#(#param_names),*) },
970        )
971    };
972
973    // Generate result conversion
974    let result_conversion = if method.return_type.is_some() {
975        {
    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! {
976            unsafe { ::miniextendr_api::trait_abi::to_sexp(result) }
977        }
978    } else {
979        {
    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! {
980            let _ = result;
981            unsafe { ::miniextendr_api::trait_abi::nil() }
982        }
983    };
984
985    // Build trait bound for __ImplT
986    let trait_bound = if trait_param_idents.is_empty() {
987        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    _s
}quote::quote! { #trait_name }
988    } else {
989        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut trait_param_idents, i) =
            trait_param_idents.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let trait_param_idents =
                match trait_param_idents.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&trait_param_idents, &mut _s);
        }
    }
    ::quote::__private::push_gt(&mut _s);
    _s
}quote::quote! { #trait_name<#(#trait_param_idents),*> }
990    };
991
992    let impl_bounds = &extra_bounds.impl_bounds;
993    let all_where_predicates = build_where_predicates(trait_where_clause, extra_bounds);
994    let where_clause = if all_where_predicates.is_empty() {
995        ::quote::__private::TokenStream::new();quote::quote! {}
996    } else {
997        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut all_where_predicates, i) =
            all_where_predicates.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let all_where_predicates =
                match all_where_predicates.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&all_where_predicates, &mut _s);
        }
    }
    _s
}quote::quote! { where #(#all_where_predicates),* }
998    };
999
1000    let method_name_str = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::{1}", trait_name,
                method_name))
    })format!("{}::{}", trait_name, method_name);
1001
1002    {
    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_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, "\"Method shim 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(&trait_name, &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, "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(&method_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::__private::parse(&mut _s, "r\"\"");
            _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,
                "r\" Converts SEXP arguments, calls the method, and returns SEXP result.\"");
            _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,
                "r\" Both Rust panics and R longjmps are caught via `with_r_unwind_protect`.\"");
            _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, "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_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut trait_type_params, i) = trait_type_params.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let trait_type_params =
                match trait_type_params.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&trait_type_params, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::ToTokens::to_tokens(&trait_bound, &mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut impl_bounds, i) = impl_bounds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let impl_bounds =
                match impl_bounds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::__private::push_add(&mut _s);
            ::quote::ToTokens::to_tokens(&impl_bounds, &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(&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::ToTokens::to_tokens(&where_clause, &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, "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(&impl_t, &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(&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(&method_call, &mut _s);
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::ToTokens::to_tokens(&result_conversion, &mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote::quote! {
1003        #[doc = ::core::concat!(
1004            "Method shim for `",
1005            ::core::stringify!(#trait_name),
1006            "::",
1007            ::core::stringify!(#method_name),
1008            "`."
1009        )]
1010        ///
1011        /// Converts SEXP arguments, calls the method, and returns SEXP result.
1012        /// Both Rust panics and R longjmps are caught via `with_r_unwind_protect`.
1013        #[doc(hidden)]
1014        #[allow(non_snake_case)]
1015        unsafe extern "C" fn #shim_name<#(#trait_type_params,)* #impl_t: #trait_bound #(+ #impl_bounds)*>(
1016            #data: *mut ::std::os::raw::c_void,
1017            #owner_parameter
1018            #argc: i32,
1019            #argv: *const ::miniextendr_api::SEXP,
1020        ) -> ::miniextendr_api::SEXP
1021        #where_clause
1022        {
1023            // Wrap in with_r_unwind_protect_shim: catches Rust panics and returns
1024            // a tagged error SEXP instead of calling Rf_errorcall directly. The
1025            // tagged SEXP is returned to the View method wrapper which re-panics
1026            // via repanic_if_rust_error, allowing the consumer's outer
1027            // `with_r_unwind_protect` guard to produce rust_* class layering
1028            // (issue #345). R-origin longjmps still propagate via R_ContinueUnwind.
1029            ::miniextendr_api::unwind_protect::with_r_unwind_protect_shim(|| {
1030                ::miniextendr_api::trait_abi::check_arity(#argc, #expected_argc, #method_name_str);
1031                let #cell = unsafe { &*#data.cast::<::core::cell::RefCell<#impl_t>>() };
1032                #native_borrow_checks
1033                // Extract arguments
1034                #(#arg_extractions)*
1035                #alias_checks
1036                #(#self_borrows)*
1037
1038                // Call method
1039                #receiver
1040                let result = #method_call;
1041
1042                // Convert result
1043                #result_conversion
1044            })
1045        }
1046    }
1047}
1048
1049/// Move the declaration shim into the trait so an impl can name it through
1050/// any path to that trait. `Self: Sized` keeps these static ABI callbacks out
1051/// of Rust trait objects. Types in the body still resolve at the declaration.
1052fn associated_method_shim(tokens: TokenStream) -> syn::TraitItemFn {
1053    use syn::visit_mut::VisitMut;
1054
1055    struct ImplTypeToSelf;
1056    impl VisitMut for ImplTypeToSelf {
1057        fn visit_path_mut(&mut self, path: &mut syn::Path) {
1058            syn::visit_mut::visit_path_mut(self, path);
1059            if let Some(first) = path.segments.first_mut()
1060                && first.ident == "__ImplT"
1061            {
1062                first.ident = syn::Ident::new("Self", first.ident.span());
1063            }
1064        }
1065    }
1066
1067    let mut shim: syn::TraitItemFn = syn::parse2(tokens).expect("generated method shim");
1068    let syn::GenericParam::Type(implementation) =
1069        shim.sig.generics.params.pop().unwrap().into_value()
1070    else {
1071        {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("the final generated parameter is __ImplT")));
}unreachable!("the final generated parameter is __ImplT")
1072    };
1073    let bounds = implementation.bounds;
1074    shim.sig
1075        .generics
1076        .make_where_clause()
1077        .predicates
1078        .push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "Self");
        ::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, "marker");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Sized");
        ::quote::__private::push_add(&mut _s);
        ::quote::ToTokens::to_tokens(&bounds, &mut _s);
        _s
    })syn::parse_quote!(Self: ::core::marker::Sized + #bounds));
1079    ImplTypeToSelf.visit_trait_item_fn_mut(&mut shim);
1080    shim
1081}
1082
1083/// Information extracted from a trait method for code generation.
1084///
1085/// Collects everything needed to generate vtable shims, view methods,
1086/// and extra trait bounds for a single method in a `#[miniextendr]` trait.
1087#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MethodInfo {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["name", "has_self", "is_mut", "owner_receiver", "param_types",
                        "param_names", "return_type", "skip", "r_name"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.name, &self.has_self, &self.is_mut, &self.owner_receiver,
                        &self.param_types, &self.param_names, &self.return_type,
                        &self.skip, &&self.r_name];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "MethodInfo",
            names, values)
    }
}Debug)]
1088struct MethodInfo {
1089    /// Method name (Rust identifier).
1090    name: syn::Ident,
1091    /// Whether the method has a self receiver (instance method).
1092    /// False for static/associated methods.
1093    has_self: bool,
1094    /// Whether receiver is `&mut self` (vs `&self`). Only meaningful if `has_self` is true.
1095    is_mut: bool,
1096    owner_receiver: Option<crate::trait_receiver::OwnerReceiver>,
1097    /// Parameter types (excluding the self receiver).
1098    param_types: Vec<syn::Type>,
1099    /// Parameter names (excluding the self receiver). Uses `arg{i}` for unnamed patterns.
1100    param_names: Vec<syn::Ident>,
1101    /// Return type. `None` when the method returns `()` (unit type or no return annotation).
1102    return_type: Option<syn::Type>,
1103    /// Whether method is marked `#[miniextendr(skip)]`, excluding it from codegen.
1104    skip: bool,
1105    /// Override the R-facing method name (from `#[miniextendr(r_name = "...")]`).
1106    /// When set, R wrappers and TPIE metadata use this name instead of the Rust ident.
1107    r_name: Option<String>,
1108}
1109
1110// region: Self-type detection helpers
1111
1112/// Check if a type syntactically contains `Self`.
1113///
1114/// Used to detect when a method returns `Self` (or `Option<Self>`, `Vec<Self>`, etc.)
1115/// so the generated shim can add `IntoR` bounds.
1116fn type_contains_self(ty: &syn::Type) -> bool {
1117    match ty {
1118        syn::Type::Path(tp) => {
1119            for seg in &tp.path.segments {
1120                if seg.ident == "Self" {
1121                    return true;
1122                }
1123                if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
1124                    for arg in &args.args {
1125                        if let syn::GenericArgument::Type(inner) = arg
1126                            && type_contains_self(inner)
1127                        {
1128                            return true;
1129                        }
1130                    }
1131                }
1132            }
1133            false
1134        }
1135        syn::Type::Reference(r) => type_contains_self(&r.elem),
1136        syn::Type::Tuple(t) => t.elems.iter().any(type_contains_self),
1137        syn::Type::Slice(s) => type_contains_self(&s.elem),
1138        syn::Type::Array(a) => type_contains_self(&a.elem),
1139        syn::Type::Paren(p) => type_contains_self(&p.elem),
1140        _ => false,
1141    }
1142}
1143
1144/// Check if a type syntactically contains `Self::AssocType` for a given associated type name.
1145///
1146/// Recursively walks the type tree looking for a 2-segment path where the first
1147/// segment is `Self` and the second matches `assoc_name` (e.g., `Self::Item`).
1148/// Used to determine whether extra `where` bounds are needed for associated types.
1149fn type_contains_self_assoc(ty: &syn::Type, assoc_name: &syn::Ident) -> bool {
1150    match ty {
1151        syn::Type::Path(tp) => {
1152            if tp.path.segments.len() == 2
1153                && tp.path.segments[0].ident == "Self"
1154                && tp.path.segments[1].ident == *assoc_name
1155            {
1156                return true;
1157            }
1158            for seg in &tp.path.segments {
1159                if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
1160                    for arg in &args.args {
1161                        if let syn::GenericArgument::Type(inner) = arg
1162                            && type_contains_self_assoc(inner, assoc_name)
1163                        {
1164                            return true;
1165                        }
1166                    }
1167                }
1168            }
1169            false
1170        }
1171        syn::Type::Reference(r) => type_contains_self_assoc(&r.elem, assoc_name),
1172        syn::Type::Tuple(t) => t
1173            .elems
1174            .iter()
1175            .any(|e| type_contains_self_assoc(e, assoc_name)),
1176        syn::Type::Slice(s) => type_contains_self_assoc(&s.elem, assoc_name),
1177        syn::Type::Array(a) => type_contains_self_assoc(&a.elem, assoc_name),
1178        syn::Type::Paren(p) => type_contains_self_assoc(&p.elem, assoc_name),
1179        _ => false,
1180    }
1181}
1182
1183/// Rewrite `Self` and `Self::AssocType` in a type tree to use `__ImplT`.
1184///
1185/// Transforms:
1186/// - `Self` → `__ImplT`
1187/// - `Self::Item` → `<__ImplT as TraitName>::Item`
1188/// - Recursively processes generic arguments (e.g., `Option<Self::Item>` →
1189///   `Option<<__ImplT as TraitName>::Item>`)
1190fn rewrite_self_in_type(
1191    ty: &syn::Type,
1192    trait_name: &syn::Ident,
1193    assoc_types: &[&syn::Ident],
1194) -> syn::Type {
1195    match ty {
1196        syn::Type::Path(tp) => {
1197            // Check for Self::AssocType (2-segment path: Self::Item)
1198            if tp.path.segments.len() == 2
1199                && tp.path.segments[0].ident == "Self"
1200                && assoc_types.iter().any(|a| *a == &tp.path.segments[1].ident)
1201            {
1202                let assoc = &tp.path.segments[1].ident;
1203                let impl_t = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__ImplT"))
            }), ::quote::__private::Option::None)quote::format_ident!("__ImplT");
1204                return ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
        ::quote::__private::push_ident(&mut _s, "as");
        ::quote::ToTokens::to_tokens(&trait_name, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::ToTokens::to_tokens(&assoc, &mut _s);
        _s
    })syn::parse_quote!(<#impl_t as #trait_name>::#assoc);
1205            }
1206            // Check for bare Self
1207            if tp.path.is_ident("Self") {
1208                let impl_t = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__ImplT"))
            }), ::quote::__private::Option::None)quote::format_ident!("__ImplT");
1209                return ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&impl_t, &mut _s);
        _s
    })syn::parse_quote!(#impl_t);
1210            }
1211            // Recursively process generic args
1212            let mut new_tp = tp.clone();
1213            for seg in &mut new_tp.path.segments {
1214                if let syn::PathArguments::AngleBracketed(args) = &mut seg.arguments {
1215                    for arg in &mut args.args {
1216                        if let syn::GenericArgument::Type(inner) = arg {
1217                            *inner = rewrite_self_in_type(inner, trait_name, assoc_types);
1218                        }
1219                    }
1220                }
1221            }
1222            syn::Type::Path(new_tp)
1223        }
1224        syn::Type::Reference(r) => {
1225            let mut new_r = r.clone();
1226            new_r.elem = Box::new(rewrite_self_in_type(&r.elem, trait_name, assoc_types));
1227            syn::Type::Reference(new_r)
1228        }
1229        syn::Type::Tuple(t) => {
1230            let mut new_t = t.clone();
1231            for elem in &mut new_t.elems {
1232                *elem = rewrite_self_in_type(elem, trait_name, assoc_types);
1233            }
1234            syn::Type::Tuple(new_t)
1235        }
1236        syn::Type::Slice(s) => {
1237            let mut new_s = s.clone();
1238            new_s.elem = Box::new(rewrite_self_in_type(&s.elem, trait_name, assoc_types));
1239            syn::Type::Slice(new_s)
1240        }
1241        syn::Type::Array(a) => {
1242            let mut new_a = a.clone();
1243            new_a.elem = Box::new(rewrite_self_in_type(&a.elem, trait_name, assoc_types));
1244            syn::Type::Array(new_a)
1245        }
1246        syn::Type::Paren(p) => {
1247            let mut new_p = p.clone();
1248            new_p.elem = Box::new(rewrite_self_in_type(&p.elem, trait_name, assoc_types));
1249            syn::Type::Paren(new_p)
1250        }
1251        _ => ty.clone(),
1252    }
1253}
1254
1255/// Check if a type syntactically contains a specific identifier.
1256///
1257/// Used to detect trait type parameters (like `T`) in method signatures so that
1258/// appropriate `TryFromSexp` or `IntoR` bounds can be added. Recursively walks
1259/// through path segments, generic arguments, references, tuples, slices, and arrays.
1260fn type_contains_ident(ty: &syn::Type, ident: &syn::Ident) -> bool {
1261    match ty {
1262        syn::Type::Path(tp) => {
1263            if tp.path.segments.len() == 1 && tp.path.segments[0].ident == *ident {
1264                return true;
1265            }
1266            for seg in &tp.path.segments {
1267                if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
1268                    for arg in &args.args {
1269                        if let syn::GenericArgument::Type(inner) = arg
1270                            && type_contains_ident(inner, ident)
1271                        {
1272                            return true;
1273                        }
1274                    }
1275                }
1276            }
1277            false
1278        }
1279        syn::Type::Reference(r) => type_contains_ident(&r.elem, ident),
1280        syn::Type::Tuple(t) => t.elems.iter().any(|e| type_contains_ident(e, ident)),
1281        syn::Type::Slice(s) => type_contains_ident(&s.elem, ident),
1282        syn::Type::Array(a) => type_contains_ident(&a.elem, ident),
1283        syn::Type::Paren(p) => type_contains_ident(&p.elem, ident),
1284        _ => false,
1285    }
1286}
1287
1288/// Extra trait bounds inferred from method signatures.
1289///
1290/// For generic traits and methods that reference `Self` or associated types,
1291/// the generated shim and vtable builder functions need additional bounds
1292/// beyond `__ImplT: TraitName`. This struct collects those bounds.
1293struct ExtraBounds {
1294    /// Bounds added directly to `__ImplT` (e.g., `IntoR` when methods return `Self`,
1295    /// or `TypedExternal + Send + 'static` when methods take `&Self` parameters).
1296    impl_bounds: Vec<TokenStream>,
1297    /// Where clause predicates for complex types (e.g.,
1298    /// `<__ImplT as Trait>::Item: IntoR` or `Vec<T>: TryFromSexp`).
1299    where_predicates: Vec<TokenStream>,
1300}
1301
1302/// Compute extra bounds needed for the shim and build_vtable functions.
1303///
1304/// - Methods returning `Self` → `__ImplT: IntoR`
1305/// - Methods with `&Self` params → `__ImplT: TypedExternal + Send + 'static`
1306/// - Methods returning types with `Self::AssocType` or trait type params →
1307///   full rewritten return type `: IntoR` (e.g., `Nullable<<__ImplT as RIterator>::Item>: IntoR`)
1308/// - Methods with trait type params in params →
1309///   full param type `: TryFromSexp` (e.g., `Vec<T>: TryFromSexp`)
1310fn compute_extra_bounds(
1311    methods: &[MethodInfo],
1312    trait_name: &syn::Ident,
1313    assoc_types: &[&syn::Ident],
1314    trait_param_idents: &[&syn::Ident],
1315) -> ExtraBounds {
1316    let mut impl_bounds = Vec::new();
1317    let mut where_predicates = Vec::new();
1318
1319    let mut needs_into_r = false;
1320    let mut needs_typed_external = false;
1321    let needs_owner = methods.iter().any(|method| method.owner_receiver.is_some());
1322
1323    // Track full types needing bounds (deduplicated by token string)
1324    let mut return_type_bound_keys: std::collections::BTreeMap<String, syn::Type> =
1325        Default::default();
1326    let mut param_type_bound_keys: std::collections::BTreeMap<String, syn::Type> =
1327        Default::default();
1328
1329    for method in methods {
1330        // Bare Self in returns → __ImplT: IntoR (as impl bound)
1331        if method.return_type.as_ref().is_some_and(type_contains_self) {
1332            needs_into_r = true;
1333        }
1334        // &Self in params → __ImplT: TypedExternal + 'static
1335        if method
1336            .param_types
1337            .iter()
1338            .any(|ty| crate::type_inspect::self_ref_mutability(ty).is_some())
1339        {
1340            needs_typed_external = true;
1341        }
1342
1343        // Full return type bounds for Self::AssocType and/or trait type params.
1344        // Instead of bare `<__ImplT as Trait>::Item: IntoR`, we add the FULL rewritten
1345        // return type: `Option<<__ImplT as Trait>::Item>: IntoR`, `Vec<T>: IntoR`, etc.
1346        // This is required because IntoR impls are concrete (no blanket `Option<T: IntoR>: IntoR`).
1347        if let Some(ref ret_ty) = method.return_type {
1348            let has_assoc = assoc_types
1349                .iter()
1350                .any(|a| type_contains_self_assoc(ret_ty, a));
1351            let has_param = trait_param_idents
1352                .iter()
1353                .any(|p| type_contains_ident(ret_ty, p));
1354            if has_assoc || has_param {
1355                let rewritten = rewrite_self_in_type(ret_ty, trait_name, assoc_types);
1356                let key = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&rewritten, &mut _s);
    _s
}quote::quote!(#rewritten).to_string();
1357                return_type_bound_keys.entry(key).or_insert(rewritten);
1358            }
1359        }
1360
1361        // Full param type bounds for trait type params.
1362        // Instead of bare `T: TryFromSexp`, we add `Vec<T>: TryFromSexp` etc.
1363        for param_ty in &method.param_types {
1364            if crate::type_inspect::self_ref_mutability(param_ty).is_none() {
1365                let has_param = trait_param_idents
1366                    .iter()
1367                    .any(|p| type_contains_ident(param_ty, p));
1368                if has_param {
1369                    let key = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&param_ty, &mut _s);
    _s
}quote::quote!(#param_ty).to_string();
1370                    param_type_bound_keys.entry(key).or_insert(param_ty.clone());
1371                }
1372            }
1373        }
1374    }
1375
1376    if needs_into_r {
1377        impl_bounds.push({
    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, "IntoR");
    _s
}quote::quote! { ::miniextendr_api::IntoR });
1378    }
1379    if needs_typed_external {
1380        impl_bounds.push(
1381            {
    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, "TypedExternal");
    ::quote::__private::push_add(&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, "marker");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Send");
    ::quote::__private::push_add(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'static");
    _s
}quote::quote! { ::miniextendr_api::TypedExternal + ::core::marker::Send + 'static },
1382        );
1383    }
1384
1385    if needs_owner && !needs_typed_external {
1386        impl_bounds.push({
    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, "TypedExternal");
    _s
}quote::quote! { ::miniextendr_api::TypedExternal });
1387    }
1388
1389    // Add full return type bounds: RewrittenType: IntoR
1390    for ty in return_type_bound_keys.values() {
1391        where_predicates.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ty, &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, "IntoR");
    _s
}quote::quote! {
1392            #ty: ::miniextendr_api::IntoR
1393        });
1394    }
1395
1396    // Add full param type bounds: ParamType: TryFromSexp, Error: Display
1397    for ty in param_type_bound_keys.values() {
1398        where_predicates.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ty, &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, "TryFromSexp");
    _s
}quote::quote! {
1399            #ty: ::miniextendr_api::TryFromSexp
1400        });
1401        where_predicates.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::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, "TryFromSexp");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Error");
    ::quote::__private::push_colon(&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, "fmt");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Display");
    _s
}quote::quote! {
1402            <#ty as ::miniextendr_api::TryFromSexp>::Error: ::std::fmt::Display
1403        });
1404    }
1405
1406    ExtraBounds {
1407        impl_bounds,
1408        where_predicates,
1409    }
1410}
1411
1412/// Build combined where predicates from the trait's own where clause and computed extra bounds.
1413///
1414/// Merges the original trait-level where clause predicates with the extra
1415/// bounds computed from method signatures (e.g., `IntoR` for return types,
1416/// `TryFromSexp` for parameters containing trait type params).
1417///
1418/// Returns a flat list of predicates suitable for use in a `where` clause.
1419fn build_where_predicates(
1420    trait_where_clause: &Option<syn::WhereClause>,
1421    extra_bounds: &ExtraBounds,
1422) -> Vec<TokenStream> {
1423    let mut all = Vec::new();
1424    if let Some(wc) = trait_where_clause {
1425        for pred in &wc.predicates {
1426            all.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&pred, &mut _s);
    _s
}quote::quote! { #pred });
1427        }
1428    }
1429    all.extend(extra_bounds.where_predicates.iter().cloned());
1430    all
1431}
1432
1433/// Extract method information from a trait method definition.
1434///
1435/// Parses the method signature to determine receiver type, parameter names/types,
1436/// return type, and any `#[miniextendr(...)]` attributes like `skip` and `r_name`.
1437/// Parameters with non-ident patterns are assigned synthetic names (`arg0`, `arg1`, etc.).
1438fn extract_method_info(method: &syn::TraitItemFn) -> syn::Result<MethodInfo> {
1439    let name = method.sig.ident.clone();
1440
1441    // Check for #[miniextendr(skip)] and #[miniextendr(r_name = "...")]
1442    let mut skip = false;
1443    let mut r_name: Option<String> = None;
1444    for attr in &method.attrs {
1445        if !attr.path().is_ident("miniextendr") {
1446            continue;
1447        }
1448        attr.parse_nested_meta(|meta| {
1449            if meta.path.is_ident("skip") {
1450                skip = true;
1451            } else if meta.path.is_ident("r_name") {
1452                let value: syn::LitStr = meta.value()?.parse()?;
1453                r_name = Some(value.value());
1454            } else if meta.path.is_ident("formal") {
1455                return Err(meta.error(crate::miniextendr_fn::TRAIT_FORMAL_UNSUPPORTED));
1456            } else {
1457                return Err(meta.error(
1458                    "unknown #[miniextendr] option on trait method; expected `skip` or `r_name`",
1459                ));
1460            }
1461            Ok(())
1462        })?;
1463    }
1464
1465    // Check for receiver
1466    let (has_self, is_mut) = method.sig.inputs.first().map_or((false, false), |arg| {
1467        if let syn::FnArg::Receiver(_) = arg {
1468            (true, crate::trait_receiver::is_mut(&method.sig))
1469        } else {
1470            (false, false)
1471        }
1472    });
1473
1474    // Extract parameters (skip self if present)
1475    let skip_count = if has_self { 1 } else { 0 };
1476    let mut param_types = Vec::new();
1477    let mut param_names = Vec::new();
1478    for (i, arg) in method.sig.inputs.iter().skip(skip_count).enumerate() {
1479        if let syn::FnArg::Typed(pat_type) = arg {
1480            if crate::return_wrap::contains_marker(&pat_type.ty) {
1481                return Err(syn::Error::new_spanned(
1482                    &pat_type.ty,
1483                    "class return markers are return-position only",
1484                ));
1485            }
1486            // `Checked<T>` / `Unchecked<T>` (#1566) steer an R wrapper's type
1487            // checks, and a trait's View passes arguments on as R values: the
1488            // wrappers belong to each impl, which says it there.
1489            let (markers, _) = crate::type_inspect::peel_param_markers(&pat_type.ty)?;
1490            if let Some(marker) = markers.first() {
1491                let name = match pat_type.pat.as_ref() {
1492                    syn::Pat::Ident(pat_ident) => crate::naming::ident_name(&pat_ident.ident),
1493                    _ => "x".to_string(),
1494                };
1495                return Err(syn::Error::new_spanned(
1496                    &pat_type.ty,
1497                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}<T>` in a `#[miniextendr]` trait method: the trait\'s View passes arguments on as R values, and each impl\'s wrapper checks them; spell it on the impl, `#[miniextendr({1}({2}))]`",
                marker.name(),
                if marker.preconditions() == Some(true) {
                    "preconditions"
                } else { "no_preconditions" }, name))
    })format!(
1498                        "`{}<T>` in a `#[miniextendr]` trait method: the trait's View passes \
1499                         arguments on as R values, and each impl's wrapper checks them; spell it \
1500                         on the impl, `#[miniextendr({}({name}))]`",
1501                        marker.name(),
1502                        if marker.preconditions() == Some(true) {
1503                            "preconditions"
1504                        } else {
1505                            "no_preconditions"
1506                        },
1507                    ),
1508                ));
1509            }
1510            param_types.push((*pat_type.ty).clone());
1511            if let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() {
1512                param_names.push(pat_ident.ident.clone());
1513            } else {
1514                param_names.push(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())),
}quote::format_ident!("arg{}", i));
1515            }
1516        }
1517    }
1518
1519    // Extract return type. A visibility marker (`Invisible<T>` / `Visible<T>`,
1520    // #1213) only steers the implementing package's R wrapper; the View and
1521    // the vtable bounds work on the inner type.
1522    let return_type = match &method.sig.output {
1523        syn::ReturnType::Default => None,
1524        syn::ReturnType::Type(_, ty) => {
1525            if let Some(err) = crate::type_inspect::visibility_marker_error(ty, "return") {
1526                return Err(err);
1527            }
1528            let (_, ty) = crate::type_inspect::peel_visibility_marker(ty);
1529            let output: syn::ReturnType = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_rarrow(&mut _s);
        ::quote::ToTokens::to_tokens(&ty, &mut _s);
        _s
    })syn::parse_quote!(-> #ty);
1530            let (wrap, output) = crate::return_wrap::resolve(&output, None)?;
1531            if wrap.as_ref().is_some_and(|wrap| wrap.conversion.is_some()) {
1532                return Err(syn::Error::new_spanned(
1533                    ty,
1534                    "ConvertTo/ConvertFrom require an inherent S7 impl method",
1535                ));
1536            }
1537            let syn::ReturnType::Type(_, ty) = output else {
1538                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
1539            };
1540            let ty = ty.as_ref();
1541            // Check if it's unit type ()
1542            if #[allow(non_exhaustive_omitted_patterns)] match ty {
    syn::Type::Tuple(t) if t.elems.is_empty() => true,
    _ => false,
}matches!(ty, syn::Type::Tuple(t) if t.elems.is_empty()) {
1543                None
1544            } else {
1545                Some(ty.clone())
1546            }
1547        }
1548    };
1549
1550    Ok(MethodInfo {
1551        name,
1552        has_self,
1553        is_mut,
1554        owner_receiver: crate::trait_receiver::owner_receiver(&method.sig),
1555        param_types,
1556        param_names,
1557        return_type,
1558        skip,
1559        r_name,
1560    })
1561}
1562
1563#[cfg(test)]
1564mod tests;
1565// endregion