Skip to main content

miniextendr_macros/
newtype_derive.rs

1//! `#[derive(TryFromSexp)]` / `#[derive(IntoR)]` — forward R↔Rust conversions
2//! from a single-field newtype to its inner type. `#[derive(IsNA)]` uses
3//! the same parser to forward native missing-value detection.
4//!
5//! For a newtype `struct UserId(Uuid)` (or `struct UserId { inner: Uuid }`):
6//!
7//! - `#[derive(TryFromSexp)]` generates the R → Rust direction: a scalar
8//!   `TryFromSexp` impl that forwards to the inner type, plus a
9//!   `miniextendr_api::TryFromSexpElement` marker impl. The marker lets
10//!   the container blankets in `miniextendr_api::newtype` light up
11//!   `Vec<UserId>` / `Option<UserId>` / `Vec<Option<UserId>>` — see issues
12//!   #844 and #1766.
13//! - `#[derive(IntoR)]` generates the Rust → R direction: a scalar `IntoR` impl
14//!   that forwards to the inner type, plus
15//!   `miniextendr_api::IntoRNewtype` (for `Option` / `Vec<Option>`) and a
16//!   concrete `miniextendr_api::IntoRVecElement`
17//!   impl (for `Vec`).
18//!
19//! Direction is chosen by *which* derive you list. Some inner types are
20//! convertible in only one direction (a compiled `regex::Regex` reads from R
21//! but cannot be written back): derive only `TryFromSexp` for those.
22//!
23//! ```ignore
24//! #[derive(TryFromSexp)]            // R -> Rust only
25//! struct Pattern(regex::Regex);
26//!
27//! #[derive(TryFromSexp, IntoR)]     // round-trip
28//! struct UserId(uuid::Uuid);
29//! ```
30//!
31//! `#[derive(TryFromSexp)]` takes one attribute, on the struct:
32//! `#[try_from_sexp(validate = path::to::check)]`, with `check` a
33//! `fn(SEXP) -> Result<(), E>` and `E: Into<SexpError>` (an `RError` or any
34//! `RConditionData` type for a classed refusal). It becomes
35//! `TryFromSexpElement::check_sexp`, which the
36//! scalar impl and every container run on the R value before the inner type
37//! reads it (#1815). The scalar impl's error is then `SexpError`, so the inner
38//! type's error must convert into it.
39//!
40//! Do not derive both `IntoR` and `MatchArg` on the same type: both would feed
41//! the single `IntoR for Vec<T>` blanket slot and collide (E0119).
42
43use proc_macro2::TokenStream;
44use quote::quote;
45use syn::{Data, DeriveInput, Fields, Type};
46
47/// The single field of a newtype: its inner type plus how to wrap/unwrap it.
48struct Newtype {
49    inner: Type,
50    /// `Some(field_ident)` for named newtypes, `None` for tuple newtypes.
51    named_field: Option<syn::Ident>,
52}
53
54impl Newtype {
55    /// `Self(<val>)` or `Self { field: <val> }`.
56    fn wrap(&self, val: &TokenStream) -> TokenStream {
57        match &self.named_field {
58            Some(field) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "Self");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&field, &mut _s);
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&val, &mut _s);
            _s
        });
    _s
}quote! { Self { #field: #val } },
59            None => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "Self");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&val, &mut _s);
            _s
        });
    _s
}quote! { Self(#val) },
60        }
61    }
62
63    /// `<binding>.0` or `<binding>.field`.
64    fn unwrap(&self, binding: &TokenStream) -> TokenStream {
65        match &self.named_field {
66            Some(field) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&binding, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&field, &mut _s);
    _s
}quote! { #binding.#field },
67            None => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&binding, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::parse(&mut _s, "0");
    _s
}quote! { #binding.0 },
68        }
69    }
70}
71
72fn parse_newtype(input: &DeriveInput) -> syn::Result<Newtype> {
73    let data = match &input.data {
74        Data::Struct(data) => data,
75        _ => {
76            return Err(syn::Error::new_spanned(
77                &input.ident,
78                "this derive only works on single-field newtype structs",
79            ));
80        }
81    };
82    match &data.fields {
83        Fields::Unnamed(fields) if fields.unnamed.len() == 1 => Ok(Newtype {
84            inner: fields.unnamed.first().unwrap().ty.clone(),
85            named_field: None,
86        }),
87        Fields::Named(fields) if fields.named.len() == 1 => {
88            let field = fields.named.first().unwrap();
89            Ok(Newtype {
90                inner: field.ty.clone(),
91                named_field: Some(field.ident.clone().unwrap()),
92            })
93        }
94        _ => Err(syn::Error::new_spanned(
95            &input.ident,
96            "this derive requires a struct with exactly one field",
97        )),
98    }
99}
100
101/// Build a `where` clause that merges the struct's existing predicates with
102/// extra predicates (the `Inner: Trait` bounds the forwarding impl requires).
103fn where_with(base: &Option<syn::WhereClause>, extra: &[TokenStream]) -> TokenStream {
104    let mut preds: Vec<TokenStream> = base
105        .iter()
106        .flat_map(|w| w.predicates.iter().map(|p| {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&p, &mut _s);
    _s
}quote! { #p }))
107        .collect();
108    preds.extend(extra.iter().cloned());
109    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut preds, i) = preds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let preds =
                match preds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&preds, &mut _s);
        }
    }
    _s
}quote! { where #(#preds),* }
110}
111
112/// The `#[try_from_sexp(...)]` options of `#[derive(TryFromSexp)]`.
113#[derive(#[automatically_derived]
impl ::core::default::Default for TryFromSexpOptions {
    #[inline]
    fn default() -> Self {
        TryFromSexpOptions { validate: ::core::default::Default::default() }
    }
}Default)]
114struct TryFromSexpOptions {
115    /// `validate = path`: the newtype's `TryFromSexpElement::check_sexp`.
116    validate: Option<syn::Path>,
117}
118
119/// Read the struct's `#[try_from_sexp(...)]` attributes. The only key is
120/// `validate = path`; any other key, a repeated `validate`, or the attribute on
121/// the field is a spanned error.
122fn parse_try_from_sexp_options(input: &DeriveInput) -> syn::Result<TryFromSexpOptions> {
123    let mut options = TryFromSexpOptions::default();
124    for attr in input
125        .attrs
126        .iter()
127        .filter(|a| a.path().is_ident("try_from_sexp"))
128    {
129        attr.parse_nested_meta(|meta| {
130            if meta.path.is_ident("validate") {
131                if options.validate.is_some() {
132                    return Err(meta.error("duplicate `validate` in `#[try_from_sexp(...)]`"));
133                }
134                options.validate = Some(meta.value()?.parse()?);
135                Ok(())
136            } else {
137                Err(meta.error(
138                    "unknown `#[try_from_sexp(...)]` key; the only key is `validate = path::to::check`",
139                ))
140            }
141        })?;
142    }
143    if let Data::Struct(data) = &input.data {
144        for field in &data.fields {
145            if let Some(attr) = field
146                .attrs
147                .iter()
148                .find(|a| a.path().is_ident("try_from_sexp"))
149            {
150                return Err(syn::Error::new_spanned(
151                    attr,
152                    "`#[try_from_sexp(...)]` goes on the struct, not on its field",
153                ));
154            }
155        }
156    }
157    Ok(options)
158}
159
160/// `#[derive(TryFromSexp)]`: scalar forwarding `TryFromSexp` + `TryFromSexpElement` marker.
161///
162/// With `#[try_from_sexp(validate = path)]` the marker's `check_sexp` calls
163/// `path`, and the scalar impl runs it before the inner conversion, with
164/// `SexpError` as its error (the inner type's error converts into it).
165pub fn derive_try_from_sexp(input: DeriveInput) -> syn::Result<TokenStream> {
166    let nt = parse_newtype(&input)?;
167    let options = parse_try_from_sexp_options(&input)?;
168    let inner = &nt.inner;
169    let name = &input.ident;
170    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
171    let base_where = &input.generics.where_clause;
172
173    let wrap_val = nt.wrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "val");
    _s
}quote! { val });
174    let wrap_inner = nt.wrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "inner");
    _s
}quote! { inner });
175    let field = nt.unwrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    _s
}quote! { self });
176    let inner_converts = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TryFromSexp");
    _s
}quote! { #inner: ::miniextendr_api::TryFromSexp };
177    let inner_try_from = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&inner, &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");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "sexp");
            _s
        });
    _s
}quote! { <#inner as ::miniextendr_api::TryFromSexp>::try_from_sexp(sexp) };
178    let inner_try_from_unchecked = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "unsafe");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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_unchecked");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    _s
                });
            _s
        });
    _s
}quote! {
179        unsafe { <#inner as ::miniextendr_api::TryFromSexp>::try_from_sexp_unchecked(sexp) }
180    };
181
182    // Without `validate` the scalar impl is the inner type's, error and all.
183    // With it, the check runs first and both errors become `SexpError`, the
184    // error every container of the newtype has.
185    let (from_where, error, try_from, try_from_unchecked, check_sexp) = match &options.validate {
186        None => (
187            where_with(base_where, &[inner_converts]),
188            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TryFromSexp");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Error");
    _s
}quote! { <#inner as ::miniextendr_api::TryFromSexp>::Error },
189            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&inner_try_from, &mut _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_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "val");
            ::quote::__private::push_or(&mut _s);
            ::quote::ToTokens::to_tokens(&wrap_val, &mut _s);
            _s
        });
    _s
}quote! { #inner_try_from.map(|val| #wrap_val) },
190            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&inner_try_from_unchecked, &mut _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_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "val");
            ::quote::__private::push_or(&mut _s);
            ::quote::ToTokens::to_tokens(&wrap_val, &mut _s);
            _s
        });
    _s
}quote! { #inner_try_from_unchecked.map(|val| #wrap_val) },
191            TokenStream::new(),
192        ),
193        Some(validate) => {
194            let check = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Self");
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TryFromSexpElement");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "check_sexp");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "sexp");
            _s
        });
    ::quote::__private::push_question(&mut _s);
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
195                <Self as ::miniextendr_api::TryFromSexpElement>::check_sexp(sexp)?;
196            };
197            (
198                where_with(
199                    base_where,
200                    &[
201                        inner_converts,
202                        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TryFromSexp");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Error");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "convert");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Into");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "from_r");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SexpError");
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! {
203                            <#inner as ::miniextendr_api::TryFromSexp>::Error:
204                                ::core::convert::Into<::miniextendr_api::from_r::SexpError>
205                        },
206                    ],
207                ),
208                {
    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, "SexpError");
    _s
}quote! { ::miniextendr_api::from_r::SexpError },
209                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&check, &mut _s);
    ::quote::ToTokens::to_tokens(&inner_try_from, &mut _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_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "val");
            ::quote::__private::push_or(&mut _s);
            ::quote::ToTokens::to_tokens(&wrap_val, &mut _s);
            _s
        });
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map_err");
    ::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, "convert");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Into");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into");
            _s
        });
    _s
}quote! {
210                    #check
211                    #inner_try_from.map(|val| #wrap_val).map_err(::core::convert::Into::into)
212                },
213                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&check, &mut _s);
    ::quote::ToTokens::to_tokens(&inner_try_from_unchecked, &mut _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_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "val");
            ::quote::__private::push_or(&mut _s);
            ::quote::ToTokens::to_tokens(&wrap_val, &mut _s);
            _s
        });
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map_err");
    ::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, "convert");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Into");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into");
            _s
        });
    _s
}quote! {
214                    #check
215                    #inner_try_from_unchecked.map(|val| #wrap_val).map_err(::core::convert::Into::into)
216                },
217                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "inline");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "check_sexp");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "sexp");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "result");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Result");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_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, "SexpError");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&validate, &mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    _s
                });
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "map_err");
            ::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, "convert");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Into");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into");
                    _s
                });
            _s
        });
    _s
}quote! {
218                    #[inline]
219                    fn check_sexp(
220                        sexp: ::miniextendr_api::SEXP,
221                    ) -> ::core::result::Result<(), ::miniextendr_api::from_r::SexpError> {
222                        #validate(sexp).map_err(::core::convert::Into::into)
223                    }
224                },
225            )
226        }
227    };
228
229    // `__mx_has_na` forwards too, so `no_na` on a newtype of a reading marker
230    // (`struct Dose(AsNumeric)`) refuses what the marker reads as `NA`. So
231    // does `__mx_input_has_na`, so a newtype arm of an `Either` is checked as
232    // its inner type: `struct Table(DataFrame)` keeps its `NA` cells.
233    let expectation = expectation_const(inner);
234    Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TryFromSexp");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&from_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Error");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&error, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "NATIVE_BORROW");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "option");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Option");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "from_r");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "NativeBorrow");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "CHARACTER_ONLY");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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, "CHARACTER_ONLY");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "__MX_EXPECTATION");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "option");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Option");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_lifetime(&mut _s, "\'static");
            ::quote::__private::push_ident(&mut _s, "str");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&expectation, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "__mx_has_na");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &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_has_na");
                    ::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(&field, &mut _s);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "__mx_input_has_na");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "input");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "SEXP");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &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_input_has_na");
                    ::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(&field, &mut _s);
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "input");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "try_from_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "SEXP");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "result");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&error, &mut _s);
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&try_from, &mut _s);
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s,
                "try_from_sexp_unchecked");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "SEXP");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "result");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&error, &mut _s);
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&try_from_unchecked, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &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, "TryFromSexpElement");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&base_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Inner");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "from_inner");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inner");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&wrap_inner, &mut _s);
                    _s
                });
            ::quote::ToTokens::to_tokens(&check_sexp, &mut _s);
            _s
        });
    _s
}quote! {
235        #[automatically_derived]
236        impl #impl_generics ::miniextendr_api::TryFromSexp for #name #ty_generics #from_where {
237            type Error = #error;
238            const NATIVE_BORROW: ::core::option::Option<::miniextendr_api::from_r::NativeBorrow> =
239                <#inner as ::miniextendr_api::TryFromSexp>::NATIVE_BORROW;
240            const CHARACTER_ONLY: bool = <#inner as ::miniextendr_api::TryFromSexp>::CHARACTER_ONLY;
241            const __MX_EXPECTATION: ::core::option::Option<&'static str> = #expectation;
242            #[inline]
243            fn __mx_has_na(&self) -> bool {
244                <#inner as ::miniextendr_api::TryFromSexp>::__mx_has_na(&#field)
245            }
246            #[inline]
247            fn __mx_input_has_na(&self, input: ::miniextendr_api::SEXP) -> bool {
248                <#inner as ::miniextendr_api::TryFromSexp>::__mx_input_has_na(&#field, input)
249            }
250            #[inline]
251            fn try_from_sexp(sexp: ::miniextendr_api::SEXP) -> ::core::result::Result<Self, #error> {
252                #try_from
253            }
254            #[inline]
255            unsafe fn try_from_sexp_unchecked(sexp: ::miniextendr_api::SEXP) -> ::core::result::Result<Self, #error> {
256                #try_from_unchecked
257            }
258        }
259
260        #[automatically_derived]
261        impl #impl_generics ::miniextendr_api::TryFromSexpElement for #name #ty_generics #base_where {
262            type Inner = #inner;
263            #[inline]
264            fn from_inner(inner: #inner) -> Self {
265                #wrap_inner
266            }
267            #check_sexp
268        }
269    })
270}
271
272/// The newtype's `TryFromSexp::__MX_EXPECTATION`: what an argument of the
273/// inner type must be, in R terms, so a newtype parameter or `Either` arm
274/// reads as its inner type does (`struct Dose(AsNumeric)`: `a single
275/// number`). The macro's own wording when it knows the inner type
276/// ([`crate::r_preconditions::conversion_expectation`]), else the inner
277/// type's constant, which a newtype of a newtype carries through.
278fn expectation_const(inner: &Type) -> TokenStream {
279    match crate::r_preconditions::conversion_expectation(inner, false) {
280        Some(expected) => {
    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(&expected, &mut _s);
            _s
        });
    _s
}quote! { ::core::option::Option::Some(#expected) },
281        None => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&inner, &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");
    _s
}quote! { <#inner as ::miniextendr_api::TryFromSexp>::__MX_EXPECTATION },
282    }
283}
284
285/// `#[derive(IsNA)]`: delegate native missing-value detection to the field.
286pub fn derive_is_na(input: DeriveInput) -> syn::Result<TokenStream> {
287    let nt = parse_newtype(&input)?;
288    let inner = &nt.inner;
289    let name = &input.ident;
290    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
291    let is_na_where = where_with(
292        &input.generics.where_clause,
293        &[
294            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "IsNA");
    _s
}quote! { #inner: ::miniextendr_api::IsNA },
295            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "Self");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "RNativeType");
    _s
}quote! { Self: ::miniextendr_api::RNativeType },
296        ],
297    );
298    let value = nt.unwrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    _s
}quote! { self });
299
300    Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &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, "IsNA");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&is_na_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "is_na");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &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, "IsNA");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "is_na");
                    ::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(&value, &mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
301        #[automatically_derived]
302        impl #impl_generics ::miniextendr_api::IsNA for #name #ty_generics #is_na_where {
303            #[inline]
304            fn is_na(&self) -> bool {
305                <#inner as ::miniextendr_api::IsNA>::is_na(&#value)
306            }
307        }
308    })
309}
310
311/// `#[derive(IntoR)]`: scalar forwarding `IntoR` + `IntoRNewtype` marker (for
312/// `Option`/`Vec<Option>` blankets) + concrete `IntoRVecElement` (for `Vec`).
313pub fn derive_into_r(input: DeriveInput) -> syn::Result<TokenStream> {
314    let nt = parse_newtype(&input)?;
315    let inner = &nt.inner;
316    let name = &input.ident;
317    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
318    let base_where = &input.generics.where_clause;
319
320    let unwrap_self = nt.unwrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    _s
}quote! { self });
321    let unwrap_v = nt.unwrap(&{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "v");
    _s
}quote! { v });
322    let into_where = where_with(base_where, &[{
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "IntoR");
    _s
}quote! { #inner: ::miniextendr_api::IntoR }]);
323    // The Vec element impl forwards to `Vec<Inner>: IntoR`; gate it on that so a
324    // newtype whose inner lacks a vector conversion still gets the scalar IntoR.
325    let vec_elem_where = where_with(
326        base_where,
327        &[{
    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, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "IntoR");
    _s
}quote! { ::std::vec::Vec<#inner>: ::miniextendr_api::IntoR }],
328    );
329
330    Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "IntoR");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&into_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Error");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Error");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "try_into_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "result");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Error");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "try_into_sexp");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&unwrap_self, &mut _s);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s,
                "try_into_sexp_unchecked");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "result");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Error");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "unsafe");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "try_into_sexp_unchecked");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::ToTokens::to_tokens(&unwrap_self, &mut _s);
                                    _s
                                });
                            _s
                        });
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "into_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into_sexp");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&unwrap_self, &mut _s);
                            _s
                        });
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "into_sexp_unchecked");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "unsafe");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&inner, &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, "IntoR");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "into_sexp_unchecked");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::ToTokens::to_tokens(&unwrap_self, &mut _s);
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &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, "IntoRNewtype");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&base_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Inner");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "into_inner");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&unwrap_self, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "automatically_derived");
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &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, "IntoRVecElement");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&vec_elem_where, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "elements_into_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "values");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "vec");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Vec");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Self");
                    ::quote::__private::push_gt(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "SEXP");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_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, "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, &mut _s);
                    ::quote::__private::push_gt(&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, "IntoR");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into_sexp");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "values");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "into_iter");
                            ::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_or(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "v");
                                    ::quote::__private::push_or(&mut _s);
                                    ::quote::ToTokens::to_tokens(&unwrap_v, &mut _s);
                                    _s
                                });
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "collect");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "std");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "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, &mut _s);
                            ::quote::__private::push_shr(&mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                ::quote::__private::TokenStream::new());
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
331        #[automatically_derived]
332        impl #impl_generics ::miniextendr_api::IntoR for #name #ty_generics #into_where {
333            type Error = <#inner as ::miniextendr_api::IntoR>::Error;
334            #[inline]
335            fn try_into_sexp(self) -> ::core::result::Result<::miniextendr_api::SEXP, <#inner as ::miniextendr_api::IntoR>::Error> {
336                <#inner as ::miniextendr_api::IntoR>::try_into_sexp(#unwrap_self)
337            }
338            #[inline]
339            unsafe fn try_into_sexp_unchecked(self) -> ::core::result::Result<::miniextendr_api::SEXP, <#inner as ::miniextendr_api::IntoR>::Error> {
340                unsafe { <#inner as ::miniextendr_api::IntoR>::try_into_sexp_unchecked(#unwrap_self) }
341            }
342            #[inline]
343            fn into_sexp(self) -> ::miniextendr_api::SEXP {
344                <#inner as ::miniextendr_api::IntoR>::into_sexp(#unwrap_self)
345            }
346            #[inline]
347            unsafe fn into_sexp_unchecked(self) -> ::miniextendr_api::SEXP {
348                unsafe { <#inner as ::miniextendr_api::IntoR>::into_sexp_unchecked(#unwrap_self) }
349            }
350        }
351
352        #[automatically_derived]
353        impl #impl_generics ::miniextendr_api::IntoRNewtype for #name #ty_generics #base_where {
354            type Inner = #inner;
355            #[inline]
356            fn into_inner(self) -> #inner {
357                #unwrap_self
358            }
359        }
360
361        #[automatically_derived]
362        impl #impl_generics ::miniextendr_api::IntoRVecElement for #name #ty_generics #vec_elem_where {
363            #[inline]
364            fn elements_into_sexp(values: ::std::vec::Vec<Self>) -> ::miniextendr_api::SEXP {
365                <::std::vec::Vec<#inner> as ::miniextendr_api::IntoR>::into_sexp(
366                    values.into_iter().map(|v| #unwrap_v).collect::<::std::vec::Vec<#inner>>()
367                )
368            }
369        }
370    })
371}
372
373#[cfg(test)]
374mod tests {
375    /// `#[try_from_sexp(validate = path)]` gives the element marker a
376    /// `check_sexp` that calls the path, and the scalar impl runs it before
377    /// the inner conversion, with `SexpError` as its error. Without the
378    /// attribute the scalar impl keeps the inner error and no check is
379    /// emitted (the trait's default accepts every value).
380    #[test]
381    fn try_from_sexp_derive_validate_emits_the_check() {
382        let validated = super::derive_try_from_sexp(syn::parse_quote! {
383            #[try_from_sexp(validate = checks::plain_number)]
384            struct Duration(f64);
385        })
386        .unwrap()
387        .to_string();
388        assert!(
389            validated.contains(
390                "fn check_sexp (sexp : :: miniextendr_api :: SEXP ,) -> :: core :: result :: Result < () , :: miniextendr_api :: from_r :: SexpError > { checks :: plain_number (sexp) . map_err (:: core :: convert :: Into :: into) }"
391            ),
392            "{validated}"
393        );
394        assert!(
395            validated.contains("type Error = :: miniextendr_api :: from_r :: SexpError ;"),
396            "{validated}"
397        );
398        assert!(
399            validated.contains(
400                "< f64 as :: miniextendr_api :: TryFromSexp > :: Error : :: core :: convert :: Into < :: miniextendr_api :: from_r :: SexpError >"
401            ),
402            "{validated}"
403        );
404        // Both scalar paths run the check first.
405        let check = "< Self as :: miniextendr_api :: TryFromSexpElement > :: check_sexp (sexp) ? ;";
406        assert_eq!(validated.matches(check).count(), 2, "{validated}");
407
408        let plain = super::derive_try_from_sexp(syn::parse_quote! { struct Duration(f64); })
409            .unwrap()
410            .to_string();
411        assert!(!plain.contains("check_sexp"), "{plain}");
412        assert!(
413            plain.contains("type Error = < f64 as :: miniextendr_api :: TryFromSexp > :: Error ;"),
414            "{plain}"
415        );
416    }
417
418    /// `validate` is the only key, given once, and only on the struct.
419    #[test]
420    fn try_from_sexp_derive_rejects_bad_options() {
421        let error = |input: syn::DeriveInput| {
422            super::derive_try_from_sexp(input)
423                .expect_err("the options should be refused")
424                .to_string()
425        };
426        assert!(
427            error(syn::parse_quote! {
428                #[try_from_sexp(check = plain_number)]
429                struct Duration(f64);
430            })
431            .contains("unknown `#[try_from_sexp(...)]` key")
432        );
433        assert!(
434            error(syn::parse_quote! {
435                #[try_from_sexp(validate = a, validate = b)]
436                struct Duration(f64);
437            })
438            .contains("duplicate `validate`")
439        );
440        assert!(
441            error(syn::parse_quote! {
442                struct Duration(#[try_from_sexp(validate = a)] f64);
443            })
444            .contains("goes on the struct")
445        );
446    }
447
448    /// `#[derive(TryFromSexp)]` forwards the hidden `no_na` probes to the
449    /// inner type, for tuple and named newtypes alike: `__mx_has_na` for the
450    /// value, and `__mx_input_has_na` for the input of an `Either` arm.
451    #[test]
452    fn try_from_sexp_derive_forwards_no_na() {
453        for (input, field) in [
454            (syn::parse_quote! { struct Table(DataFrame); }, "self . 0"),
455            (
456                syn::parse_quote! { struct Table { value: DataFrame } },
457                "self . value",
458            ),
459        ] {
460            let out = super::derive_try_from_sexp(input).unwrap().to_string();
461            let forward = |call: &str| {
462                format!("< DataFrame as :: miniextendr_api :: TryFromSexp > :: {call}")
463            };
464            assert!(out.contains("fn __mx_has_na (& self) -> bool"), "{out}");
465            assert!(
466                out.contains(&forward(&format!("__mx_has_na (& {field})"))),
467                "{out}"
468            );
469            assert!(
470                out.contains(
471                    "fn __mx_input_has_na (& self , input : :: miniextendr_api :: SEXP) -> bool"
472                ),
473                "{out}"
474            );
475            assert!(
476                out.contains(&forward(&format!("__mx_input_has_na (& {field} , input)"))),
477                "{out}"
478            );
479        }
480    }
481
482    /// `#[derive(TryFromSexp)]` declares the inner type's R-facing
483    /// expectation: the macro's wording for an inner type it knows, else the
484    /// inner type's own constant (a newtype of a newtype, a generic newtype).
485    #[test]
486    fn try_from_sexp_derive_declares_the_inner_expectation() {
487        let expectation = |input: syn::DeriveInput| {
488            let out = super::derive_try_from_sexp(input).unwrap().to_string();
489            let start = out
490                .find("const __MX_EXPECTATION")
491                .unwrap_or_else(|| panic!("no expectation constant: {out}"));
492            let end = start + out[start..].find(';').unwrap();
493            out[start..end].trim_end().to_string()
494        };
495        let declares = |text: &str| {
496            format!(
497                "const __MX_EXPECTATION : :: core :: option :: Option < & 'static str > = \
498                 :: core :: option :: Option :: Some ({text:?})"
499            )
500        };
501        assert_eq!(
502            expectation(syn::parse_quote! { struct Dose(AsNumeric); }),
503            declares("a single number")
504        );
505        assert_eq!(
506            expectation(syn::parse_quote! { struct Numbers { values: AsNumericVec } }),
507            declares("numeric")
508        );
509        assert_eq!(
510            expectation(syn::parse_quote! { struct Table(DataFrame); }),
511            declares("a data frame")
512        );
513        for (input, inner) in [
514            (syn::parse_quote! { struct Wrapped(Table); }, "Table"),
515            (syn::parse_quote! { struct Id(Uuid); }, "Uuid"),
516            (syn::parse_quote! { struct Any<T>(T); }, "T"),
517        ] {
518            assert_eq!(
519                expectation(input),
520                format!(
521                    "const __MX_EXPECTATION : :: core :: option :: Option < & 'static str > = \
522                     < {inner} as :: miniextendr_api :: TryFromSexp > :: __MX_EXPECTATION"
523                )
524            );
525        }
526    }
527}