Skip to main content

miniextendr_macros/
typed_dataframe.rs

1//! Parser and expansion for the `typed_dataframe!` macro.
2//!
3//! Generates a struct that wraps an R `data.frame`, validates declared
4//! columns via `TryFromSexp`, and exposes borrowed per-column accessors.
5//!
6//! # Syntax
7//!
8//! ```ignore
9//! typed_dataframe! {
10//!     /// The shape we accept for the Theoph PK dataset.
11//!     pub TheophDf {
12//!         subject: i32,
13//!         weight: f64,
14//!         dose: f64,
15//!         flag: Option<i32>,   // optional column
16//!     }
17//! }
18//! ```
19//!
20//! Expands to a struct `TheophDf` with `TryFromSexp` and per-column
21//! accessors (`subject() -> &[i32]`, `flag() -> Option<&[i32]>`).
22
23use proc_macro2::TokenStream;
24use quote::{format_ident, quote};
25use syn::parse::{Parse, ParseStream};
26use syn::punctuated::Punctuated;
27use syn::{Attribute, Ident, Token, Type, TypePath, Visibility};
28
29/// Parsed input for `typed_dataframe!`.
30pub struct TypedDataframeInput {
31    /// Outer attributes (doc comments etc.) on the struct.
32    pub attrs: Vec<Attribute>,
33    /// Visibility (e.g. `pub`).
34    pub vis: Visibility,
35    /// Struct name.
36    pub name: Ident,
37    /// Declared columns.
38    pub fields: Vec<TypedDataframeField>,
39    /// If `false`, the input data.frame may not have extra (un-declared) columns.
40    /// Default is `true`. Toggle with leading `@exact;` prefix.
41    pub allow_extra: bool,
42}
43
44/// A single column declaration.
45pub struct TypedDataframeField {
46    /// Field attributes (doc comments etc.).
47    pub attrs: Vec<Attribute>,
48    /// Column name (as used in R `names(df)`).
49    pub name: Ident,
50    /// Element type (e.g. `i32`, `f64`).
51    pub elem_ty: Type,
52    /// True if the field was declared `Option<T>` (column may be absent).
53    pub optional: bool,
54}
55
56impl Parse for TypedDataframeInput {
57    fn parse(input: ParseStream) -> syn::Result<Self> {
58        // Optional @exact; prefix for strict mode.
59        let allow_extra = if input.peek(::syn::token::AtToken![@]) {
60            input.parse::<::syn::token::AtToken![@]>()?;
61            let mode: Ident = input.parse()?;
62            if mode != "exact" {
63                return Err(syn::Error::new_spanned(
64                    mode,
65                    "expected `exact` after @; use `@exact;` for strict mode",
66                ));
67            }
68            input.parse::<::syn::token::SemiToken![;]>()?;
69            false
70        } else {
71            true
72        };
73
74        // Parse outer attributes (doc comments etc.).
75        let attrs = input.call(Attribute::parse_outer)?;
76
77        // Visibility (pub, pub(crate), or nothing).
78        let vis: Visibility = input.parse()?;
79
80        // Struct name.
81        let name: Ident = input.parse()?;
82
83        // Brace-delimited field list.
84        let content;
85        match ::syn::__private::parse_braces(&input) {
    ::syn::__private::Ok(braces) => {
        content = braces.content;
        _ = content;
        braces.token
    }
    ::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::braced!(content in input);
86
87        let fields_punct: Punctuated<TypedDataframeField, ::syn::token::CommaToken![,]> =
88            Punctuated::parse_terminated(&content)?;
89        let fields: Vec<TypedDataframeField> = fields_punct.into_iter().collect();
90
91        if fields.is_empty() {
92            return Err(syn::Error::new(
93                name.span(),
94                "typed_dataframe! requires at least one column declaration",
95            ));
96        }
97
98        Ok(TypedDataframeInput {
99            attrs,
100            vis,
101            name,
102            fields,
103            allow_extra,
104        })
105    }
106}
107
108impl Parse for TypedDataframeField {
109    fn parse(input: ParseStream) -> syn::Result<Self> {
110        let attrs = input.call(Attribute::parse_outer)?;
111        let name: Ident = input.parse()?;
112        input.parse::<::syn::token::ColonToken![:]>()?;
113        let ty: Type = input.parse()?;
114
115        // Detect `Option<T>` and unwrap to the inner type.
116        let (elem_ty, optional) = match unwrap_option(&ty) {
117            Some(inner) => (inner, true),
118            None => (ty, false),
119        };
120
121        Ok(TypedDataframeField {
122            attrs,
123            name,
124            elem_ty,
125            optional,
126        })
127    }
128}
129
130/// If `ty` is `Option<T>`, return `T`; otherwise `None`.
131fn unwrap_option(ty: &Type) -> Option<Type> {
132    let Type::Path(TypePath { qself: None, path }) = ty else {
133        return None;
134    };
135    // Must be exactly `Option<...>` (last segment) — we don't try to verify
136    // the full path because users may write `std::option::Option<T>`.
137    let segment = path.segments.last()?;
138    if segment.ident != "Option" {
139        return None;
140    }
141    let syn::PathArguments::AngleBracketed(args) = &segment.arguments else {
142        return None;
143    };
144    if args.args.len() != 1 {
145        return None;
146    }
147    let syn::GenericArgument::Type(inner) = args.args.first()? else {
148        return None;
149    };
150    Some(inner.clone())
151}
152
153/// Expand a parsed `typed_dataframe!` into the generated struct, impls, and
154/// per-column accessors.
155pub fn expand_typed_dataframe(input: TypedDataframeInput) -> TokenStream {
156    let TypedDataframeInput {
157        attrs,
158        vis,
159        name,
160        fields,
161        allow_extra,
162    } = input;
163
164    let struct_name_str = name.to_string();
165
166    // Per-field generated bits.
167    let col_fields = fields.iter().map(|f| {
168        let col_ident = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(&f.name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}_col", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}_col", crate::naming::unraw(&f.name));
169        if f.optional {
170            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&col_ident, &mut _s);
    ::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, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SEXP");
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! { #col_ident: ::std::option::Option<::miniextendr_api::SEXP> }
171        } else {
172            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&col_ident, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SEXP");
    _s
}quote! { #col_ident: ::miniextendr_api::SEXP }
173        }
174    });
175
176    let accessors = fields.iter().map(|f| {
177        let method_ident = &f.name;
178        let col_ident = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(&f.name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}_col", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}_col", crate::naming::unraw(&f.name));
179        let elem_ty = &f.elem_ty;
180        let method_attrs = &f.attrs;
181        if f.optional {
182            {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut method_attrs, i) = method_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let method_attrs =
                match method_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&method_attrs, &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, "pub");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&method_ident, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::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, "std");
    ::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_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
            _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::__private::push_ident(&mut _s, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::ToTokens::to_tokens(&col_ident, &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, "col");
                    ::quote::__private::push_or(&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_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "len");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "self");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "nrow");
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "ptr");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&elem_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, "RNativeType");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "dataptr_mut");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "col");
                                    _s
                                });
                            ::quote::__private::push_ident(&mut _s, "as");
                            ::quote::__private::push_star(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "const");
                            ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "if");
                            ::quote::__private::push_ident(&mut _s, "len");
                            ::quote::__private::push_eq_eq(&mut _s);
                            ::quote::__private::parse(&mut _s, "0");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_and(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Bracket,
                                        ::quote::__private::TokenStream::new());
                                    _s
                                });
                            ::quote::__private::push_ident(&mut _s, "else");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "std");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "slice");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "from_raw_parts");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "ptr");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "len");
                                            _s
                                        });
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
183                #(#method_attrs)*
184                #[inline]
185                pub fn #method_ident(&self) -> ::std::option::Option<&[#elem_ty]> {
186                    self.#col_ident.map(|col| unsafe {
187                        let len = self.nrow;
188                        let ptr = <#elem_ty as ::miniextendr_api::RNativeType>::dataptr_mut(col)
189                            as *const #elem_ty;
190                        if len == 0 { &[] } else { ::std::slice::from_raw_parts(ptr, len) }
191                    })
192                }
193            }
194        } else {
195            {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut method_attrs, i) = method_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let method_attrs =
                match method_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&method_attrs, &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, "pub");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&method_ident, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "self");
            _s
        });
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
            _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_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "len");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "nrow");
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "ptr");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&elem_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, "RNativeType");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "dataptr_mut");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "self");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::ToTokens::to_tokens(&col_ident, &mut _s);
                            _s
                        });
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_star(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "const");
                    ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "if");
                    ::quote::__private::push_ident(&mut _s, "len");
                    ::quote::__private::push_eq_eq(&mut _s);
                    ::quote::__private::parse(&mut _s, "0");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_and(&mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Bracket,
                                ::quote::__private::TokenStream::new());
                            _s
                        });
                    ::quote::__private::push_ident(&mut _s, "else");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "std");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "slice");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "from_raw_parts");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "ptr");
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "len");
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
196                #(#method_attrs)*
197                #[inline]
198                pub fn #method_ident(&self) -> &[#elem_ty] {
199                    unsafe {
200                        let len = self.nrow;
201                        let ptr = <#elem_ty as ::miniextendr_api::RNativeType>::dataptr_mut(self.#col_ident)
202                            as *const #elem_ty;
203                        if len == 0 { &[] } else { ::std::slice::from_raw_parts(ptr, len) }
204                    }
205                }
206            }
207        }
208    });
209
210    // Per-field validation: walk each declared column, batch errors.
211    let validation_locals = fields.iter().map(|f| {
212        let col_ident = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(&f.name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}_col", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}_col", crate::naming::unraw(&f.name));
213        let name_str = crate::naming::ident_name(&f.name);
214        let elem_ty = &f.elem_ty;
215        if f.optional {
216            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::ToTokens::to_tokens(&col_ident, &mut _s);
    ::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, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SEXP");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_eq(&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, "match");
            ::quote::__private::push_ident(&mut _s, "view");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "column_raw");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&name_str, &mut _s);
                    _s
                });
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    ::quote::__private::push_fat_arrow(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    ::quote::__private::push_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, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Some");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "col");
                            _s
                        });
                    ::quote::__private::push_fat_arrow(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "actual");
                            ::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, "SexpExt");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "type_of");
                            ::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, "col");
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "expected");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&elem_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, "RNativeType");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "SEXP_TYPE");
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "if");
                            ::quote::__private::push_ident(&mut _s, "actual");
                            ::quote::__private::push_ne(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "expected");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "__errs");
                                    ::quote::__private::push_dot(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "push");
                                    ::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, "format");
                                            ::quote::__private::push_bang(&mut _s);
                                            ::quote::__private::push_group(&mut _s,
                                                ::quote::__private::Delimiter::Parenthesis,
                                                {
                                                    let mut _s = ::quote::__private::TokenStream::new();
                                                    ::quote::__private::parse(&mut _s,
                                                        "\"column `{}`: expected {} ({:?}), got {:?}\"");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::ToTokens::to_tokens(&name_str, &mut _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, "stringify");
                                                    ::quote::__private::push_bang(&mut _s);
                                                    ::quote::__private::push_group(&mut _s,
                                                        ::quote::__private::Delimiter::Parenthesis,
                                                        {
                                                            let mut _s = ::quote::__private::TokenStream::new();
                                                            ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
                                                            _s
                                                        });
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "expected");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "actual");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    _s
                                                });
                                            _s
                                        });
                                    ::quote::__private::push_semi(&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, "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::__private::push_ident(&mut _s, "else");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "std");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "option");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "Option");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "Some");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "col");
                                            _s
                                        });
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
217                let #col_ident: ::std::option::Option<::miniextendr_api::SEXP> = {
218                    match view.column_raw(#name_str) {
219                        ::std::option::Option::None => ::std::option::Option::None,
220                        ::std::option::Option::Some(col) => {
221                            let actual = ::miniextendr_api::SexpExt::type_of(&col);
222                            let expected = <#elem_ty as ::miniextendr_api::RNativeType>::SEXP_TYPE;
223                            if actual != expected {
224                                __errs.push(::std::format!(
225                                    "column `{}`: expected {} ({:?}), got {:?}",
226                                    #name_str,
227                                    ::std::stringify!(#elem_ty),
228                                    expected,
229                                    actual,
230                                ));
231                                ::std::option::Option::None
232                            } else {
233                                ::std::option::Option::Some(col)
234                            }
235                        }
236                    }
237                };
238            }
239        } else {
240            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::ToTokens::to_tokens(&col_ident, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "SEXP");
    ::quote::__private::push_eq(&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, "match");
            ::quote::__private::push_ident(&mut _s, "view");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "column_raw");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&name_str, &mut _s);
                    _s
                });
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    ::quote::__private::push_fat_arrow(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "__errs");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "push");
                            ::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, "format");
                                    ::quote::__private::push_bang(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::parse(&mut _s,
                                                "\"missing required column `{}` (expected {} / {:?})\"");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::ToTokens::to_tokens(&name_str, &mut _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, "stringify");
                                            ::quote::__private::push_bang(&mut _s);
                                            ::quote::__private::push_group(&mut _s,
                                                ::quote::__private::Delimiter::Parenthesis,
                                                {
                                                    let mut _s = ::quote::__private::TokenStream::new();
                                                    ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
                                                    _s
                                                });
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_lt(&mut _s);
                                            ::quote::ToTokens::to_tokens(&elem_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, "RNativeType");
                                            ::quote::__private::push_gt(&mut _s);
                                            ::quote::__private::push_colon2(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "SEXP_TYPE");
                                            ::quote::__private::push_comma(&mut _s);
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&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_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "nil");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                ::quote::__private::TokenStream::new());
                            _s
                        });
                    ::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, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Some");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "col");
                            _s
                        });
                    ::quote::__private::push_fat_arrow(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "actual");
                            ::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, "SexpExt");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "type_of");
                            ::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, "col");
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "expected");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&elem_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, "RNativeType");
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "SEXP_TYPE");
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "if");
                            ::quote::__private::push_ident(&mut _s, "actual");
                            ::quote::__private::push_ne(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "expected");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "__errs");
                                    ::quote::__private::push_dot(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "push");
                                    ::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, "format");
                                            ::quote::__private::push_bang(&mut _s);
                                            ::quote::__private::push_group(&mut _s,
                                                ::quote::__private::Delimiter::Parenthesis,
                                                {
                                                    let mut _s = ::quote::__private::TokenStream::new();
                                                    ::quote::__private::parse(&mut _s,
                                                        "\"column `{}`: expected {} ({:?}), got {:?}\"");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::ToTokens::to_tokens(&name_str, &mut _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, "stringify");
                                                    ::quote::__private::push_bang(&mut _s);
                                                    ::quote::__private::push_group(&mut _s,
                                                        ::quote::__private::Delimiter::Parenthesis,
                                                        {
                                                            let mut _s = ::quote::__private::TokenStream::new();
                                                            ::quote::ToTokens::to_tokens(&elem_ty, &mut _s);
                                                            _s
                                                        });
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "expected");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "actual");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    _s
                                                });
                                            _s
                                        });
                                    ::quote::__private::push_semi(&mut _s);
                                    _s
                                });
                            ::quote::__private::push_ident(&mut _s, "col");
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
241                let #col_ident: ::miniextendr_api::SEXP = {
242                    match view.column_raw(#name_str) {
243                        ::std::option::Option::None => {
244                            __errs.push(::std::format!(
245                                "missing required column `{}` (expected {} / {:?})",
246                                #name_str,
247                                ::std::stringify!(#elem_ty),
248                                <#elem_ty as ::miniextendr_api::RNativeType>::SEXP_TYPE,
249                            ));
250                            ::miniextendr_api::SEXP::nil()
251                        }
252                        ::std::option::Option::Some(col) => {
253                            let actual = ::miniextendr_api::SexpExt::type_of(&col);
254                            let expected = <#elem_ty as ::miniextendr_api::RNativeType>::SEXP_TYPE;
255                            if actual != expected {
256                                __errs.push(::std::format!(
257                                    "column `{}`: expected {} ({:?}), got {:?}",
258                                    #name_str,
259                                    ::std::stringify!(#elem_ty),
260                                    expected,
261                                    actual,
262                                ));
263                            }
264                            col
265                        }
266                    }
267                };
268            }
269        }
270    });
271
272    let col_idents = fields
273        .iter()
274        .map(|f| match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(&f.name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}_col", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}_col", crate::naming::unraw(&f.name)));
275    let col_idents_for_struct = col_idents.clone();
276
277    let declared_names: Vec<String> = fields
278        .iter()
279        .map(|f| crate::naming::ident_name(&f.name))
280        .collect();
281    let declared_count = fields.len();
282    let allow_extra_check = if allow_extra {
283        ::quote::__private::TokenStream::new();quote! {}
284    } else {
285        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "const");
    ::quote::__private::push_ident(&mut _s, "__DECLARED");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "str");
            _s
        });
    ::quote::__private::push_eq(&mut _s);
    ::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 declared_names, i) =
                    declared_names.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let declared_names =
                        match declared_names.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&declared_names, &mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "mut");
    ::quote::__private::push_ident(&mut _s, "__extras");
    ::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_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);
    ::quote::__private::push_eq(&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_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "new");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_semi(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_ident(&mut _s, "col_name");
    ::quote::__private::push_ident(&mut _s, "in");
    ::quote::__private::push_ident(&mut _s, "view");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "names");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "if");
            ::quote::__private::push_bang(&mut _s);
            ::quote::__private::push_ident(&mut _s, "__DECLARED");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "contains");
            ::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, "col_name");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "as_str");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    _s
                });
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "__extras");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "push");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "col_name");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "to_string");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                ::quote::__private::TokenStream::new());
                            _s
                        });
                    ::quote::__private::push_semi(&mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "if");
    ::quote::__private::push_bang(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__extras");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "is_empty");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "__errs");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "push");
            ::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, "format");
                    ::quote::__private::push_bang(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::parse(&mut _s,
                                "\"unexpected extra columns: {:?}\"");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "__extras");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            _s
        });
    _s
}quote! {
286            // Strict mode: reject any column not declared.
287            const __DECLARED: &[&str] = &[#( #declared_names ),*];
288            let mut __extras: ::std::vec::Vec<::std::string::String> = ::std::vec::Vec::new();
289            for col_name in view.names() {
290                if !__DECLARED.contains(&col_name.as_str()) {
291                    __extras.push(col_name.to_string());
292                }
293            }
294            if !__extras.is_empty() {
295                __errs.push(::std::format!(
296                    "unexpected extra columns: {:?}",
297                    __extras
298                ));
299            }
300        }
301    };
302
303    {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut attrs, i) = attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let attrs =
                match attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&attrs, &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, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "non_snake_case");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&vis, &mut _s);
    ::quote::__private::push_ident(&mut _s, "struct");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "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);
            ::quote::__private::push_ident(&mut _s, "nrow");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "usize");
            ::quote::__private::push_comma(&mut _s);
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut col_fields, i) = col_fields.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let col_fields =
                        match col_fields.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&col_fields, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "doc");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s,
                        "r\" Number of rows in the underlying data.frame.\"");
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "pub");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "nrow");
            ::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, "usize");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "nrow");
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "doc");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s,
                        "r\" Number of declared columns.\"");
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "pub");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "ncol");
            ::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, "usize");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&declared_count, &mut _s);
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "doc");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::parse(&mut _s,
                        "r\" The backing SEXP (preserves the data.frame class attribute).\"");
                    _s
                });
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "inline");
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "pub");
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "as_sexp");
            ::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_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, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    _s
                });
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut accessors, i) = accessors.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let accessors =
                        match accessors.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&accessors, &mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "from_r");
    ::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::__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_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_semi(&mut _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");
                    ::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, "std");
            ::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::__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::__private::push_ident(&mut _s, "use");
                    ::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, "SexpExt");
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_underscore(&mut _s);
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "if");
                    ::quote::__private::push_bang(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "sexp");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "is_data_frame");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "return");
                            ::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, "result");
                            ::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, "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, "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_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "InvalidValue");
                                    ::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, "format");
                                            ::quote::__private::push_bang(&mut _s);
                                            ::quote::__private::push_group(&mut _s,
                                                ::quote::__private::Delimiter::Parenthesis,
                                                {
                                                    let mut _s = ::quote::__private::TokenStream::new();
                                                    ::quote::__private::parse(&mut _s,
                                                        "\"{}: expected a data.frame, got {:?}\"");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::ToTokens::to_tokens(&struct_name_str, &mut _s);
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "sexp");
                                                    ::quote::__private::push_dot(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "type_of");
                                                    ::quote::__private::push_group(&mut _s,
                                                        ::quote::__private::Delimiter::Parenthesis,
                                                        ::quote::__private::TokenStream::new());
                                                    ::quote::__private::push_comma(&mut _s);
                                                    _s
                                                });
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            _s
                        });
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "view");
                    ::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, "dataframe");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "DataFrame");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "from_sexp");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__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_or(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "e");
                            ::quote::__private::push_or(&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_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "InvalidValue");
                            ::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, "format");
                                    ::quote::__private::push_bang(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::parse(&mut _s, "\"{}: {}\"");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::ToTokens::to_tokens(&struct_name_str, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "e");
                                            _s
                                        });
                                    _s
                                });
                            _s
                        });
                    ::quote::__private::push_question(&mut _s);
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "nrow");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "view");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "nrow");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "mut");
                    ::quote::__private::push_ident(&mut _s, "__errs");
                    ::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_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);
                    ::quote::__private::push_eq(&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_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "new");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_semi(&mut _s);
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut validation_locals, i) =
                            validation_locals.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let validation_locals =
                                match validation_locals.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&validation_locals, &mut _s);
                        }
                    }
                    ::quote::ToTokens::to_tokens(&allow_extra_check, &mut _s);
                    ::quote::__private::push_ident(&mut _s, "if");
                    ::quote::__private::push_bang(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__errs");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "is_empty");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "return");
                            ::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, "result");
                            ::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, "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, "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_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "InvalidValue");
                                    ::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, "format");
                                            ::quote::__private::push_bang(&mut _s);
                                            ::quote::__private::push_group(&mut _s,
                                                ::quote::__private::Delimiter::Parenthesis,
                                                {
                                                    let mut _s = ::quote::__private::TokenStream::new();
                                                    ::quote::__private::parse(&mut _s, "\"{}: {}\"");
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::ToTokens::to_tokens(&struct_name_str, &mut _s);
                                                    ::quote::__private::push_comma(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "__errs");
                                                    ::quote::__private::push_dot(&mut _s);
                                                    ::quote::__private::push_ident(&mut _s, "join");
                                                    ::quote::__private::push_group(&mut _s,
                                                        ::quote::__private::Delimiter::Parenthesis,
                                                        {
                                                            let mut _s = ::quote::__private::TokenStream::new();
                                                            ::quote::__private::parse(&mut _s, "\"; \"");
                                                            _s
                                                        });
                                                    _s
                                                });
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            _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, "result");
                    ::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, "Ok");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&name, &mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "sexp");
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "nrow");
                                    ::quote::__private::push_comma(&mut _s);
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut col_idents_for_struct, i) =
                                            col_idents_for_struct.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let col_idents_for_struct =
                                                match col_idents_for_struct.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&col_idents_for_struct,
                                                &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                        }
                                    }
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
304        #(#attrs)*
305        #[allow(non_snake_case)]
306        #vis struct #name {
307            sexp: ::miniextendr_api::SEXP,
308            nrow: usize,
309            #( #col_fields, )*
310        }
311
312        impl #name {
313            /// Number of rows in the underlying data.frame.
314            #[inline]
315            pub fn nrow(&self) -> usize { self.nrow }
316
317            /// Number of declared columns.
318            #[inline]
319            pub fn ncol(&self) -> usize { #declared_count }
320
321            /// The backing SEXP (preserves the data.frame class attribute).
322            #[inline]
323            pub fn as_sexp(&self) -> ::miniextendr_api::SEXP { self.sexp }
324
325            #( #accessors )*
326        }
327
328        impl ::miniextendr_api::from_r::TryFromSexp for #name {
329            type Error = ::miniextendr_api::from_r::SexpError;
330
331            fn try_from_sexp(
332                sexp: ::miniextendr_api::SEXP,
333            ) -> ::std::result::Result<Self, ::miniextendr_api::from_r::SexpError> {
334                use ::miniextendr_api::SexpExt as _;
335
336                // 1. Must be a data.frame.
337                if !sexp.is_data_frame() {
338                    return ::std::result::Result::Err(
339                        ::miniextendr_api::from_r::SexpError::InvalidValue(
340                            ::std::format!(
341                                "{}: expected a data.frame, got {:?}",
342                                #struct_name_str,
343                                sexp.type_of(),
344                            )
345                        )
346                    );
347                }
348
349                // 2. Build the view for O(1) name lookup + nrow extraction.
350                let view = ::miniextendr_api::dataframe::DataFrame::from_sexp(sexp)
351                    .map_err(|e| ::miniextendr_api::from_r::SexpError::InvalidValue(
352                        ::std::format!("{}: {}", #struct_name_str, e)
353                    ))?;
354                let nrow = view.nrow();
355
356                // 3. Walk each declared column, batching all errors.
357                let mut __errs: ::std::vec::Vec<::std::string::String> =
358                    ::std::vec::Vec::new();
359
360                #( #validation_locals )*
361
362                #allow_extra_check
363
364                if !__errs.is_empty() {
365                    return ::std::result::Result::Err(
366                        ::miniextendr_api::from_r::SexpError::InvalidValue(
367                            ::std::format!(
368                                "{}: {}",
369                                #struct_name_str,
370                                __errs.join("; ")
371                            )
372                        )
373                    );
374                }
375
376                ::std::result::Result::Ok(#name {
377                    sexp,
378                    nrow,
379                    #( #col_idents_for_struct, )*
380                })
381            }
382        }
383    }
384}
385
386#[cfg(test)]
387mod tests {
388    use super::*;
389
390    #[test]
391    fn test_parse_basic() {
392        let input: TypedDataframeInput = syn::parse_quote! {
393            pub TheophDf {
394                subject: i32,
395                weight: f64,
396            }
397        };
398        assert_eq!(input.name.to_string(), "TheophDf");
399        assert_eq!(input.fields.len(), 2);
400        assert_eq!(input.fields[0].name.to_string(), "subject");
401        assert!(!input.fields[0].optional);
402        assert!(input.allow_extra);
403    }
404
405    #[test]
406    fn test_parse_optional() {
407        let input: TypedDataframeInput = syn::parse_quote! {
408            pub Df { x: i32, y: Option<f64> }
409        };
410        assert!(!input.fields[0].optional);
411        assert!(input.fields[1].optional);
412    }
413
414    #[test]
415    fn test_parse_exact_mode() {
416        let input: TypedDataframeInput = syn::parse_quote! {
417            @exact;
418            pub Df { x: i32 }
419        };
420        assert!(!input.allow_extra);
421    }
422
423    #[test]
424    fn test_parse_with_doc_attrs() {
425        let input: TypedDataframeInput = syn::parse_quote! {
426            /// Theoph PK shape.
427            pub TheophDf {
428                /// Subject id.
429                subject: i32,
430            }
431        };
432        assert!(!input.attrs.is_empty());
433        assert!(!input.fields[0].attrs.is_empty());
434    }
435
436    #[test]
437    fn test_parse_empty_fails() {
438        let result: syn::Result<TypedDataframeInput> = syn::parse2(quote! {
439            pub Df {}
440        });
441        assert!(result.is_err());
442    }
443}