Skip to main content

miniextendr_macros/
rust_conversion_builder.rs

1//! Shared utilities for converting R SEXP parameters to Rust types.
2//!
3//! This module provides a builder for generating Rust conversion code from R SEXP arguments,
4//! ensuring consistent behavior across standalone functions and impl methods.
5
6use crate::miniextendr_fn::CoercionMapping;
7use proc_macro2::TokenStream;
8use quote::{quote, quote_spanned};
9use syn::spanned::Spanned;
10
11/// Builder for generating Rust conversion statements from R SEXP parameters.
12///
13/// Handles:
14/// - Unit types `()` → identity binding
15/// - `&Dots` → special wrapper with storage
16/// - Slices `&[T]` → TryFromSexp
17/// - `&str` → String + Borrow (for worker thread compatibility)
18/// - Scalar references → DATAPTR_RO_unchecked
19/// - Coercion → multi-source numeric conversion (incl. widened native `i32`/`f64`) or logical/integer bool conversion
20/// - Default → TryFromSexp
21pub struct RustConversionBuilder {
22    /// Infer copied trait signature types from a concrete method item.
23    inferred_types: bool,
24    /// Enable coercion for all parameters
25    coerce_all: bool,
26    /// Parameter names that should use coercion
27    coerce_params: Vec<String>,
28    /// Enable strict input conversion for lossy types
29    strict: bool,
30    /// Parameter names with `match_arg + several_ok` — use `match_arg_vec_from_sexp` instead of `TryFromSexp`.
31    match_arg_several_ok_params: Vec<String>,
32    /// Choice parameters whose type wraps the choice in `Missing` / `Option`
33    /// layers (#1473, #1551), with the kind of their innermost value. Decoded
34    /// by [`layered_choice_expr`] instead of `TryFromSexp`.
35    layered_choice_params: Vec<(String, ChoiceLeaf)>,
36    /// `no_na` parameters (Rust name) with the author's `no_na(message = ..)`,
37    /// if any: their converted value is checked right after the conversion
38    /// (see [`Self::with_no_na`]).
39    no_na_params: Vec<(String, Option<String>)>,
40    /// Parameters (Rust name) declared with parameter markers
41    /// (`Checked<T>` / `Unchecked<T>`, #1566), outermost first: the inner
42    /// type converts, then the value is wrapped (see
43    /// [`Self::with_param_markers`]).
44    param_markers: Vec<(String, Vec<crate::type_inspect::ParamMarker>)>,
45    /// The crate's `conversion_error_class` (`[package.metadata.miniextendr]`),
46    /// appended to every conversion condition's class vector.
47    conversion_error_class: Vec<String>,
48    /// Whether `Quoted` / `Quosure` parameters are bound (a standalone fn,
49    /// whose R wrapper passes them unevaluated, #1835). Elsewhere they are a
50    /// compile error.
51    unevaluated_args: bool,
52    /// The impl's type, for `Self` in a method's borrowed external argument
53    /// (`other: &Self`): the wrapper is a free function.
54    self_type: Option<syn::Type>,
55    /// The R formal of each parameter (#1842): what a conversion condition
56    /// names the argument (see [`Self::with_formals`]).
57    formals: crate::r_wrapper_builder::Formals,
58}
59
60impl RustConversionBuilder {
61    /// Create a new conversion builder, carrying the crate-level
62    /// `conversion_error_class` from the manifest (empty when unset).
63    pub fn new() -> Self {
64        Self {
65            inferred_types: false,
66            coerce_all: false,
67            coerce_params: Vec::new(),
68            strict: false,
69            match_arg_several_ok_params: Vec::new(),
70            layered_choice_params: Vec::new(),
71            no_na_params: Vec::new(),
72            param_markers: Vec::new(),
73            formals: crate::r_wrapper_builder::Formals::default(),
74            conversion_error_class: crate::crate_config::conversion_error_class(),
75            unevaluated_args: false,
76            self_type: None,
77        }
78    }
79
80    pub(crate) fn with_inferred_types(mut self) -> Self {
81        self.inferred_types = true;
82        self
83    }
84
85    /// Name the impl's type for `Self` in borrowed external arguments.
86    pub fn with_self_type(mut self, self_type: syn::Type) -> Self {
87        self.self_type = Some(self_type);
88        self
89    }
90
91    /// The borrowed external argument (`&T` / `&mut T` / a view, #2106)
92    /// `pat_type` declares. A parameter marker's parameter is none: the
93    /// marker rebinds the converted value, which a borrowed argument only
94    /// gets after every conversion.
95    fn external_arg(
96        &self,
97        pat_type: &syn::PatType,
98    ) -> Option<crate::externalptr_args::ExternalArg> {
99        let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() else {
100            return None;
101        };
102        let name = crate::naming::ident_name(&pat_ident.ident);
103        if self.param_markers.iter().any(|(n, _)| *n == name) {
104            return None;
105        }
106        crate::externalptr_args::external_arg(&pat_type.ty)
107    }
108
109    /// Bind `Quoted` / `Quosure` parameters (#1835): set for standalone fns,
110    /// whose R wrapper passes those arguments unevaluated
111    /// (`r_wrapper_builder::RArgumentBuilder::build_call_args_vec`). Without
112    /// it such a parameter is a compile error.
113    pub fn with_unevaluated_args(mut self) -> Self {
114        self.unevaluated_args = true;
115        self
116    }
117
118    /// Override the crate-level conversion-error classes (the manifest's
119    /// `conversion_error_class` is read by [`Self::new`]).
120    #[cfg(test)]
121    pub fn with_conversion_error_class(mut self, classes: Vec<String>) -> Self {
122        self.conversion_error_class = classes;
123        self
124    }
125
126    /// Enable coercion for all parameters.
127    pub fn with_coerce_all(mut self) -> Self {
128        self.coerce_all = true;
129        self
130    }
131
132    /// Add a single parameter name that should use coercion.
133    ///
134    /// `param_name` is matched against the identifier in the function signature.
135    /// Can be called multiple times to add several parameters.
136    pub fn with_coerce_param(mut self, param_name: String) -> Self {
137        self.coerce_params.push(param_name);
138        self
139    }
140
141    /// Enable strict input conversion for lossy types (i64/u64/isize/usize + Vec variants).
142    pub fn with_strict(mut self) -> Self {
143        self.strict = true;
144        self
145    }
146
147    /// Mark a parameter as `match_arg + several_ok` — uses `match_arg_vec_from_sexp`
148    /// instead of `TryFromSexp` for converting STRSXP → `Vec<EnumType>`.
149    pub fn with_match_arg_several_ok(mut self, param_name: String) -> Self {
150        self.match_arg_several_ok_params.push(param_name);
151        self
152    }
153
154    /// Mark a choice parameter whose type wraps the choice in `Missing` /
155    /// `Option` layers (#1473, #1551): it is decoded layer by layer with the
156    /// `miniextendr_api::match_arg_*` helpers (see [`layered_choice_expr`])
157    /// instead of `TryFromSexp`. There is no `TryFromSexp for Option<T>` a
158    /// downstream crate could provide for its own enum (orphan rule), and a
159    /// `T: MatchArg` blanket would collide with the newtype blanket in
160    /// `miniextendr_api::newtype`, so the wrapper calls the helpers directly.
161    pub fn with_layered_choice(mut self, param_name: String, leaf: ChoiceLeaf) -> Self {
162        self.layered_choice_params.push((param_name, leaf));
163        self
164    }
165
166    /// Mark a `#[miniextendr(no_na)]` parameter (`param_name` is its Rust
167    /// name), with the author's `no_na(message = "...")` if given.
168    ///
169    /// The R guard `!anyNA(x)` runs first; a type can still read an input as
170    /// missing that `anyNA()` does not see (the reading markers `AsNumeric*` /
171    /// `AsCharacter*` read the text `"NA"` or a blank string as `NA`). So when
172    /// the parameter converts through plain `TryFromSexp`, the converted value
173    /// is asked `TryFromSexp::__mx_has_na` right after its binding, and a
174    /// refusal returns the R guard's own condition (see
175    /// [`no_na_value_stmt`]). No type is named: Rust resolves the call on the
176    /// value's real type, so aliases and derived newtypes of a marker are
177    /// checked too, and for any other type the default `false` optimises out.
178    /// The reference arms (`&T`, `&[T]`, `&str`) emit no check and keep only
179    /// the R guard: they convert through the reference type's own impl, and
180    /// no reading marker converts by reference.
181    ///
182    /// An `Either` parameter (also under `Missing`) has no R guard
183    /// (`r_preconditions::no_na_checked_after_conversion`). Its value is asked
184    /// `TryFromSexp::__mx_input_has_na` with the input SEXP instead: the arm
185    /// the value converted to makes the guard's `anyNA()` check on the input
186    /// in Rust, then its own `__mx_has_na`, and a `DataFrame` arm refuses
187    /// nothing (also behind a derived newtype or `Result<_, ()>`, which
188    /// forward the call).
189    pub fn with_no_na(mut self, param_name: String, message: Option<String>) -> Self {
190        self.no_na_params.push((param_name, message));
191        self
192    }
193
194    /// Name each argument by its R formal (#1842) in its conversion
195    /// condition: the message's `'<p>'` and `e$param`. Without a declared
196    /// formal, the Rust name without leading underscores.
197    pub fn with_formals(mut self, formals: crate::r_wrapper_builder::Formals) -> Self {
198        self.formals = formals;
199        self
200    }
201
202    /// Mark a parameter (`param_name` is its Rust name) whose declared type
203    /// wraps the one it converts as in parameter markers (`Checked<T>` /
204    /// `Unchecked<T>`, #1566), outermost first. The `pat_type` this builder
205    /// sees holds the inner type, so the conversion and its failure context
206    /// (`e$rust_type`) are the inner type's; after the parameter's last
207    /// statement (the borrow on the split worker path, else the conversion or
208    /// its `no_na` check) the value is rebound through each marker's
209    /// `from_inner`, innermost first, so the call receives the declared type.
210    pub fn with_param_markers(
211        mut self,
212        param_name: String,
213        markers: Vec<crate::type_inspect::ParamMarker>,
214    ) -> Self {
215        self.param_markers.push((param_name, markers));
216        self
217    }
218
219    /// The rebinding of a marked parameter's converted value (see
220    /// [`Self::with_param_markers`]), or `None` for an unmarked parameter.
221    fn marker_rebind(&self, pat_type: &syn::PatType) -> Option<TokenStream> {
222        let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() else {
223            return None;
224        };
225        let ident = &pat_ident.ident;
226        let name = crate::naming::ident_name(ident);
227        let (_, markers) = self.param_markers.iter().find(|(n, _)| *n == name)?;
228        let span = pat_type.ty.span();
229        let rebinds = markers.iter().rev().map(|marker| {
230            let ctor = marker.ctor_path();
231            {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ctor, &mut _s);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_inner");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&ident, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=> let #ident = #ctor::from_inner(#ident); }
232        });
233        Some({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut rebinds, i) = rebinds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let rebinds =
                match rebinds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&rebinds, &mut _s);
        }
    }
    _s
}quote! { #(#rebinds)* })
234    }
235
236    /// Check if a parameter should use coercion.
237    ///
238    /// Returns `true` if `coerce_all` is set or `param_name` appears in the per-parameter list.
239    fn should_coerce(&self, param_name: &str) -> bool {
240        self.coerce_all || self.coerce_params.contains(&param_name.to_string())
241    }
242
243    /// Describe only the conversion actually used for this argument.
244    ///
245    /// Special paths can have no TryFromSexp impl for the declared type. Omit
246    /// their metadata queries at codegen time; a runtime branch still typechecks.
247    pub(crate) fn native_borrow_metadata(
248        &self,
249        pat_type: &syn::PatType,
250        sexp_ident: &syn::Ident,
251    ) -> Option<TokenStream> {
252        let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() else {
253            return None;
254        };
255        let ty = pat_type.ty.as_ref();
256        if crate::type_inspect::call_marker(ty).is_some()
257            || crate::type_inspect::unevaluated_param(ty).is_some()
258            || crate::type_inspect::is_lazy_dots_marker(ty)
259            || self.external_arg(pat_type).is_some()
260        {
261            return None;
262        }
263        // Character borrows never alias native numeric storage. In particular,
264        // do not instantiate Vec<&'a str>'s raw, static-only TryFromSexp impl
265        // merely to ask for its empty metadata: worker storage is owned.
266        if worker_string_storage(ty, sexp_ident).is_some() {
267            return None;
268        }
269        if crate::type_inspect::is_rooted_view(ty) {
270            return Some(self.borrow_metadata_for(ty, &pat_ident.ident, true));
271        }
272        let param_name = crate::naming::ident_name(&pat_ident.ident);
273        match ty {
274            syn::Type::ImplTrait(_) => return None,
275            syn::Type::Tuple(t) if t.elems.is_empty() => return None,
276            syn::Type::Reference(r) => {
277                if let syn::Type::Path(tp) = r.elem.as_ref()
278                    && (tp.path.is_ident("str")
279                        || tp
280                            .path
281                            .segments
282                            .last()
283                            .is_some_and(|seg| seg.ident == "Dots"))
284                {
285                    return None;
286                }
287                if self.match_arg_several_ok_params.contains(&param_name)
288                    && crate::classify_several_ok_container(ty).is_some()
289                {
290                    return None;
291                }
292            }
293            _ => {
294                if self.strict
295                    && crate::return_type_analysis::strict_input_conversion_for_type(ty, sexp_ident)
296                        .is_some()
297                {
298                    return None;
299                }
300                if self
301                    .layered_choice_params
302                    .iter()
303                    .any(|(name, _)| *name == param_name)
304                {
305                    return None;
306                }
307                if self.match_arg_several_ok_params.contains(&param_name)
308                    && crate::classify_several_ok_container(ty).is_some()
309                {
310                    return None;
311                }
312                // Numeric delegates to TryFromSexp, so retain that converter's metadata.
313                if self.should_coerce(&param_name)
314                    && let Some(mapping) = CoercionMapping::from_type(ty)
315                    && !#[allow(non_exhaustive_omitted_patterns)] match mapping {
    CoercionMapping::Numeric => true,
    _ => false,
}matches!(mapping, CoercionMapping::Numeric)
316                {
317                    return None;
318                }
319            }
320        }
321        Some(self.borrow_metadata_for(
322            ty,
323            &pat_ident.ident,
324            crate::type_inspect::is_rooted_reference(ty),
325        ))
326    }
327
328    fn borrow_metadata_for(&self, ty: &syn::Type, name: &syn::Ident, rooted: bool) -> TokenStream {
329        if self.inferred_types {
330            let target = crate::trait_signature::argument_ident(name);
331            if rooted {
332                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&target, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "rooted_native_borrow");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    _s
}quote! { #target.rooted_native_borrow() }
333            } else {
334                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&target, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "native_borrow");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    _s
}quote! { #target.native_borrow() }
335            }
336        } else {
337            let ty = crate::type_inspect::erase_lifetimes(ty);
338            if rooted {
339                {
    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, "TryFromRoot");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'_");
    ::quote::__private::push_shr(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "NATIVE_BORROW");
    _s
}quote! { <#ty as ::miniextendr_api::TryFromRoot<'_>>::NATIVE_BORROW }
340            } else {
341                {
    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, "NATIVE_BORROW");
    _s
}quote! { <#ty as ::miniextendr_api::TryFromSexp>::NATIVE_BORROW }
342            }
343        }
344    }
345
346    /// The binding of a `Quoted` / `Quosure` parameter (#1835) from the
347    /// argument its R wrapper passed: the capture, or the missing-argument
348    /// sentinel. `Missing<..>` reads the sentinel as `Missing::Absent`; a bare
349    /// marker returns R's own error for a missing argument as a conversion
350    /// condition naming the parameter (`e$param`). The marker borrows the
351    /// argument SEXP (rooted by `.Call()` for the call), so it cannot outlive
352    /// the call.
353    fn unevaluated_binding(
354        &self,
355        ident: &syn::Ident,
356        sexp_ident: &syn::Ident,
357        r_name: &str,
358        ty: &syn::Type,
359        param: crate::type_inspect::UnevaluatedParam,
360    ) -> TokenStream {
361        let span = ty.span();
362        let marker = param.kind.api_path();
363        let bound_ty = crate::type_inspect::erase_lifetimes(ty);
364        if !self.unevaluated_args {
365            let message = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` parameters are supported on standalone `#[miniextendr]` functions only (standalone S3 methods included); a class or trait method\'s wrapper cannot pass an argument unevaluated",
                param.kind.name()))
    })format!(
366                "`{}` parameters are supported on standalone `#[miniextendr]` functions only \
367                 (standalone S3 methods included); a class or trait method's wrapper cannot \
368                 pass an argument unevaluated",
369                param.kind.name()
370            );
371            // The binding keeps the method's own use of the parameter from
372            // adding a follow-on "cannot find value" to the diagnostic.
373            let binding = if param.optional {
374                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&marker, &mut _s);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "missing_from_wrapper_arg");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote_spanned! {span=> unsafe { #marker::missing_from_wrapper_arg(&#sexp_ident) } }
375            } else {
376                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&marker, &mut _s);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "from_wrapper_arg");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Some");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "None");
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "panic");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::TokenStream::new()
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {span=>
377                    match unsafe { #marker::from_wrapper_arg(&#sexp_ident) } {
378                        ::core::option::Option::Some(v) => v,
379                        ::core::option::Option::None => ::core::panic!(),
380                    }
381                }
382            };
383            return {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "compile_error");
    ::quote::__private::push_bang_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&message, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&binding, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
384                ::core::compile_error!(#message);
385                let #ident: #bound_ty = #binding;
386            };
387        }
388        if param.optional {
389            // SAFETY (of the emitted `unsafe`): on the R main thread inside the
390            // wrapper's with_r_unwind_protect closure; `.Call()` roots the
391            // argument for the call.
392            return {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&marker, &mut _s);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "missing_from_wrapper_arg");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
393                let #ident: #bound_ty = unsafe { #marker::missing_from_wrapper_arg(&#sexp_ident) };
394            };
395        }
396        let message = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("argument \"{0}\" is missing, with no default",
                r_name))
    })format!("argument \"{r_name}\" is missing, with no default");
397        let crate_class = &self.conversion_error_class;
398        let call = crate::naming::call_slot_ident();
399        // SAFETY (of the emitted `unsafe`): as above; the `None` arm returns
400        // the tagged condition from inside the wrapper's closure, like a
401        // conversion `Err` arm.
402        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&marker, &mut _s);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "from_wrapper_arg");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Some");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "None");
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "return");
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "unsafe");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "miniextendr_api");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "error_value");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "arg_check_condition_value");
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    let _span: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    ::quote::ToTokens::to_tokens(&message, &mut _s);
                                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                                    ::quote::ToTokens::to_tokens(&r_name, &mut _s);
                                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                                    ::quote::__private::push_and_spanned(&mut _s, _span);
                                    ::quote::__private::push_group_spanned(&mut _s, _span,
                                        ::quote::__private::Delimiter::Bracket,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            let _span: ::quote::__private::Span =
                                                ::quote::__private::get_span(_span).__into_span();
                                            {
                                                use ::quote::__private::ext::*;
                                                let mut _first = true;
                                                let has_iter = ::quote::__private::HasIterator::<false>;
                                                #[allow(unused_mut)]
                                                let (mut crate_class, i) = crate_class.quote_into_iter();
                                                let has_iter = has_iter | i;
                                                <_ as
                                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                                while true {
                                                    let crate_class =
                                                        match crate_class.next() {
                                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                                            None => break,
                                                        };
                                                    if !_first {
                                                        ::quote::__private::push_comma_spanned(&mut _s, _span);
                                                    }
                                                    _first = false;
                                                    ::quote::ToTokens::to_tokens(&crate_class, &mut _s);
                                                }
                                            }
                                            _s
                                        });
                                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                                        "core");
                                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                                        "option");
                                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                                        "Option");
                                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                                        "Some");
                                    ::quote::__private::push_group_spanned(&mut _s, _span,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            let _: ::quote::__private::Span =
                                                ::quote::__private::get_span(_span).__into_span();
                                            ::quote::ToTokens::to_tokens(&call, &mut _s);
                                            _s
                                        });
                                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                                    _s
                                });
                            _s
                        });
                    ::quote::__private::push_semi_spanned(&mut _s, _span);
                    _s
                });
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
403            let #ident: #bound_ty = match unsafe { #marker::from_wrapper_arg(&#sexp_ident) } {
404                ::core::option::Option::Some(v) => v,
405                ::core::option::Option::None => {
406                    return unsafe {
407                        ::miniextendr_api::error_value::arg_check_condition_value(
408                            #message,
409                            #r_name,
410                            &[#(#crate_class),*],
411                            ::core::option::Option::Some(#call),
412                        )
413                    };
414                }
415            };
416        }
417    }
418
419    /// Generate a conversion expression that returns a tagged condition SEXP on failure.
420    ///
421    /// The R wrapper inspects `.val` and raises a structured `rust_*` condition; the
422    /// `return` happens from inside the C wrapper body before any further conversion.
423    ///
424    /// - `try_expr`: The `Result<T, E>`-producing expression
425    /// - `ctx`: The argument's R-facing failure context ([`ArgContext`]): the
426    ///   message prefix, `e$param` and `e$rust_type`
427    /// - `ident`: The binding name for the converted value
428    /// - `ty`: The target Rust type (for the `let` binding). The annotation is
429    ///   load-bearing: the `Err` arm probes the error type by method call
430    ///   ([`conversion_err_arm`]), which needs that type known at that point.
431    /// - `span`: Source span for error reporting
432    fn conversion_stmt(
433        &self,
434        try_expr: TokenStream,
435        ctx: &ArgContext,
436        ident: &syn::Ident,
437        ty: &syn::Type,
438        span: proc_macro2::Span,
439    ) -> TokenStream {
440        let err_arm = conversion_err_arm(ctx, &self.conversion_error_class, span);
441        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::ToTokens::to_tokens(&try_expr, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Ok");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&err_arm, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
442            let #ident: #ty = match #try_expr {
443                ::core::result::Result::Ok(v) => v,
444                #err_arm
445            };
446        }
447    }
448
449    /// Generate conversion statement for a single parameter.
450    ///
451    /// This is the non-split variant: owned conversions and borrow statements are
452    /// concatenated into a single list, suitable for main-thread execution where
453    /// everything runs in the same scope.
454    ///
455    /// - `pat_type`: the typed pattern from the function signature (e.g., `x: i32`).
456    /// - `sexp_ident`: the identifier of the raw SEXP variable holding the R argument.
457    ///
458    /// Returns a flat list of `let` binding statements that convert `sexp_ident` into
459    /// the Rust type declared in `pat_type`.
460    pub fn build_conversion(
461        &self,
462        pat_type: &syn::PatType,
463        sexp_ident: &syn::Ident,
464    ) -> Vec<TokenStream> {
465        // `build_conversion` is the single-scope (main-thread) path: every statement
466        // runs inside the same `with_r_unwind_protect` closure where the argument
467        // SEXPs are live for the whole call. So `&str` can borrow R's CHARSXP pool
468        // directly — zero-copy — exactly like `&[T]` already does. The owning-`String`
469        // detour only exists to satisfy `Send` when the value must cross the worker
470        // boundary (`build_conversion_split`), which never applies here.
471        let (owned, borrowed) = self.build_conversion_split_inner(pat_type, sexp_ident, true);
472        owned
473            .into_iter()
474            .chain(borrowed)
475            .chain(self.marker_rebind(pat_type))
476            .collect()
477    }
478
479    /// Generate conversion statements split into two phases for worker thread execution.
480    ///
481    /// `&str`, `Option<&str>`, `Vec<&str>` and `Vec<Option<&str>>` first
482    /// convert to the corresponding owned strings on R's main thread. The
483    /// worker closure owns that storage and creates the borrows inside it.
484    /// Other conversions without a separate borrow use only the first vec.
485    ///
486    /// - `pat_type`: the typed pattern from the function signature (e.g., `s: &str`).
487    /// - `sexp_ident`: the identifier of the raw SEXP variable holding the R argument.
488    ///
489    /// Returns `(owned_conversions, borrow_statements)` where each element is a list
490    /// of `let` binding token streams.
491    pub fn build_conversion_split(
492        &self,
493        pat_type: &syn::PatType,
494        sexp_ident: &syn::Ident,
495    ) -> (Vec<TokenStream>, Vec<TokenStream>) {
496        // Rust considers &str Send, but that does not give it ownership of an
497        // R CHARSXP. Copy character borrows before moving them to the worker.
498        let (mut owned, mut borrowed) =
499            self.build_conversion_split_inner(pat_type, sexp_ident, false);
500        // A marker wraps the parameter's final binding: the borrow inside the
501        // worker closure when there is one, else the owned value, which then
502        // moves into the closure as the declared type.
503        if let Some(rebind) = self.marker_rebind(pat_type) {
504            if borrowed.is_empty() {
505                owned.push(rebind);
506            } else {
507                borrowed.push(rebind);
508            }
509        }
510        (owned, borrowed)
511    }
512
513    /// Inner implementation of [`Self::build_conversion_split`].
514    ///
515    /// `root_shared_inputs` selects the main-thread shared-borrow path:
516    /// - `true` (main-thread, single-scope): emit a direct zero-copy `&str` borrow
517    ///   over R's CHARSXP pool via `TryFromRoot` — no `String` allocation.
518    ///   Shared native references use the same root-bound path; its lifetime
519    ///   prevents the result from escaping the call as a static reference.
520    /// - `false` (worker): convert borrowed strings, including optional and
521    ///   vector forms, to owned storage on main; borrow only inside the worker.
522    fn build_conversion_split_inner(
523        &self,
524        pat_type: &syn::PatType,
525        sexp_ident: &syn::Ident,
526        root_shared_inputs: bool,
527    ) -> (Vec<TokenStream>, Vec<TokenStream>) {
528        let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() else {
529            return (::alloc::vec::Vec::new()vec![], ::alloc::vec::Vec::new()vec![]);
530        };
531        let ident = &pat_ident.ident;
532        // `r#`-free spelling for synthesized bindings (`__storage_where`).
533        let plain = crate::naming::unraw(ident);
534        // These temporaries survive other argument conversions (and, for
535        // worker borrows, cross into another closure). Source parameters may
536        // use the same spelling, so keep every temporary hygienic.
537        let binding_span = proc_macro2::Span::mixed_site();
538        let ty = pat_type.ty.as_ref();
539        // The R formal's name (`_x` → `x`, `r#type` → `type`, a declared
540        // `formal`, #1842): what a conversion condition names in its message
541        // and in `e$param`.
542        let r_name = self.formals.of_ident(ident);
543        // What a conversion failure of this argument says (#1591): the R-facing
544        // expectation (coerce-widened like the R-side check), `e$param` and
545        // `e$rust_type`.
546        let ctx = ArgContext::new(
547            &r_name,
548            ty,
549            self.should_coerce(&crate::naming::ident_name(ident)),
550        );
551
552        // A `Call` / `CallerCall` marker (#1566) never reaches this builder from
553        // a standalone fn: `lib.rs` removes it from the inputs and binds it from
554        // the call slot at the call site. Seeing one here means a class or trait
555        // method took it, where the wrapper's own call is the only attribution.
556        if crate::type_inspect::call_marker(ty).is_some() {
557            let span = ty.span();
558            let call = crate::naming::call_slot_ident();
559            // The binding keeps the method's own use of the parameter from adding
560            // a follow-on "cannot find value" to the diagnostic; the wrapper's call
561            // slot is in scope in every C wrapper, so it also type-checks.
562            let stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "compile_error");
    ::quote::__private::push_bang_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::parse_spanned(&mut _s, _span,
                "\"`Call` / `CallerCall` parameters are supported on standalone `#[miniextendr]` \\\n                     functions only; class and trait methods attribute conditions to the wrapper\'s own call\"");
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_sexp");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&call, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
563                ::core::compile_error!(
564                    "`Call` / `CallerCall` parameters are supported on standalone `#[miniextendr]` \
565                     functions only; class and trait methods attribute conditions to the wrapper's own call"
566                );
567                let #ident: #ty = <#ty>::from_sexp(#call);
568            };
569            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
570        }
571
572        // A borrowed external argument (#2106) converts to its handle here;
573        // the C wrapper borrows it after every conversion
574        // (`externalptr_args::arg_borrows`).
575        if let Some(external) = self.external_arg(pat_type) {
576            let err_arm = conversion_err_arm(&ctx, &self.conversion_error_class, ty.span());
577            let stmt = crate::externalptr_args::handle_conversion(
578                ident,
579                sexp_ident,
580                ty,
581                &external,
582                self.self_type.as_ref(),
583                err_arm,
584            );
585            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
586        }
587
588        // A copied trait signature (#2123) may name a type that resolves only
589        // in the declaration's module: its plain conversions take their type
590        // from the witness inferred from the concrete method instead.
591        let target = self
592            .inferred_types
593            .then(|| crate::trait_signature::argument_ident(ident));
594
595        let param_name = crate::naming::ident_name(ident);
596        let layered_choice = self
597            .layered_choice_params
598            .iter()
599            .find(|(name, _)| *name == param_name)
600            .map(|(_, leaf)| leaf);
601        let rooted_reference = root_shared_inputs
602            && crate::type_inspect::is_rooted_reference(ty)
603            && !self.match_arg_several_ok_params.contains(&param_name)
604            && layered_choice.is_none();
605        if crate::type_inspect::is_rooted_view(ty) || rooted_reference {
606            if let Some(stmt) = crate::type_inspect::static_rooted_view_binding(ident, ty) {
607                return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
608            }
609            let span = ty.span();
610            let roots = match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__mx_roots_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__mx_roots_{}", plain, span = binding_span);
611            // The call roots its argument. The scope also retains any transient
612            // children returned by an ALTREP accessor during conversion.
613            let root = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&roots, &mut _s);
            ::quote::__private::push_dot_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "rooted");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote_spanned! {span=> unsafe { #roots.rooted(#sexp_ident) } };
614            let (try_expr, bound_ty): (_, syn::Type) = match &target {
615                Some(target) => (
616                    {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::ToTokens::to_tokens(&target, &mut _s);
    ::quote::__private::push_dot_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "rooted");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&root, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=> #target.rooted(#root) },
617                    ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_underscore(&mut _s);
        _s
    })syn::parse_quote!(_),
618                ),
619                None => {
620                    let bound_ty = crate::type_inspect::erase_lifetimes(ty);
621                    (
622                        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "as");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromRoot");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::__private::push_lifetime_spanned(&mut _s, _span, "\'_");
    ::quote::__private::push_shr_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "try_from_root");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&root, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
623                            <#bound_ty as ::miniextendr_api::TryFromRoot<'_>>::try_from_root(#root)
624                        },
625                        bound_ty,
626                    )
627                }
628            };
629            let stmt = self.conversion_stmt(try_expr, &ctx, ident, &bound_ty, span);
630            return (
631                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [{
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::ToTokens::to_tokens(&roots, &mut _s);
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "unsafe");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "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());
                            _s
                        });
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::ToTokens::to_tokens(&stmt, &mut _s);
                    _s
                }]))vec![quote! {
632                    let #roots = unsafe { ::miniextendr_api::gc_protect::ProtectScope::new() };
633                    #stmt
634                }],
635                ::alloc::vec::Vec::new()vec![],
636            );
637        }
638
639        // Main-thread &str normally returned above. Its existing special
640        // choice path also uses owned storage; keep that fallback here.
641        let owned_ident = match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__owned_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__owned_{}", plain, span = binding_span);
642        if (!root_shared_inputs || #[allow(non_exhaustive_omitted_patterns)] match ty {
    syn::Type::Reference(_) => true,
    _ => false,
}matches!(ty, syn::Type::Reference(_)))
643            && !self.match_arg_several_ok_params.contains(&param_name)
644            && let Some((owned_ty, borrow_expr)) = worker_string_storage(ty, &owned_ident)
645        {
646            // The borrow is of a local copy, so it can't be `'static` either.
647            if let Some(stmt) = crate::type_inspect::static_rooted_view_binding(ident, ty) {
648                return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
649            }
650            let span = ty.span();
651            // Preserve the existing decoder for a string with choices, but
652            // decode into owned storage. Diagnostics keep the author's type.
653            let try_expr = if let Some(leaf) = layered_choice {
654                layered_choice_expr(&owned_ty, leaf.clone(), sexp_ident, span)
655            } else {
656                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromSexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "try_from_sexp");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
657                    ::miniextendr_api::TryFromSexp::try_from_sexp(#sexp_ident)
658                }
659            };
660            let owned_stmt = self.conversion_stmt(try_expr, &ctx, &owned_ident, &owned_ty, span);
661            let bound_ty = crate::type_inspect::erase_lifetimes(ty);
662            let borrow_stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&borrow_expr, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
663                let #ident: #bound_ty = #borrow_expr;
664            };
665            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [owned_stmt]))vec![owned_stmt], ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [borrow_stmt]))vec![borrow_stmt]);
666        }
667
668        if !root_shared_inputs
669            && !self.match_arg_several_ok_params.contains(&param_name)
670            && let Some((owned_ty, copy, borrow)) = worker_native_storage(ty, &owned_ident)
671        {
672            if let Some(stmt) = crate::type_inspect::static_rooted_view_binding(ident, ty) {
673                return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
674            }
675            let span = ty.span();
676            let bound_ty = crate::type_inspect::erase_lifetimes(ty);
677            // Check the borrowed representation before copying: scalar inputs
678            // still require exactly one element, and optional NULLs stay None.
679            let roots = match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__mx_roots_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__mx_roots_{}", plain, span = binding_span);
680            let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
            ::quote::ToTokens::to_tokens(&roots, &mut _s);
            ::quote::__private::push_eq_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "gc_protect");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "ProtectScope");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "new");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let _: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::TokenStream::new()
                        });
                    _s
                });
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "map");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_lt_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "as");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "TryFromRoot");
                    ::quote::__private::push_lt_spanned(&mut _s, _span);
                    ::quote::__private::push_lifetime_spanned(&mut _s, _span,
                        "\'_");
                    ::quote::__private::push_shr_spanned(&mut _s, _span);
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "try_from_root");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "unsafe");
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    let _span: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    ::quote::ToTokens::to_tokens(&roots, &mut _s);
                                    ::quote::__private::push_dot_spanned(&mut _s, _span);
                                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                                        "rooted");
                                    ::quote::__private::push_group_spanned(&mut _s, _span,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            let _: ::quote::__private::Span =
                                                ::quote::__private::get_span(_span).__into_span();
                                            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                                            _s
                                        });
                                    _s
                                });
                            _s
                        });
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&copy, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    _s
                });
            _s
        });
    _s
}quote_spanned! {span=> {
681                let #roots = unsafe { ::miniextendr_api::gc_protect::ProtectScope::new() };
682                ::core::result::Result::map(
683                    <#bound_ty as ::miniextendr_api::TryFromRoot<'_>>::try_from_root(unsafe {
684                        #roots.rooted(#sexp_ident)
685                    }),
686                    #copy,
687                )
688            }};
689            let owned_stmt = self.conversion_stmt(try_expr, &ctx, &owned_ident, &owned_ty, span);
690            let borrow_stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&borrow, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
691                let #ident: #bound_ty = #borrow;
692            };
693            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [owned_stmt]))vec![owned_stmt], ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [borrow_stmt]))vec![borrow_stmt]);
694        }
695
696        // `LazyDots` (#1892): the R wrapper passes its own frame,
697        // `environment()`, at the position of `...`; the marker reads the
698        // dots from it and never goes through `TryFromSexp`. Bound in every
699        // context: each promise carries its own environment, so the frame of
700        // a class method's wrapper serves as well as a standalone function's.
701        if crate::type_inspect::is_lazy_dots_marker(ty) {
702            let span = ty.span();
703            let bound_ty = crate::type_inspect::erase_lifetimes(ty);
704            // SAFETY (of the emitted `unsafe`): on the R main thread inside the
705            // wrapper's with_r_unwind_protect closure; `.Call()` roots the
706            // frame for the call, and the marker borrows the argument.
707            let stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&bound_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "LazyDots");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "from_wrapper_arg");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
708                let #ident: #bound_ty =
709                    unsafe { ::miniextendr_api::LazyDots::from_wrapper_arg(&#sexp_ident) };
710            };
711            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
712        }
713
714        // `Quoted` / `Quosure` (#1835): the R wrapper passes the argument
715        // unevaluated, behind the missing-argument sentinel; it never goes
716        // through `TryFromSexp`.
717        if let Some(param) = crate::type_inspect::unevaluated_param(ty) {
718            return (
719                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.unevaluated_binding(ident, sexp_ident, &r_name, ty, param)]))vec![self.unevaluated_binding(ident, sexp_ident, &r_name, ty, param)],
720                ::alloc::vec::Vec::new()vec![],
721            );
722        }
723
724        match ty {
725            // Unit type: ()
726            // Note: We never generate `mut` on conversion bindings - the user's function
727            // has its own parameter binding that will be `mut` if they specified it.
728            syn::Type::Tuple(t) if t.elems.is_empty() => {
729                let stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! { let #ident = (); };
730                (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![])
731            }
732
733            // Reference types: &T, &mut T
734            syn::Type::Reference(r) => {
735                let param_name = crate::naming::ident_name(ident);
736                let is_dots = #[allow(non_exhaustive_omitted_patterns)] match r.elem.as_ref() {
    syn::Type::Path(tp) if
        tp.path.segments.last().map(|s| s.ident == "Dots").unwrap_or(false) =>
        true,
    _ => false,
}matches!(
737                    r.elem.as_ref(),
738                    syn::Type::Path(tp)
739                        if tp.path.segments.last()
740                            .map(|s| s.ident == "Dots")
741                            .unwrap_or(false)
742                );
743                let is_slice = #[allow(non_exhaustive_omitted_patterns)] match r.elem.as_ref() {
    syn::Type::Slice(_) => true,
    _ => false,
}matches!(r.elem.as_ref(), syn::Type::Slice(_));
744
745                // &[T] / &mut [T] with match_arg + several_ok:
746                // two-phase: pre-call Vec<T>, in-call borrow
747                if is_slice
748                    && self
749                        .match_arg_several_ok_params
750                        .contains(&param_name.to_string())
751                    && let Some((crate::SeveralOkContainer::BorrowedSlice, inner_ty)) =
752                        crate::classify_several_ok_container(ty)
753                {
754                    let is_mut = r.mutability.is_some();
755                    let storage_ident =
756                        match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__storage_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__storage_{}", plain, span = binding_span);
757                    let vec_ty: syn::Type = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<#inner_ty>);
758                    let span = ty.span();
759                    let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
760                        ::miniextendr_api::match_arg_vec_from_sexp::<#inner_ty>(#sexp_ident)
761                    };
762                    // Emit owned Vec<T> binding.
763                    // For &mut [T] the storage binding needs `mut`.
764                    let owned_stmt = if is_mut {
765                        // Need `let mut storage_ident: vec_ty = ...`; inline the mut variant.
766                        let err_arm = conversion_err_arm(&ctx, &self.conversion_error_class, span);
767                        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "mut");
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&vec_ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::ToTokens::to_tokens(&try_expr, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Ok");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&err_arm, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
768                            let mut #storage_ident: #vec_ty = match #try_expr {
769                                ::core::result::Result::Ok(v) => v,
770                                #err_arm
771                            };
772                        }
773                    } else {
774                        self.conversion_stmt(try_expr, &ctx, &storage_ident, &vec_ty, span)
775                    };
776                    let borrow_stmt = if is_mut {
777                        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_and_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "mut");
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
778                            let #ident: #ty = &mut #storage_ident;
779                        }
780                    } else {
781                        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_and_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
782                            let #ident: #ty = &#storage_ident;
783                        }
784                    };
785                    return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [owned_stmt]))vec![owned_stmt], ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [borrow_stmt]))vec![borrow_stmt]);
786                }
787
788                if is_dots {
789                    // &Dots: create wrapper with storage (main thread only - requires SEXP)
790                    let storage_ident =
791                        match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}_storage", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("{}_storage", plain, span = binding_span);
792                    let stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dots");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Dots");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "inner");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_and(&mut _s);
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
793                        let #storage_ident = ::miniextendr_api::dots::Dots { inner: #sexp_ident };
794                        let #ident = &#storage_ident;
795                    };
796                    (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![])
797                } else if is_slice {
798                    // Worker shared slices and mutable slices still use TryFromSexp.
799                    // Annotate the binding with the lifetime-erased type
800                    // (`&'a [T]` → `&'_ [T]`):
801                    // the user's lifetime need not be in scope, and the `Err` arm's
802                    // probe needs the error type named.
803                    let span = ty.span();
804                    let (try_expr, binding_ty) = try_from_sexp(
805                        target.as_ref(),
806                        sexp_ident,
807                        crate::type_inspect::erase_lifetimes(ty),
808                        span,
809                    );
810                    let stmt = self.conversion_stmt(try_expr, &ctx, ident, &binding_ty, span);
811                    (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![])
812                } else {
813                    // &T for other types: use TryFromSexp for the reference type.
814                    let span = ty.span();
815                    let (try_expr, binding_ty) =
816                        try_from_sexp(target.as_ref(), sexp_ident, ty.clone(), span);
817                    let stmt = self.conversion_stmt(try_expr, &ctx, ident, &binding_ty, span);
818                    (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![])
819                }
820            }
821
822            // All other types
823            _ => {
824                let param_name = crate::naming::ident_name(ident);
825
826                // Strict mode: use checked input helpers for lossy types. A
827                // rejected input is the same argument error as any other
828                // conversion failure (#1594), worded against what strict
829                // accepts (`a single whole number`).
830                if self.strict
831                    && let Some(strict_expr) =
832                        crate::return_type_analysis::strict_input_conversion_for_type(
833                            ty, sexp_ident,
834                        )
835                {
836                    let span = ty.span();
837                    let strict_ctx = ArgContext::strict(&r_name, ty);
838                    let stmt = self.conversion_stmt(strict_expr, &strict_ctx, ident, ty, span);
839                    return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
840                }
841
842                // A choice under `Missing` / `Option` / `Either` layers (#1473,
843                // #1551): decoded layer by layer, outermost first. Under an
844                // `Either<.., R>` layer, a value `R` refuses is reported against
845                // the whole parameter, in the words of its `@param` line, and an
846                // `R` that reads only character input is a compile error.
847                if let Some((_, leaf)) = self
848                    .layered_choice_params
849                    .iter()
850                    .find(|(name, _)| *name == param_name)
851                {
852                    let span = ty.span();
853                    let try_expr = layered_choice_expr(ty, leaf.clone(), sexp_ident, span);
854                    let choice_ctx = ArgContext::either_choice(&r_name, ty, leaf);
855                    let stmt = self.conversion_stmt(
856                        try_expr,
857                        choice_ctx.as_ref().unwrap_or(&ctx),
858                        ident,
859                        ty,
860                        span,
861                    );
862                    let mut stmts = either_arm_guards(&param_name, ty);
863                    stmts.push(stmt);
864                    return (stmts, ::alloc::vec::Vec::new()vec![]);
865                }
866
867                // match_arg + several_ok: use match_arg_vec_from_sexp for container types
868                if self
869                    .match_arg_several_ok_params
870                    .contains(&param_name.to_string())
871                    && let Some((container, inner_ty)) = crate::classify_several_ok_container(ty)
872                {
873                    let span = ty.span();
874                    match container {
875                        crate::SeveralOkContainer::Vec => {
876                            let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
877                                ::miniextendr_api::match_arg_vec_from_sexp::<#inner_ty>(#sexp_ident)
878                            };
879                            let stmt = self.conversion_stmt(try_expr, &ctx, ident, ty, span);
880                            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
881                        }
882                        crate::SeveralOkContainer::BoxedSlice => {
883                            let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    ::quote::__private::push_dot_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "map");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_or_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_or_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_dot_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "into_boxed_slice");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::TokenStream::new()
                });
            _s
        });
    _s
}quote_spanned! {span=>
884                                ::miniextendr_api::match_arg_vec_from_sexp::<#inner_ty>(#sexp_ident)
885                                    .map(|v| v.into_boxed_slice())
886                            };
887                            let stmt = self.conversion_stmt(try_expr, &ctx, ident, ty, span);
888                            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![]);
889                        }
890                        crate::SeveralOkContainer::Array(n) => {
891                            let span = ty.span();
892                            // First extract the Vec via match_arg_vec_from_sexp (handles
893                            // match_arg validation + error reporting), then the array
894                            // conversion, whose only failure is the selection length:
895                            // an argument error like any other (#1591).
896                            let vec_ty: syn::Type = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<#inner_ty>);
897                            let vec_ident =
898                                match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__vec_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__vec_{}", plain, span = binding_span);
899                            let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
900                                ::miniextendr_api::match_arg_vec_from_sexp::<#inner_ty>(#sexp_ident)
901                            };
902                            let vec_stmt =
903                                self.conversion_stmt(try_expr, &ctx, &vec_ident, &vec_ty, span);
904                            let len_ctx = ArgContext {
905                                prefix: ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}\' must be of length {1}",
                r_name, n))
    })format!("'{r_name}' must be of length {n}"),
906                                expected_known: true,
907                                ..ctx.clone()
908                            };
909                            let len_arm =
910                                conversion_err_arm(&len_ctx, &self.conversion_error_class, span);
911                            let arr_stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&n, &mut _s);
            _s
        });
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "try_from");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&vec_ident, &mut _s);
            _s
        });
    ::quote::__private::push_dot_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "map_err");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_or_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_or_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "std");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "format");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::parse_spanned(&mut _s, _span,
                        "\"got length {}\"");
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    ::quote::__private::push_dot_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "len");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let _: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::TokenStream::new()
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Result");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Ok");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&len_arm, &mut _s);
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
912                                let #ident: #ty = match <[#inner_ty; #n]>::try_from(#vec_ident)
913                                    .map_err(|v| ::std::format!("got length {}", v.len()))
914                                {
915                                    ::core::result::Result::Ok(v) => v,
916                                    #len_arm
917                                };
918                            };
919                            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [vec_stmt, arr_stmt]))vec![vec_stmt, arr_stmt], ::alloc::vec::Vec::new()vec![]);
920                        }
921                        crate::SeveralOkContainer::BorrowedSlice => {
922                            let storage_ident =
923                                match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__storage_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!("__storage_{}", plain, span = binding_span);
924                            let vec_ty: syn::Type = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<#inner_ty>);
925                            let try_expr = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
926                                ::miniextendr_api::match_arg_vec_from_sexp::<#inner_ty>(#sexp_ident)
927                            };
928                            let owned_stmt =
929                                self.conversion_stmt(try_expr, &ctx, &storage_ident, &vec_ty, span);
930                            let borrow_stmt = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::__private::push_and_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&storage_ident, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
931                                let #ident: #ty = &#storage_ident;
932                            };
933                            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [owned_stmt]))vec![owned_stmt], ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [borrow_stmt]))vec![borrow_stmt]);
934                        }
935                    }
936                }
937
938                let should_coerce = self.should_coerce(&param_name);
939                let coercion_mapping = if should_coerce {
940                    CoercionMapping::from_type(ty)
941                } else {
942                    None
943                };
944
945                let span = ty.span();
946                let stmt = match coercion_mapping {
947                    Some(mapping) => {
948                        let try_expr = match mapping {
949                            CoercionMapping::Numeric => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromSexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "try_from_sexp");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
950                                ::miniextendr_api::TryFromSexp::try_from_sexp(#sexp_ident)
951                            },
952                            CoercionMapping::Bool => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_bool");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
953                                ::miniextendr_api::from_r::try_from_sexp_coerced_bool(#sexp_ident)
954                            },
955                            CoercionMapping::BoolVec => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_bool_vec");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
956                                ::miniextendr_api::from_r::try_from_sexp_coerced_bool_vec(#sexp_ident)
957                            },
958                            CoercionMapping::NativeInt => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_i32");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
959                                ::miniextendr_api::from_r::try_from_sexp_coerced_i32(#sexp_ident)
960                            },
961                            CoercionMapping::NativeIntVec => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_i32_vec");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
962                                ::miniextendr_api::from_r::try_from_sexp_coerced_i32_vec(#sexp_ident)
963                            },
964                            CoercionMapping::NativeReal => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_f64");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
965                                ::miniextendr_api::from_r::try_from_sexp_coerced_f64(#sexp_ident)
966                            },
967                            CoercionMapping::NativeRealVec => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "from_r");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "try_from_sexp_coerced_f64_vec");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
968                                ::miniextendr_api::from_r::try_from_sexp_coerced_f64_vec(#sexp_ident)
969                            },
970                        };
971                        self.conversion_stmt(try_expr, &ctx, ident, ty, span)
972                    }
973                    None => {
974                        let (try_expr, binding_ty) =
975                            try_from_sexp(target.as_ref(), sexp_ident, ty.clone(), span);
976                        // `ty: TryFromSexp` here, so a failure can ask the
977                        // type what it declares.
978                        let declared = match &target {
979                            Some(target) => ctx.with_inferred(target),
980                            None => ctx.with_declared(ty),
981                        };
982                        let stmt =
983                            self.conversion_stmt(try_expr, &declared, ident, &binding_ty, span);
984                        // `ty: TryFromSexp` is proven here, so a `no_na`
985                        // parameter's value can be asked after the binding.
986                        // Owned vector: it runs on the main thread, before a
987                        // worker closure, like the conversion's `Err` arm.
988                        if let Some((_, message)) = self
989                            .no_na_params
990                            .iter()
991                            .find(|(name, _)| *name == param_name)
992                        {
993                            let message = crate::r_preconditions::no_na_message(
994                                &r_name,
995                                ty,
996                                message.as_deref(),
997                            );
998                            // An `Either` has no R guard: the arm it converted
999                            // to reads the input instead. The input is bound
1000                            // first, since the conversion binding may shadow
1001                            // it (a C wrapper can keep the parameter's name).
1002                            if crate::r_preconditions::no_na_checked_after_conversion(ty) {
1003                                let input = match ::quote::__private::IdentFragmentAdapter(&plain) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__no_na_input_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(binding_span)),
}quote::format_ident!(
1004                                    "__no_na_input_{}",
1005                                    plain,
1006                                    span = binding_span
1007                                );
1008                                let bind = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::ToTokens::to_tokens(&input, &mut _s);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
1009                                    let #input = #sexp_ident;
1010                                };
1011                                let check = no_na_value_stmt(
1012                                    ident,
1013                                    Some(&input),
1014                                    &r_name,
1015                                    &message,
1016                                    &self.conversion_error_class,
1017                                    span,
1018                                );
1019                                return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [bind, stmt, check]))vec![bind, stmt, check], ::alloc::vec::Vec::new()vec![]);
1020                            }
1021                            let check = no_na_value_stmt(
1022                                ident,
1023                                None,
1024                                &r_name,
1025                                &message,
1026                                &self.conversion_error_class,
1027                                span,
1028                            );
1029                            return (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt, check]))vec![stmt, check], ::alloc::vec::Vec::new()vec![]);
1030                        }
1031                        stmt
1032                    }
1033                };
1034                (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt], ::alloc::vec::Vec::new()vec![])
1035            }
1036        }
1037    }
1038
1039    /// Generate conversion statements for all parameters in a function signature.
1040    ///
1041    /// Iterates over `inputs` (the function's parameter list) paired with `sexp_idents`
1042    /// (the corresponding SEXP variable names), calling [`build_conversion`](Self::build_conversion)
1043    /// for each typed parameter. Receiver parameters (`self`) are silently skipped.
1044    ///
1045    /// Returns a flat list of all conversion statements, in parameter order.
1046    pub fn build_conversions(
1047        &self,
1048        inputs: &syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>,
1049        sexp_idents: &[syn::Ident],
1050    ) -> Vec<TokenStream> {
1051        let mut all_statements = Vec::new();
1052
1053        for (arg, sexp_ident) in inputs.iter().zip(sexp_idents.iter()) {
1054            if let syn::FnArg::Typed(pat_type) = arg {
1055                let statements = self.build_conversion(pat_type, sexp_ident);
1056                all_statements.extend(statements);
1057            }
1058        }
1059
1060        all_statements
1061    }
1062}
1063
1064impl Default for RustConversionBuilder {
1065    fn default() -> Self {
1066        Self::new()
1067    }
1068}
1069
1070/// `TryFromSexp` on `sexp_ident`, and the type its binding names: `ty`, or
1071/// for a copied trait signature (#2123) `_`, with the conversion through the
1072/// witness `target` inferred from the concrete method, so a declaration-local
1073/// type is never spelled in the impl's module.
1074fn try_from_sexp(
1075    target: Option<&syn::Ident>,
1076    sexp_ident: &syn::Ident,
1077    ty: syn::Type,
1078    span: proc_macro2::Span,
1079) -> (TokenStream, syn::Type) {
1080    match target {
1081        Some(target) => (
1082            {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::ToTokens::to_tokens(&target, &mut _s);
    ::quote::__private::push_dot_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "convert");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=> #target.convert(#sexp_ident) },
1083            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_underscore(&mut _s);
        _s
    })syn::parse_quote!(_),
1084        ),
1085        None => (
1086            {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromSexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "try_from_sexp");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&sexp_ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=> ::miniextendr_api::TryFromSexp::try_from_sexp(#sexp_ident) },
1087            ty,
1088        ),
1089    }
1090}
1091
1092// region: layered choice parameters
1093
1094/// Where the innermost value of a layered choice parameter comes from.
1095#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ChoiceLeaf {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::MatchArg =>
                ::core::fmt::Formatter::write_str(f, "MatchArg"),
            Self::MatchArgSeveral =>
                ::core::fmt::Formatter::write_str(f, "MatchArgSeveral"),
            Self::Literal { choices: __self_0, several: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Literal", "choices", __self_0, "several", &__self_1),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ChoiceLeaf {
    #[inline]
    fn clone(&self) -> Self {
        match self {
            Self::MatchArg => ChoiceLeaf::MatchArg,
            Self::MatchArgSeveral => ChoiceLeaf::MatchArgSeveral,
            Self::Literal { choices: __self_0, several: __self_1 } =>
                ChoiceLeaf::Literal {
                    choices: ::core::clone::Clone::clone(__self_0),
                    several: ::core::clone::Clone::clone(__self_1),
                },
        }
    }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ChoiceLeaf { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ChoiceLeaf {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::Literal { choices: __self_0, several: __self_1 },
                    Self::Literal { choices: __arg1_0, several: __arg1_1 }) =>
                    __self_1 == __arg1_1 && __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ChoiceLeaf {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Vec<String>>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq)]
1096pub enum ChoiceLeaf {
1097    /// A scalar `match_arg` type (`T: MatchArg`), decoded with
1098    /// `match_arg_from_sexp::<T>`.
1099    MatchArg,
1100    /// A `match_arg` + `several_ok` container (`Vec<T>` / `Box<[T]>`),
1101    /// decoded with `match_arg_vec_from_sexp::<T>`: under `Missing<..>`, or
1102    /// on the left of an `Either<.., R>` (#1612).
1103    MatchArgSeveral,
1104    /// The string type of a `choices(...)` parameter, decoded with its own
1105    /// `TryFromSexp` (the R prelude already matched it against the list).
1106    Literal {
1107        /// The choice list, which the argument error of an `Either<.., R>`
1108        /// parameter names.
1109        choices: Vec<String>,
1110        /// `several_ok`: one or more of the choices.
1111        several: bool,
1112    },
1113}
1114
1115/// A layer around a choice parameter's value, outermost first.
1116enum ChoiceLayer<'a> {
1117    /// `Missing<..>`: the missing-argument sentinel is `Missing::Absent`.
1118    Missing,
1119    /// `Option<..>`: `NULL` is `None`.
1120    Null,
1121    /// `Either<.., R>`: character or factor input is the choice (`Left`),
1122    /// anything else converts to `R` (`Right`).
1123    Either(&'a syn::Type),
1124}
1125
1126/// The decoding expression for a choice parameter of type `ty` whose value
1127/// sits under `Missing` / `Option` / `Either` layers (#1473, #1551), applied
1128/// to the `SEXP` binding `sexp`. Each layer is one `miniextendr_api::match_arg_*`
1129/// helper that takes the decoder of the layers below it, so
1130/// `Missing<Option<Mode>>` becomes
1131///
1132/// ```ignore
1133/// ::miniextendr_api::match_arg_missing_or(sexp, ::miniextendr_api::match_arg_option_from_sexp::<Mode>)
1134/// ```
1135///
1136/// `Either<Route, DataFrame>` becomes
1137///
1138/// ```ignore
1139/// ::miniextendr_api::match_arg_either_or::<_, DataFrame, _>(sexp, ::miniextendr_api::match_arg_from_sexp::<Route>)
1140/// ```
1141///
1142/// and a `several_ok` list with another kind of value (#1612),
1143/// `Either<Vec<Fill>, DataFrame>`, becomes
1144///
1145/// ```ignore
1146/// ::miniextendr_api::match_arg_either_or::<_, DataFrame, _>(sexp, ::miniextendr_api::match_arg_vec_from_sexp::<Fill>)
1147/// ```
1148fn layered_choice_expr(
1149    ty: &syn::Type,
1150    leaf: ChoiceLeaf,
1151    sexp: &syn::Ident,
1152    span: proc_macro2::Span,
1153) -> TokenStream {
1154    let layers = crate::type_inspect::choice_layers(ty);
1155    let mut wraps = Vec::new();
1156    if layers.missing {
1157        wraps.push(ChoiceLayer::Missing);
1158    }
1159    if layers.nullable {
1160        wraps.push(ChoiceLayer::Null);
1161    }
1162    if let Some(right) = layers.either_right {
1163        wraps.push(ChoiceLayer::Either(right));
1164    }
1165    let value = LayeredValue::new(layers.value, leaf);
1166    let expr = value.apply(&wraps, &{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&sexp, &mut _s);
    _s
}quote! { #sexp });
1167    {
    let mut _s = ::quote::__private::TokenStream::new();
    let _: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::ToTokens::to_tokens(&expr, &mut _s);
    _s
}quote_spanned! {span=> #expr }
1168}
1169
1170/// The four borrowed character shapes supported by the raw converters.
1171/// Keep their worker storage owned; do not generalize this to arbitrary list
1172/// nesting, which has different conversion and rooting requirements (#1427).
1173fn worker_string_storage(ty: &syn::Type, storage: &syn::Ident) -> Option<(syn::Type, TokenStream)> {
1174    let vector_element = match ty {
1175        syn::Type::Path(path) if path.qself.is_none() => path
1176            .path
1177            .segments
1178            .last()
1179            .filter(|seg| seg.ident == "Vec")
1180            .and_then(crate::type_inspect::first_type_argument),
1181        _ => None,
1182    };
1183    let element = vector_element.unwrap_or(ty);
1184    let optional_element = crate::type_inspect::option_inner_type(element);
1185    let syn::Type::Reference(reference) = optional_element.unwrap_or(element) else {
1186        return None;
1187    };
1188    if reference.mutability.is_some()
1189        || !#[allow(non_exhaustive_omitted_patterns)] match reference.elem.as_ref() {
    syn::Type::Path(path) if path.path.is_ident("str") => true,
    _ => false,
}matches!(reference.elem.as_ref(), syn::Type::Path(path) if path.path.is_ident("str"))
1190    {
1191        return None;
1192    }
1193    Some(
1194        match (vector_element.is_some(), optional_element.is_some()) {
1195            (false, false) => (
1196                ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "string");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "String");
        _s
    })syn::parse_quote!(::std::string::String),
1197                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "std");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "string");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "String");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_str");
    ::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(&storage, &mut _s);
            _s
        });
    _s
}quote!(::std::string::String::as_str(&#storage)),
1198            ),
1199            (false, true) => (
1200                ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "core");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "option");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Option");
        ::quote::__private::push_lt(&mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "string");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "String");
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::core::option::Option<::std::string::String>),
1201                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_deref");
    ::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(&storage, &mut _s);
            _s
        });
    _s
}quote!(::core::option::Option::as_deref(&#storage)),
1202            ),
1203            (true, false) => (
1204                ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::quote::__private::push_lt(&mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "string");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "String");
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<::std::string::String>),
1205                {
    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, "iter");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Iterator");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "collect");
    ::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, "iter");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Iterator");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "map");
            ::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, "iter");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "IntoIterator");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into_iter");
                    ::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(&storage, &mut _s);
                            _s
                        });
                    ::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, "string");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "String");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "as_str");
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            _s
        });
    _s
}quote!(::core::iter::Iterator::collect(::core::iter::Iterator::map(
1206                    ::core::iter::IntoIterator::into_iter(&#storage),
1207                    ::std::string::String::as_str,
1208                ))),
1209            ),
1210            (true, true) => (
1211                ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::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, "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, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "string");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "String");
        ::quote::__private::push_shr(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<::core::option::Option<::std::string::String>>),
1212                {
    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, "iter");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Iterator");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "collect");
    ::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, "iter");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Iterator");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "map");
            ::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, "iter");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "IntoIterator");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into_iter");
                    ::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(&storage, &mut _s);
                            _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, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "as_deref");
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            _s
        });
    _s
}quote!(::core::iter::Iterator::collect(::core::iter::Iterator::map(
1213                    ::core::iter::IntoIterator::into_iter(&#storage),
1214                    ::core::option::Option::as_deref,
1215                ))),
1216            ),
1217        },
1218    )
1219}
1220
1221/// Shared native worker inputs are snapshots of their R-thread conversion.
1222/// Copy before dispatch, then form every reference inside the worker closure.
1223/// Mutable inputs keep their separate write-through conversion path.
1224fn worker_native_storage(
1225    ty: &syn::Type,
1226    storage: &syn::Ident,
1227) -> Option<(syn::Type, TokenStream, TokenStream)> {
1228    if !crate::type_inspect::is_rooted_reference(ty) || worker_string_storage(ty, storage).is_some()
1229    {
1230        return None;
1231    }
1232    let optional = crate::type_inspect::option_inner_type(ty);
1233    let syn::Type::Reference(reference) = optional.unwrap_or(ty) else {
1234        return None;
1235    };
1236    let element = &reference.elem;
1237    let (owned, copy, borrow) = match element.as_ref() {
1238        syn::Type::Slice(slice) => {
1239            let element = &slice.elem;
1240            (
1241                ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "std");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "vec");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Vec");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&element, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::std::vec::Vec<#element>),
1242                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "std");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "vec");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Vec");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "from");
    _s
}quote!(::std::vec::Vec::from),
1243                if optional.is_some() {
1244                    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_deref");
    ::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(&storage, &mut _s);
            _s
        });
    _s
}quote!(::core::option::Option::as_deref(&#storage))
1245                } else {
1246                    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "std");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "vec");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Vec");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_slice");
    ::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(&storage, &mut _s);
            _s
        });
    _s
}quote!(::std::vec::Vec::as_slice(&#storage))
1247                },
1248            )
1249        }
1250        _ => (
1251            element.as_ref().clone(),
1252            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_or(&mut _s);
    ::quote::__private::push_ident(&mut _s, "value");
    ::quote::__private::push_or(&mut _s);
    ::quote::__private::push_star(&mut _s);
    ::quote::__private::push_ident(&mut _s, "value");
    _s
}quote!(|value| *value),
1253            if optional.is_some() {
1254                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_ref");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::quote::ToTokens::to_tokens(&storage, &mut _s);
            _s
        });
    _s
}quote!(::core::option::Option::as_ref(&#storage))
1255            } else {
1256                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::ToTokens::to_tokens(&storage, &mut _s);
    _s
}quote!(&#storage)
1257            },
1258        ),
1259    };
1260    if optional.is_some() {
1261        Some((
1262            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "core");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "option");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Option");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&owned, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })syn::parse_quote!(::core::option::Option<#owned>),
1263            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_or(&mut _s);
    ::quote::__private::push_ident(&mut _s, "value");
    ::quote::__private::push_or(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "value");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&copy, &mut _s);
            _s
        });
    _s
}quote!(|value| ::core::option::Option::map(value, #copy)),
1264            borrow,
1265        ))
1266    } else {
1267        Some((owned, copy, borrow))
1268    }
1269}
1270
1271/// One compile-time assertion per leaf of the `R` arm of an `Either` choice
1272/// parameter `param` of type `ty` (nested `Either`s on the `R` side peeled):
1273/// compilation fails when the leaf's `TryFromSexp` is `CHARACTER_ONLY`, since
1274/// the choice check never sends character or factor input there. Read
1275/// through `EitherArmProbe`, so a leaf without `TryFromSexp` adds no error of
1276/// its own. Empty without an `Either` layer.
1277///
1278/// Each guard is a block holding only items (the fallback trait import and a
1279/// `const _` assertion), spanned on the leaf: the assertion is evaluated by
1280/// `cargo check` too, and the error points at the arm.
1281fn either_arm_guards(param: &str, ty: &syn::Type) -> Vec<TokenStream> {
1282    fn leaves<'a>(ty: &'a syn::Type, out: &mut Vec<&'a syn::Type>) {
1283        match crate::type_inspect::either_arms(ty) {
1284            Some((left, right)) => {
1285                leaves(left, out);
1286                leaves(right, out);
1287            }
1288            None => out.push(ty),
1289        }
1290    }
1291
1292    let Some(right) = crate::type_inspect::choice_layers(ty).either_right else {
1293        return Vec::new();
1294    };
1295    let nested = crate::type_inspect::either_arms(right).is_some();
1296    let mut arms = Vec::new();
1297    leaves(right, &mut arms);
1298    arms.into_iter()
1299        .map(|leaf| {
1300            let shown = crate::type_inspect::type_display(leaf);
1301            let arm = if nested {
1302                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("the other arm\'s `{1}` (in `{0}`)",
                crate::type_inspect::type_display(right), shown))
    })format!(
1303                    "the other arm's `{shown}` (in `{}`)",
1304                    crate::type_inspect::type_display(right)
1305                )
1306            } else {
1307                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("the other arm `{0}`", shown))
    })format!("the other arm `{shown}`")
1308            };
1309            let message = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`Either` choice parameter `{0}`: {1} reads only character or factor input, and the choice check sends every character or factor argument to the choice arm, so at most NULL can reach `{2}`. Give that arm a type that reads other input (a data frame, a number, a list); for a NULL alternative, declare the parameter as `Option<Either<..>>`.",
                param, arm, shown))
    })format!(
1310                "`Either` choice parameter `{param}`: {arm} reads only character or factor \
1311                 input, and the choice check sends every character or factor argument to the \
1312                 choice arm, so at most NULL can reach `{shown}`. Give that arm a type that \
1313                 reads other input (a data frame, a number, a list); for a NULL alternative, \
1314                 declare the parameter as `Option<Either<..>>`."
1315            );
1316            // `assert!` reads a lone literal as a format string.
1317            let message = message.replace('{', "{{").replace('}', "}}");
1318            let probe = crate::type_inspect::erase_lifetimes(leaf);
1319            {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(leaf.span()).__into_span();
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_pound_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "allow");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "unused_imports");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_ident_spanned(&mut _s, _span, "use");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "match_arg");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "EitherArmProbeFallback");
            ::quote::__private::push_ident_spanned(&mut _s, _span, "as");
            ::quote::__private::push_underscore_spanned(&mut _s, _span);
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            ::quote::__private::push_pound_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "allow");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "clippy");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "assertions_on_constants");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_ident_spanned(&mut _s, _span, "const");
            ::quote::__private::push_underscore_spanned(&mut _s, _span);
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::TokenStream::new()
                });
            ::quote::__private::push_eq_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "assert");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_bang_spanned(&mut _s, _span);
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "match_arg");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "EitherArmProbe");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_lt_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&probe, &mut _s);
                    ::quote::__private::push_gt_spanned(&mut _s, _span);
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "CHARACTER_ONLY");
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&message, &mut _s);
                    _s
                });
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {leaf.span()=>
1320                {
1321                    #[allow(unused_imports)]
1322                    use ::miniextendr_api::match_arg::EitherArmProbeFallback as _;
1323                    #[allow(clippy::assertions_on_constants)]
1324                    const _: () = ::core::assert!(
1325                        !::miniextendr_api::match_arg::EitherArmProbe::<#probe>::CHARACTER_ONLY,
1326                        #message
1327                    );
1328                }
1329            }
1330        })
1331        .collect()
1332}
1333
1334/// The innermost value of a layered choice parameter.
1335struct LayeredValue {
1336    leaf: ChoiceLeaf,
1337    /// The decoded type: the `MatchArg` type of a scalar, the element type
1338    /// of a `several_ok` container, the string type of a `choices` value
1339    /// (lifetimes erased).
1340    choice_ty: syn::Type,
1341    /// A `Box<[T]>` container, converted from the decoded `Vec<T>`.
1342    boxed: bool,
1343}
1344
1345impl LayeredValue {
1346    fn new(value: &syn::Type, leaf: ChoiceLeaf) -> Self {
1347        let (choice_ty, boxed) = match (&leaf, crate::classify_several_ok_container(value)) {
1348            (ChoiceLeaf::MatchArgSeveral, Some((container, inner))) => (
1349                inner.clone(),
1350                #[allow(non_exhaustive_omitted_patterns)] match container {
    crate::SeveralOkContainer::BoxedSlice => true,
    _ => false,
}matches!(container, crate::SeveralOkContainer::BoxedSlice),
1351            ),
1352            _ => (crate::type_inspect::erase_lifetimes(value), false),
1353        };
1354        Self {
1355            leaf,
1356            choice_ty,
1357            boxed,
1358        }
1359    }
1360
1361    /// `layers` over this value, decoding the argument `sexp`: the outermost
1362    /// layer's helper called on `sexp` with the decoder of the rest.
1363    fn apply(&self, layers: &[ChoiceLayer], sexp: &TokenStream) -> TokenStream {
1364        let t = &self.choice_ty;
1365        match layers {
1366            [] if self.boxed => {
    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, "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &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(&sexp, &mut _s);
            _s
        });
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::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, "std");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "vec");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Vec");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into_boxed_slice");
            _s
        });
    _s
}quote! {
1367                ::miniextendr_api::match_arg_vec_from_sexp::<#t>(#sexp)
1368                    .map(::std::vec::Vec::into_boxed_slice)
1369            },
1370            [] => {
1371                let decoder = self.decoder(&[]);
1372                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&decoder, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&sexp, &mut _s);
            _s
        });
    _s
}quote! { #decoder(#sexp) }
1373            }
1374            // `Option<T>` over a scalar choice (#1473) keeps its dedicated helper.
1375            [ChoiceLayer::Null] if self.leaf == ChoiceLeaf::MatchArg => {
1376                {
    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, "match_arg_option_from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &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(&sexp, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::match_arg_option_from_sexp::<#t>(#sexp) }
1377            }
1378            [first, rest @ ..] => {
1379                let inner = self.decoder(rest);
1380                match first {
1381                    ChoiceLayer::Missing => {
1382                        {
    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, "match_arg_missing_or");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&sexp, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::match_arg_missing_or(#sexp, #inner) }
1383                    }
1384                    ChoiceLayer::Null => {
1385                        {
    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, "match_arg_null_or");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&sexp, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::match_arg_null_or(#sexp, #inner) }
1386                    }
1387                    ChoiceLayer::Either(right) => {
1388                        let right = crate::type_inspect::erase_lifetimes(right);
1389                        {
    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, "match_arg_either_or");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_underscore(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&right, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_underscore(&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(&sexp, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            _s
        });
    _s
}quote! {
1390                            ::miniextendr_api::match_arg_either_or::<_, #right, _>(#sexp, #inner)
1391                        }
1392                    }
1393                }
1394            }
1395        }
1396    }
1397
1398    /// `layers` over this value as a decoder (`FnOnce(SEXP) -> Result<_, _>`):
1399    /// a function path where one exists, a closure otherwise.
1400    fn decoder(&self, layers: &[ChoiceLayer]) -> TokenStream {
1401        let t = &self.choice_ty;
1402        match (layers, &self.leaf) {
1403            ([], ChoiceLeaf::MatchArg) => {
1404                {
    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, "match_arg_from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! { ::miniextendr_api::match_arg_from_sexp::<#t> }
1405            }
1406            ([], ChoiceLeaf::MatchArgSeveral) if !self.boxed => {
1407                {
    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, "match_arg_vec_from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! { ::miniextendr_api::match_arg_vec_from_sexp::<#t> }
1408            }
1409            ([], ChoiceLeaf::Literal { .. }) => {
1410                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &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, "try_from_sexp");
    _s
}quote! { <#t as ::miniextendr_api::TryFromSexp>::try_from_sexp }
1411            }
1412            ([ChoiceLayer::Null], ChoiceLeaf::MatchArg) => {
1413                {
    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, "match_arg_option_from_sexp");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&t, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! { ::miniextendr_api::match_arg_option_from_sexp::<#t> }
1414            }
1415            _ => {
1416                let arg = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "__mx_sexp");
    _s
}quote! { __mx_sexp };
1417                let body = self.apply(layers, &arg);
1418                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_or(&mut _s);
    ::quote::ToTokens::to_tokens(&arg, &mut _s);
    ::quote::__private::push_or(&mut _s);
    ::quote::ToTokens::to_tokens(&body, &mut _s);
    _s
}quote! { |#arg| #body }
1419            }
1420        }
1421    }
1422}
1423
1424// endregion
1425
1426// region: conversion-failure conditions
1427
1428/// The R-facing context of one argument's conversion failure (#1591).
1429#[derive(#[automatically_derived]
impl ::core::clone::Clone for ArgContext {
    #[inline]
    fn clone(&self) -> Self {
        ArgContext {
            prefix: ::core::clone::Clone::clone(&self.prefix),
            expected_known: ::core::clone::Clone::clone(&self.expected_known),
            expected_at_run_time: ::core::clone::Clone::clone(&self.expected_at_run_time),
            declared: ::core::clone::Clone::clone(&self.declared),
            r_name: ::core::clone::Clone::clone(&self.r_name),
            rust_type: ::core::clone::Clone::clone(&self.rust_type),
            nullable: ::core::clone::Clone::clone(&self.nullable),
        }
    }
}Clone)]
1430struct ArgContext {
1431    /// The message prefix: `'<p>' must be <expected>` when the type has an
1432    /// R-facing expectation ([`crate::r_preconditions::conversion_expectation`]),
1433    /// `invalid '<p>' argument` otherwise. The error's reason follows it.
1434    prefix: String,
1435    /// Whether `prefix` states the expectation. Passed to the probe
1436    /// (`__mx_conversion_err_parts!(e, expected_known)`), so a built-in error's
1437    /// reason does not repeat it (`got character` rather than
1438    /// `expected integer, got character`).
1439    expected_known: bool,
1440    /// An expression yielding the expectation (a `String`) on the failure
1441    /// path, when the macro knows it but not its text: the choices of a
1442    /// `match_arg` type under an `Either<.., R>` layer come from
1443    /// `MatchArg::CHOICES`. Takes the place of `prefix`.
1444    expected_at_run_time: Option<TokenStream>,
1445    /// An expression yielding what the argument's type declares (an
1446    /// `Option<String>`) on the failure path, when the macro has no wording
1447    /// for it: set by [`ArgContext::with_declared`] where the binding
1448    /// converts with `TryFromSexp`, and tried before the error's own
1449    /// expectation ([`declared_expectation`]).
1450    declared: Option<TokenStream>,
1451    /// The R formal's name, `e$param`.
1452    r_name: String,
1453    /// The Rust type as written in the signature, `e$rust_type`: kept for the
1454    /// package author, out of the user-facing message.
1455    rust_type: String,
1456    /// Whether the value may be `NULL` (an `Option<_>`, under any `Missing`):
1457    /// an expectation the error supplies at run time then reads
1458    /// `NULL or <expected>`. Only used when `expected_known` is `false`.
1459    nullable: bool,
1460}
1461
1462impl ArgContext {
1463    /// The context of parameter `r_name` of type `ty`; `coerced` when the
1464    /// `coerce` knob applies to it (the expectation widens with the gate).
1465    fn new(r_name: &str, ty: &syn::Type, coerced: bool) -> Self {
1466        Self::with_expectation(
1467            r_name,
1468            ty,
1469            crate::r_preconditions::conversion_expectation(ty, coerced),
1470        )
1471    }
1472
1473    /// The context of a `strict` lossy-integer parameter (#1594): the
1474    /// expectation names what strict accepts, a whole number, since a
1475    /// logical, raw or fractional input is refused.
1476    fn strict(r_name: &str, ty: &syn::Type) -> Self {
1477        Self::with_expectation(
1478            r_name,
1479            ty,
1480            crate::r_preconditions::strict_conversion_expectation(ty),
1481        )
1482    }
1483
1484    fn with_expectation(r_name: &str, ty: &syn::Type, expected: Option<String>) -> Self {
1485        let prefix = match &expected {
1486            Some(expected) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\'{0}\' must be {1}", r_name,
                expected))
    })format!("'{r_name}' must be {expected}"),
1487            None => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("invalid \'{0}\' argument", r_name))
    })format!("invalid '{r_name}' argument"),
1488        };
1489        let value_ty = crate::miniextendr_fn::get_missing_inner_type(ty).unwrap_or(ty);
1490        Self {
1491            prefix,
1492            expected_known: expected.is_some(),
1493            expected_at_run_time: None,
1494            declared: None,
1495            r_name: r_name.to_string(),
1496            rust_type: crate::type_inspect::type_display(ty),
1497            nullable: crate::type_inspect::is_option_type(value_ty),
1498        }
1499    }
1500
1501    /// This context for a binding that converts `ty` with `TryFromSexp`: when
1502    /// the macro has no wording for the type, the failure path asks the type
1503    /// what it declares ([`declared_expectation`]). Only there is
1504    /// `ty: TryFromSexp` known; the other conversion paths (a `several_ok`
1505    /// `Vec<Mode>`, a coercion helper) may name a type that has no impl. An
1506    /// `impl Trait` type gets no lookup: it cannot name a path, and its
1507    /// binding is already the compile error.
1508    fn with_declared(&self, ty: &syn::Type) -> Self {
1509        let mut ctx = self.clone();
1510        if !ctx.expected_known && ctx.expected_at_run_time.is_none() && !names_impl_trait(ty) {
1511            ctx.declared = Some(declared_expectation(ty));
1512        }
1513        ctx
1514    }
1515
1516    /// [`ArgContext::with_declared`] for a copied trait signature (#2123):
1517    /// the witness `target` names the type the method takes.
1518    fn with_inferred(&self, target: &syn::Ident) -> Self {
1519        let mut ctx = self.clone();
1520        if !ctx.expected_known && ctx.expected_at_run_time.is_none() {
1521            ctx.declared =
1522                Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&target, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "expectation");
    ::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, "map");
    ::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, "std");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "string");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ToString");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "to_string");
            _s
        });
    _s
}quote! { #target.expectation().map(::std::string::ToString::to_string) });
1523        }
1524        ctx
1525    }
1526
1527    /// The context of a choice parameter of type `ty` decoded as `leaf`, when
1528    /// the type has an `Either<.., R>` layer; `None` otherwise. A value `R`
1529    /// refuses is reported against the whole parameter, in the words of its
1530    /// `@param` line: `'route' must be one of "oral", "bolus", or a data
1531    /// frame` (`one or more of` for `several_ok`, `, a data frame, or NULL`
1532    /// under `Option`). The choices are `MatchArg::CHOICES` for a `match_arg`
1533    /// type, followed by its listed `MatchArg::ALIASES` (`(or "po" for
1534    /// "oral")`, #2148), and the literal list for `choices(...)`, which has
1535    /// no aliases; the `R` arm is named by its `@param` noun
1536    /// ([`crate::type_inspect::r_value_noun`]). The error then supplies only
1537    /// the reason (`got integer`).
1538    fn either_choice(r_name: &str, ty: &syn::Type, leaf: &ChoiceLeaf) -> Option<Self> {
1539        let layers = crate::type_inspect::choice_layers(ty);
1540        let right = layers.either_right?;
1541        let suffix = crate::miniextendr_fn::choice_alternatives_suffix(
1542            Some(&crate::type_inspect::r_value_noun(right)),
1543            layers.nullable,
1544            "NULL",
1545        );
1546        let (choices, aliases, several) = match leaf {
1547            ChoiceLeaf::Literal { choices, several } => {
1548                ({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&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 choices, i) = choices.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let choices =
                        match choices.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&choices, &mut _s);
                }
            }
            _s
        });
    _s
}quote! { &[#(#choices),*] }, {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        ::quote::__private::TokenStream::new());
    _s
}quote! { &[] }, *several)
1549            }
1550            ChoiceLeaf::MatchArg | ChoiceLeaf::MatchArgSeveral => {
1551                let choice_ty = LayeredValue::new(layers.value, leaf.clone()).choice_ty;
1552                (
1553                    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&choice_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, "MatchArg");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "CHOICES");
    _s
}quote! { <#choice_ty as ::miniextendr_api::MatchArg>::CHOICES },
1554                    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&choice_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, "MatchArg");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ALIASES");
    _s
}quote! { <#choice_ty as ::miniextendr_api::MatchArg>::ALIASES },
1555                    *leaf == ChoiceLeaf::MatchArgSeveral,
1556                )
1557            }
1558        };
1559        Some(Self {
1560            expected_at_run_time: Some({
    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, "match_arg");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "choice_expectation");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&choices, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&aliases, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&several, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&suffix, &mut _s);
            _s
        });
    _s
}quote! {
1561                ::miniextendr_api::match_arg::choice_expectation(#choices, #aliases, #several, #suffix)
1562            }),
1563            ..Self::with_expectation(r_name, ty, None)
1564        })
1565    }
1566}
1567
1568/// The `Err(e)` arm of a conversion binding: return the tagged
1569/// `kind = "conversion"` value. `__mx_conversion_err_parts!` takes the class
1570/// vector, message and data from an `RConditionData` error type, the
1571/// R-worded reason from a built-in conversion error and the `Display` text
1572/// otherwise; `conversion_condition_value` puts the context's prefix before
1573/// it, appends the crate's `conversion_error_class` and adds `e$param` and
1574/// `e$rust_type`.
1575fn conversion_err_arm(
1576    ctx: &ArgContext,
1577    crate_class: &[String],
1578    span: proc_macro2::Span,
1579) -> TokenStream {
1580    let call = crate::naming::call_slot_ident();
1581    conversion_err_arm_with_call(
1582        ctx,
1583        crate_class,
1584        &{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Some");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&call, &mut _s);
            _s
        });
    _s
}quote! { ::core::option::Option::Some(#call) },
1585        span,
1586    )
1587}
1588
1589/// Trait shims have no R call slot. They return the same structured argument
1590/// error as C wrappers; a View re-panic attributes it to the consumer's call.
1591/// `read_ty` supplies TryFromSexp expectations when the conversion uses that
1592/// trait; rooted views instead derive their expectation from the error.
1593pub(crate) fn shim_conversion_err_arm(
1594    name: &str,
1595    ty: &syn::Type,
1596    read_ty: Option<&syn::Type>,
1597    target: Option<&syn::Ident>,
1598) -> TokenStream {
1599    let mut ctx = ArgContext::new(name, ty, false);
1600    if let Some(target) = target {
1601        ctx = ctx.with_inferred(target);
1602    } else if let Some(read_ty) = read_ty {
1603        ctx = ctx.with_declared(read_ty);
1604    }
1605    conversion_err_arm_with_call(
1606        &ctx,
1607        &crate::crate_config::conversion_error_class(),
1608        &{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "None");
    _s
}quote! { ::core::option::Option::None },
1609        ty.span(),
1610    )
1611}
1612
1613fn conversion_err_arm_with_call(
1614    ctx: &ArgContext,
1615    crate_class: &[String],
1616    call: &TokenStream,
1617    span: proc_macro2::Span,
1618) -> TokenStream {
1619    let ArgContext {
1620        prefix,
1621        expected_known,
1622        expected_at_run_time,
1623        declared,
1624        r_name,
1625        rust_type,
1626        nullable,
1627    } = ctx;
1628    let expected = match expected_at_run_time {
1629        Some(expr) => Expected::RunTime(expr),
1630        None if *expected_known => Expected::Literal(prefix),
1631        None => Expected::FromError(declared.as_ref()),
1632    };
1633    let value = conversion_value_tokens(
1634        &ConversionSubject {
1635            expected,
1636            quoted: r_name,
1637            param: r_name,
1638            nullable: *nullable,
1639            rust_type,
1640        },
1641        crate_class,
1642        call,
1643        span,
1644    );
1645    let err = crate::naming::conversion_error_ident();
1646    // SAFETY (of the emitted `unsafe`): the arm runs inside the wrapper's
1647    // with_r_unwind_protect closure, on the R main thread.
1648    {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "result");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Result");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Err");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&err, &mut _s);
            _s
        });
    ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "return");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&value, &mut _s);
            _s
        });
    ::quote::__private::push_comma_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
1649        ::core::result::Result::Err(#err) => return unsafe { #value },
1650    }
1651}
1652
1653/// The post-conversion `no_na` check of the binding `ident` (R name
1654/// `r_name`): when the value holds what its type reads as `NA`
1655/// (`TryFromSexp::__mx_has_na`), return the tagged `kind = "conversion"`
1656/// value `no_na`'s R guard would raise, with `message` verbatim, the crate's
1657/// `conversion_error_class` and `e$param` (`arg_check_condition_value`). The
1658/// call is the wrapper's call slot, as for a conversion failure.
1659///
1660/// `input` is the argument's SEXP when no R guard ran (an `Either`, see
1661/// `r_preconditions::no_na_checked_after_conversion`): the value is then
1662/// asked `TryFromSexp::__mx_input_has_na`, which also makes the guard's
1663/// `anyNA()` check on the input, by the arm the value converted to.
1664fn no_na_value_stmt(
1665    ident: &syn::Ident,
1666    input: Option<&syn::Ident>,
1667    r_name: &str,
1668    message: &str,
1669    crate_class: &[String],
1670    span: proc_macro2::Span,
1671) -> TokenStream {
1672    let call = crate::naming::call_slot_ident();
1673    let has_na = match input {
1674        Some(sexp) => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromSexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "__mx_input_has_na");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&ident, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&sexp, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
1675            ::miniextendr_api::TryFromSexp::__mx_input_has_na(&#ident, #sexp)
1676        },
1677        None => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "TryFromSexp");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "__mx_has_na");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&ident, &mut _s);
            _s
        });
    _s
}quote_spanned! {span=>
1678            ::miniextendr_api::TryFromSexp::__mx_has_na(&#ident)
1679        },
1680    };
1681    // SAFETY (of the emitted `unsafe`): the check runs right after the
1682    // argument's conversion, where the conversion `Err` arm runs: on the R
1683    // main thread, inside the wrapper's with_r_unwind_protect closure or
1684    // before the worker closure.
1685    {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "if");
    ::quote::ToTokens::to_tokens(&has_na, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "return");
            ::quote::__private::push_ident_spanned(&mut _s, _span, "unsafe");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "error_value");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "arg_check_condition_value");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::ToTokens::to_tokens(&message, &mut _s);
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::ToTokens::to_tokens(&r_name, &mut _s);
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::__private::push_and_spanned(&mut _s, _span);
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Bracket,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    let _span: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    {
                                        use ::quote::__private::ext::*;
                                        let mut _first = true;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut crate_class, i) = crate_class.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let crate_class =
                                                match crate_class.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            if !_first {
                                                ::quote::__private::push_comma_spanned(&mut _s, _span);
                                            }
                                            _first = false;
                                            ::quote::ToTokens::to_tokens(&crate_class, &mut _s);
                                        }
                                    }
                                    _s
                                });
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "core");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "option");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "Option");
                            ::quote::__private::push_colon2_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "Some");
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    let _: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    ::quote::ToTokens::to_tokens(&call, &mut _s);
                                    _s
                                });
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {span=>
1686        if #has_na {
1687            return unsafe {
1688                ::miniextendr_api::error_value::arg_check_condition_value(
1689                    #message,
1690                    #r_name,
1691                    &[#(#crate_class),*],
1692                    ::core::option::Option::Some(#call),
1693                )
1694            };
1695        }
1696    }
1697}
1698
1699/// Where the `<expected>` of a conversion failure's `'<p>' must be <expected>`
1700/// comes from.
1701pub(crate) enum Expected<'a> {
1702    /// The macro knows it: the whole prefix, `'<p>' must be <expected>`.
1703    Literal(&'a str),
1704    /// An expression the macro wrote yields it on the failure path (the
1705    /// choices of a `match_arg` type): the prefix is `'<p>' must be <it>`.
1706    RunTime(&'a TokenStream),
1707    /// What the type declares, when an expression for it is given
1708    /// ([`declared_expectation`]), else what the error may know
1709    /// (`__mx_conversion_expectation!`), else the prefix is
1710    /// `invalid '<p>' argument`.
1711    FromError(Option<&'a TokenStream>),
1712}
1713
1714/// What a conversion failure is about: the value it names and how.
1715pub(crate) struct ConversionSubject<'a> {
1716    /// Where the expectation in the message prefix comes from.
1717    pub(crate) expected: Expected<'a>,
1718    /// The name quoted in the message: the parameter, or a sidecar's field.
1719    pub(crate) quoted: &'a str,
1720    /// `e$param`: the R formal that failed.
1721    pub(crate) param: &'a str,
1722    /// The value may be `NULL` (`Option<_>`): an expectation the error
1723    /// supplies reads `NULL or <expected>` ([`Expected::FromError`] only).
1724    pub(crate) nullable: bool,
1725    /// `e$rust_type`: the Rust type as written.
1726    pub(crate) rust_type: &'a str,
1727}
1728
1729/// The `conversion_condition_value(...)` expression for the error bound as
1730/// `e` on `subject`, with the crate class and `call`.
1731///
1732/// With [`Expected::Literal`] (the macro knows the R-facing expectation,
1733/// `'<p>' must be <expected>`) the prefix is that literal; with
1734/// [`Expected::RunTime`] it is `'<p>' must be ` and the expression's value.
1735/// With [`Expected::FromError`] the prefix is built on the failure path by
1736/// `condition::conversion_prefix` (`NULL or ...` when `nullable`) from what
1737/// the type declares (a `#[derive(TryFromSexp)]` newtype, the sides of an
1738/// `Either`), else what the error may know (`__mx_conversion_expectation!(e)`,
1739/// #1594), falling back to `invalid '<p>' argument`.
1740///
1741/// With [`Expected::RunTime`] and [`Expected::FromError`] the error may also
1742/// word the whole message (`__mx_conversion_arg_message!(e, quoted)`): a
1743/// `match_arg` choice error reads as the R-side `match_arg` check
1744/// (`'mode' should be one of "fast", "slow"`, #1767), whatever the prefix.
1745/// Shared by the argument conversions and the sidecar setters.
1746pub(crate) fn conversion_value_tokens(
1747    subject: &ConversionSubject,
1748    crate_class: &[String],
1749    call: &TokenStream,
1750    span: proc_macro2::Span,
1751) -> TokenStream {
1752    let ConversionSubject {
1753        expected,
1754        quoted,
1755        param,
1756        nullable,
1757        rust_type,
1758    } = subject;
1759    let rust_type = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Some");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&rust_type, &mut _s);
            _s
        });
    _s
}quote! { ::core::option::Option::Some(#rust_type) };
1760    let e = crate::naming::conversion_error_ident();
1761    // A `match_arg` choice error words the whole message as the R-side
1762    // `match_arg` check does (#1767). A type with a literal expectation is
1763    // never a `match_arg` type, so only the other two arms ask.
1764    let arg_message = {
    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_conversion_arg_message");
    ::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(&e, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&quoted, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::__mx_conversion_arg_message!(#e, #quoted) };
1765    match expected {
1766        Expected::Literal(prefix) => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "error_value");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "conversion_condition_value");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&prefix, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&param, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&rust_type, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    {
                        use ::quote::__private::ext::*;
                        let mut _first = true;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut crate_class, i) = crate_class.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let crate_class =
                                match crate_class.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            if !_first {
                                ::quote::__private::push_comma_spanned(&mut _s, _span);
                            }
                            _first = false;
                            ::quote::ToTokens::to_tokens(&crate_class, &mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_conversion_err_parts");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::ToTokens::to_tokens(&e, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "true");
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "None");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&call, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {span=>
1767            ::miniextendr_api::error_value::conversion_condition_value(
1768                #prefix,
1769                #param,
1770                #rust_type,
1771                &[#(#crate_class),*],
1772                ::miniextendr_api::__mx_conversion_err_parts!(#e, true),
1773                ::core::option::Option::None,
1774                #call,
1775            )
1776        },
1777        Expected::RunTime(expr) => {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "error_value");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "conversion_condition_value");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "std");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "format");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::parse_spanned(&mut _s, _span,
                        "\"\'{}\' must be {}\"");
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&quoted, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&expr, &mut _s);
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&param, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&rust_type, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    {
                        use ::quote::__private::ext::*;
                        let mut _first = true;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut crate_class, i) = crate_class.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let crate_class =
                                match crate_class.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            if !_first {
                                ::quote::__private::push_comma_spanned(&mut _s, _span);
                            }
                            _first = false;
                            ::quote::ToTokens::to_tokens(&crate_class, &mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_conversion_err_parts");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::ToTokens::to_tokens(&e, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "true");
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&arg_message, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&call, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {span=>
1778            ::miniextendr_api::error_value::conversion_condition_value(
1779                &::std::format!("'{}' must be {}", #quoted, #expr),
1780                #param,
1781                #rust_type,
1782                &[#(#crate_class),*],
1783                ::miniextendr_api::__mx_conversion_err_parts!(#e, true),
1784                #arg_message,
1785                #call,
1786            )
1787        },
1788        Expected::FromError(declared) => {
1789            let from_error = {
    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_conversion_expectation");
    ::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(&e, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::__mx_conversion_expectation!(#e) };
1790            let expected = match declared {
1791                Some(declared) => {
    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::ToTokens::to_tokens(&declared, &mut _s);
            _s
        });
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "or_else");
    ::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::ToTokens::to_tokens(&from_error, &mut _s);
            _s
        });
    _s
}quote! { (#declared).or_else(|| #from_error) },
1792                None => from_error,
1793            };
1794            {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_expected");
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_lt_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "std");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "string");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "String");
            ::quote::__private::push_gt_spanned(&mut _s, _span);
            ::quote::__private::push_eq_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&expected, &mut _s);
            ::quote::__private::push_semi_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "error_value");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "conversion_condition_value");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "condition");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "conversion_prefix");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::ToTokens::to_tokens(&quoted, &mut _s);
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::ToTokens::to_tokens(&nullable, &mut _s);
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "__mx_expected");
                            ::quote::__private::push_dot_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "as_deref");
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let _: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    ::quote::__private::TokenStream::new()
                                });
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            _s
                        });
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&param, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&rust_type, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Bracket,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            {
                                use ::quote::__private::ext::*;
                                let mut _first = true;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut crate_class, i) = crate_class.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let crate_class =
                                        match crate_class.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    if !_first {
                                        ::quote::__private::push_comma_spanned(&mut _s, _span);
                                    }
                                    _first = false;
                                    ::quote::ToTokens::to_tokens(&crate_class, &mut _s);
                                }
                            }
                            _s
                        });
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "miniextendr_api");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "__mx_conversion_err_parts");
                    ::quote::__private::push_bang_spanned(&mut _s, _span);
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            let _span: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::ToTokens::to_tokens(&e, &mut _s);
                            ::quote::__private::push_comma_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "__mx_expected");
                            ::quote::__private::push_dot_spanned(&mut _s, _span);
                            ::quote::__private::push_ident_spanned(&mut _s, _span,
                                "is_some");
                            ::quote::__private::push_group_spanned(&mut _s, _span,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let _: ::quote::__private::Span =
                                        ::quote::__private::get_span(_span).__into_span();
                                    ::quote::__private::TokenStream::new()
                                });
                            _s
                        });
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&arg_message, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&call, &mut _s);
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    _s
                });
            _s
        });
    _s
}quote_spanned! {span=> {
1795                let __mx_expected: ::core::option::Option<::std::string::String> = #expected;
1796                ::miniextendr_api::error_value::conversion_condition_value(
1797                    &::miniextendr_api::condition::conversion_prefix(
1798                        #quoted,
1799                        #nullable,
1800                        __mx_expected.as_deref(),
1801                    ),
1802                    #param,
1803                    #rust_type,
1804                    &[#(#crate_class),*],
1805                    ::miniextendr_api::__mx_conversion_err_parts!(#e, __mx_expected.is_some()),
1806                    #arg_message,
1807                    #call,
1808                )
1809            } }
1810        }
1811    }
1812}
1813
1814/// The expression, on a conversion failure's path, for what a parameter of
1815/// type `ty` declares when the macro has no wording for it: an
1816/// `Option<String>`, with the error bound as `e`. Only for a type the binding
1817/// converts with `TryFromSexp`, whose `__MX_EXPECTATION` it reads.
1818///
1819/// An `Either` (also under `Missing`) is worded side by side
1820/// (`from_r::either_expectation`, [`expected_arm`]), so one side the macro
1821/// does not know no longer leaves the whole parameter without an
1822/// expectation; any other type is asked for its `__MX_EXPECTATION` (a
1823/// `#[derive(TryFromSexp)]` newtype says what its inner type does). The
1824/// `NULL or` of an `Option<_>` parameter is the prefix's (`nullable`).
1825pub(crate) fn declared_expectation(ty: &syn::Type) -> TokenStream {
1826    let value = crate::miniextendr_fn::get_missing_inner_type(ty).unwrap_or(ty);
1827    let value = crate::type_inspect::option_inner_type(value).unwrap_or(value);
1828    if crate::type_inspect::either_arms(value).is_some() {
1829        let arms = expected_arm(value);
1830        let e = crate::naming::conversion_error_ident();
1831        {
    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, "from_r");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "either_expectation");
    ::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(&e, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::ToTokens::to_tokens(&arms, &mut _s);
            _s
        });
    _s
}quote! { ::miniextendr_api::from_r::either_expectation(&#e, &#arms) }
1832    } else {
1833        let value = crate::type_inspect::erase_lifetimes(value);
1834        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&value, &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, "__MX_EXPECTATION");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::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, "std");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "string");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ToString");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "to_string");
            _s
        });
    _s
}quote! {
1835            <#value as ::miniextendr_api::TryFromSexp>::__MX_EXPECTATION
1836                .map(::std::string::ToString::to_string)
1837        }
1838    }
1839}
1840
1841/// The `from_r::ExpectedArm` of one side of an `Either`, of type `ty`: the
1842/// macro's wording when it has one
1843/// ([`crate::r_preconditions::conversion_expectation`]), a nested `Either`
1844/// side by side, `NULL or <T>` for an `Option<T>` or `Result<T, ()>` side,
1845/// else the type's `__MX_EXPECTATION`, with its `@param` noun
1846/// ([`crate::type_inspect::r_value_noun`]) for when neither the type nor its
1847/// error names it. Every side is a `TryFromSexp` type, as `Either`'s own
1848/// impl requires (and the `Option` / `Result` impls of their `T`).
1849fn expected_arm(ty: &syn::Type) -> TokenStream {
1850    let arm = {
    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, "from_r");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ExpectedArm");
    _s
}quote! { ::miniextendr_api::from_r::ExpectedArm };
1851    if let Some(text) = crate::r_preconditions::conversion_expectation(ty, false) {
1852        return {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&arm, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Known");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&text, &mut _s);
            _s
        });
    _s
}quote! { #arm::Known(#text) };
1853    }
1854    if let Some((left, right)) = crate::type_inspect::either_arms(ty) {
1855        let (left, right) = (expected_arm(left), expected_arm(right));
1856        return {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&arm, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Either");
    ::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(&left, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::ToTokens::to_tokens(&right, &mut _s);
            _s
        });
    _s
}quote! { #arm::Either(&#left, &#right) };
1857    }
1858    if let Some(inner) =
1859        crate::type_inspect::option_inner_type(ty).or_else(|| unit_result_ok_type(ty))
1860    {
1861        let inner = expected_arm(inner);
1862        return {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&arm, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Nullable");
    ::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(&inner, &mut _s);
            _s
        });
    _s
}quote! { #arm::Nullable(&#inner) };
1863    }
1864    let noun = crate::type_inspect::r_value_noun(ty);
1865    let ty = crate::type_inspect::erase_lifetimes(ty);
1866    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&arm, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Opaque");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "declared");
            ::quote::__private::push_colon(&mut _s);
            ::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, "__MX_EXPECTATION");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "noun");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&noun, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    _s
}quote! {
1867        #arm::Opaque {
1868            declared: <#ty as ::miniextendr_api::TryFromSexp>::__MX_EXPECTATION,
1869            noun: #noun,
1870        }
1871    }
1872}
1873
1874/// Whether `ty` spells an `impl Trait` anywhere (`impl AsRef<str>`,
1875/// `Vec<impl Display>`).
1876fn names_impl_trait(ty: &syn::Type) -> bool {
1877    fn scan(tokens: TokenStream) -> bool {
1878        tokens.into_iter().any(|tt| match tt {
1879            proc_macro2::TokenTree::Ident(ident) => ident == "impl",
1880            proc_macro2::TokenTree::Group(group) => scan(group.stream()),
1881            _ => false,
1882        })
1883    }
1884    scan({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    _s
}quote! { #ty })
1885}
1886
1887/// `T` for a `Result<T, ()>` type, which reads `NULL` as `Err(())`.
1888fn unit_result_ok_type(ty: &syn::Type) -> Option<&syn::Type> {
1889    let syn::Type::Path(tp) = ty else {
1890        return None;
1891    };
1892    let seg = tp.path.segments.last()?;
1893    if seg.ident != "Result" {
1894        return None;
1895    }
1896    let ok = crate::type_inspect::first_type_argument(seg)?;
1897    match crate::type_inspect::second_type_argument(seg)? {
1898        syn::Type::Tuple(unit) if unit.elems.is_empty() => Some(ok),
1899        _ => None,
1900    }
1901}
1902
1903// endregion
1904
1905#[cfg(test)]
1906mod tests;