Skip to main content

miniextendr_macros/miniextendr_impl/
field_syntax.rs

1//! `$` / `[[` field syntax for the `#[r_data]` fields of S3, S4 and env
2//! classes: `s3(r_data_accessors)`, `s4(r_data_accessors)`,
3//! `env(r_data_accessors)`, and their getters-only form
4//! `r_data_accessors = "get"` (#1848).
5//!
6//! The methods call the helpers `#[derive(ExternalPtr)]` emits for the type
7//! (`.rdata_fields_T`, `.rdata_get_T`, `.rdata_set_T`, `.rdata_no_field_T`,
8//! see `externalptr_derive::generate_field_syntax_helpers`), which call the
9//! per-field `.Call()` accessors. Those carry no call slot (#344, #348), so
10//! each method raises a tagged condition value with its own frame as the
11//! fallback (`environment()`), which `.miniextendr_frame_call` turns into the
12//! generic's call: `x$keys`, `x$keys <- value` (#1851).
13//!
14//! No reader matches a prefix of a name (#1922). On an S3 bare pointer `$`
15//! and `[[` take an exact field name, and `[[` also a whole-number position
16//! in the field order (`subscriptOutOfBoundsError` past the last field,
17//! through the preamble's `.miniextendr_field_at`); an unknown name raises
18//! `miniextendr_no_field` there, as a write does (#1921).
19//! `s3(r_data_accessors, lookup = "list")` keeps a list's other lenience
20//! (#1891): an unknown name or `NA` reads `NULL`, and `[[` takes a logical
21//! or a fractional position (truncated) as a list's does. In both, a `[[`
22//! index that is neither one name nor one position raises the preamble's
23//! `.miniextendr_field_index_error` (the type's `field_error` classes, then
24//! `notSubsettableError`, on the user's call) instead of reaching
25//! `[[.default` (#1920). The S3 class also gets `names()` (the field names),
26//! `as.list()` (every field, in order, `NULL` fields kept; #1890) and
27//! `.DollarNames()` (#1885), and S4 and env classes `.DollarNames()`. A name
28//! that is not a field falls through on a list or an environment receiver,
29//! by the exact name: `$` reads a list's element with `.subset2()` (R's `$`
30//! on a list matches a prefix) and an environment's through `NextMethod()`,
31//! `[[` and the writes go to R's own `[[` (with `exact = TRUE`) / `$<-` /
32//! `[[<-`, as do `names()` and `as.list()` there (`as.list.environment()`
33//! by name on an environment, whose class attribute would send
34//! `NextMethod()` to the default method, which can't coerce one). The writes
35//! raise `miniextendr_no_field`, naming the R class and its fields, on a bare
36//! pointer (an S3 or env object), as `$` does on an S4 object, which have
37//! nothing to fall through to. A `[[<-` index that is not a name falls
38//! through. Under `restored(refuse = "every_read")` every S3 reader first
39//! checks a pointer, list or environment receiver (#1901, #1919): a restored
40//! pointer and a list or environment without one are refused before the
41//! index is looked at. Every replacement method puts `value` last and
42//! returns the object (#1853).
43//!
44//! The S3 `[[`, `as.list()` and `[[<-` take `...` because their generics
45//! do, and read none of it on a bare pointer, so there they refuse every
46//! argument in it (#2174) with `dots = empty`'s check (`dots_policy`), on
47//! the generic's call, with the formal each one most likely meant and the
48//! type's `field_error` classes in front: `x[["data", exatc = TRUE]]`,
49//! `x[[1, 2]]`, `as.list(x, all.names = TRUE)`, `x[["data", 2]] <- v`. `[[`
50//! takes `exact` as a formal after `...`, as `[[.data.frame` does, so
51//! `exact = FALSE` is no extra argument; field names match exactly whatever
52//! it says. A list or environment receiver hands its dots on, as before. An
53//! env class's `[[` (`env_class.rs`) takes `exact` the same way and refuses
54//! the rest on every receiver, since nothing reads its dots.
55//!
56//! A field fallback (`fallback = "Self::f"`, #2150; see
57//! `miniextendr_impl::FieldFallback`) answers the names no field has
58//! on the bare pointer, through a `.Call` entry the impl block emits
59//! (`fallback_c_entries`): `$` and `[[` by name on an S3 object, `$` on an
60//! S4 object, and `$` / `[[` on an env object after its methods. The
61//! fallback's `None` reads what an unknown name reads without it. Fields win,
62//! a position counts the fields only, `names()`, `as.list()` and the writes
63//! don't see it, and a list or environment receiver keeps its own elements
64//! for those names. With `fallback_names = "Self::g"`, `.DollarNames()`
65//! offers the fallback's names after the fields (and an env class's
66//! methods).
67//!
68//! `.DollarNames()` is registered with `@exportS3Method utils::.DollarNames`
69//! (`S3method(utils::.DollarNames, Class)`): the `@method` + `@export` pair
70//! writes an unqualified `S3method(.DollarNames, Class)`, which fails to load
71//! with only base attached (`R CMD check` loads a namespace that way). S4
72//! takes the same S3 method, which `utils` dispatches on the S4 class.
73
74use super::{ClassSystem, FieldLookup, ParsedImpl};
75use crate::naming::{RDataHelper, rdata_helper_name};
76
77/// The names of the type's field helpers.
78struct Helpers {
79    fields: String,
80    get: String,
81    set: String,
82    no_field: String,
83    /// The classes in front of the methods' own errors (#1899), `NULL`
84    /// without `field_error(...)`.
85    error_class: String,
86    /// `TRUE` under `restored(refuse = "every_read")` (#1901): it gates the
87    /// calls of `live`.
88    every_read: String,
89    /// The liveness check of `restored(refuse = "every_read")` (#1901), a
90    /// stub that is never called without it.
91    live: String,
92    /// The `.Call` entry of the impl's `fallback = "..."` (#2150), for a
93    /// name no field has ([`fallback_c_entries`]).
94    fallback: Option<String>,
95    /// The `.Call` entry of its `fallback_names = "..."`, for
96    /// `.DollarNames()`.
97    fallback_names: Option<String>,
98}
99
100impl Helpers {
101    fn new(parsed_impl: &ParsedImpl) -> Self {
102        let type_name = parsed_impl.type_ident.to_string();
103        Helpers {
104            fields: rdata_helper_name(RDataHelper::Fields, &type_name),
105            get: rdata_helper_name(RDataHelper::Get, &type_name),
106            set: rdata_helper_name(RDataHelper::Set, &type_name),
107            no_field: rdata_helper_name(RDataHelper::NoField, &type_name),
108            error_class: rdata_helper_name(RDataHelper::ErrorClass, &type_name),
109            every_read: rdata_helper_name(RDataHelper::EveryRead, &type_name),
110            live: rdata_helper_name(RDataHelper::Live, &type_name),
111            fallback: parsed_impl
112                .field_fallback
113                .as_ref()
114                .map(|_| crate::naming::sidecar_fallback_c_name(&type_name)),
115            fallback_names: parsed_impl
116                .field_fallback
117                .as_ref()
118                .and_then(|fallback| fallback.names.as_ref())
119                .map(|_| crate::naming::sidecar_fallback_names_c_name(&type_name)),
120        }
121    }
122
123    /// The fallback's read of `name`, a name no field has, on the bare
124    /// pointer `receiver` (#2150): the method returns the value the fallback
125    /// has for it. The method passes its own frame (`environment()`) as the
126    /// value of `None`, which the entry hands back untouched, so no value the
127    /// fallback computes can be taken for it; the lines after these decide
128    /// what `None` reads. Nothing without a fallback.
129    fn fallback_read(&self, receiver: &str, name: &str, indent: &str) -> Vec<String> {
130        let Some(entry) = &self.fallback else {
131            return Vec::new();
132        };
133        let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}.val <- .Call({1}, {2}, {3}, environment())",
                                indent, entry, receiver, name))
                    })]))vec![format!(
134            "{indent}.val <- .Call({entry}, {receiver}, {name}, environment())"
135        )];
136        lines.extend(guard(indent));
137        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}if (!identical(.val, environment())) return(.val)",
                indent))
    })format!(
138            "{indent}if (!identical(.val, environment())) return(.val)"
139        ));
140        lines
141    }
142
143    /// The call of the impl's `fallback_names` entry (#2150) on the bare
144    /// pointer `receiver`, for `.DollarNames()`; `None` without one. The
145    /// entry gives `character(0)` for a pointer without its Rust value, so
146    /// completion still never raises on a restored object.
147    fn fallback_names_call(&self, receiver: &str) -> Option<String> {
148        let entry = self.fallback_names.as_ref()?;
149        Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".Call({0}, {1})", entry, receiver))
    })format!(".Call({entry}, {receiver})"))
150    }
151
152    /// The last lines of a `.DollarNames()` with a `fallback_names` (#2150):
153    /// `value`, which reads the fallback's names (or a list's own), bound to
154    /// `.val` and checked, then `pattern` over `known` and `.val`, each name
155    /// once (a name the fallback shares with a field reads the field).
156    fn dollar_names_with_fallback(value: &str, known: &str) -> Vec<String> {
157        let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("  .val <- {0}", value))
                    })]))vec![format!("  .val <- {value}")];
158        lines.extend(guard("  "));
159        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  grep(pattern, unique(c({0}, .val)), value = TRUE)",
                known))
    })format!(
160            "  grep(pattern, unique(c({known}, .val)), value = TRUE)"
161        ));
162        lines
163    }
164
165    /// Under `restored(refuse = "every_read")` (#1901), the check a read
166    /// that reaches no accessor makes first on the bare pointer `receiver`:
167    /// a pointer without its Rust value raises the type's restored error. A
168    /// type without the option skips it (its flag is `FALSE`).
169    fn live_check(&self, receiver: &str, indent: &str) -> Vec<String> {
170        let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{1}if ({0}) {{",
                                self.every_read, indent))
                    })]))vec![format!("{indent}if ({}) {{", self.every_read)];
171        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}  .val <- {0}({2}, TRUE)",
                self.live, indent, receiver))
    })format!("{indent}  .val <- {}({receiver}, TRUE)", self.live));
172        lines.extend(guard(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}  ", indent))
    })format!("{indent}  ")));
173        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}}}", indent))
    })format!("{indent}}}"));
174        lines
175    }
176
177    /// The first check of every S3 reader under `restored(refuse =
178    /// "every_read")` (#1901, #1919), on a bare pointer and on a list or
179    /// environment receiver: a pointer without its Rust value, a `.ptr` that
180    /// is one, and a list or environment that carries none (the shape an
181    /// earlier release may have saved) raise the type's refusal before the
182    /// index is looked at, so a position or an unknown name is refused too.
183    /// An atomic receiver was never saved; its field reads refuse it.
184    fn every_read_check(&self) -> Vec<String> {
185        let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("  if ({0} && typeof(x) %in% c(\"externalptr\", \"list\", \"environment\")) {{",
                                self.every_read))
                    })]))vec![format!(
186            "  if ({} && typeof(x) %in% c(\"externalptr\", \"list\", \"environment\")) {{",
187            self.every_read
188        )];
189        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    .val <- {0}(x, TRUE)",
                self.live))
    })format!("    .val <- {}(x, TRUE)", self.live));
190        lines.extend(guard("    "));
191        lines.push("  }".to_string());
192        lines
193    }
194
195    /// The `.DollarNames()` guard: under `restored(refuse = "every_read")` a
196    /// receiver without a live Rust value completes to nothing (#1901): a
197    /// restored pointer, a list or environment carrying one or none (#1919),
198    /// whose `names()` would refuse. `.DollarNames()` serves completion, so
199    /// it never raises.
200    fn dollar_names_guard(&self, receiver: &str) -> String {
201        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if ({0} && !{1}({2}, FALSE)) return(character(0))",
                self.every_read, self.live, receiver))
    })format!(
202            "  if ({every_read} && !{live}({receiver}, FALSE)) return(character(0))",
203            every_read = self.every_read,
204            live = self.live
205        )
206    }
207}
208
209/// The tagged-condition guard after an accessor call: the method's frame is
210/// the raise fallback, resolved to the generic's call (#1851).
211fn guard(indent: &str) -> Vec<String> {
212    crate::method_return_builder::condition_check_lines_with_default(indent, "environment()")
213}
214
215/// The formals of the S3 `[[` reader: `exact` after `...`, as
216/// `[[.data.frame` has it, so R matches it by name and `...` holds only
217/// what the reader refuses (#2174).
218const SUBSET_FORMALS: &str = "x, i, ..., exact = TRUE";
219
220/// The formals of the S3 `as.list()` reader, its generic's.
221const AS_LIST_FORMALS: &str = "x, ...";
222
223/// The formals of the S3 `[[<-` writer, `value` last (#1853).
224const SUBSET_ASSIGN_FORMALS: &str = "x, i, ..., value";
225
226/// The formals of an env class's `[[`: its `$`'s, then `...` and `exact`,
227/// as the S3 `[[` has them (#2174).
228pub(super) const ENV_SUBSET_FORMALS: &str = "self, name, ..., exact = TRUE";
229
230/// The check a method with `formals` makes before it reads its index
231/// (#2174): `dots = empty`'s statement
232/// ([`DotsPolicy::r_check`](crate::dots_policy::DotsPolicy::r_check)), which
233/// refuses every argument in `...` on the generic's call (the method's
234/// frame), with the formal each one most likely meant. `class` is an R
235/// expression for the classes in front, the type's `field_error` classes.
236fn dots_check(formals: &str, class: Option<&str>, indent: &str) -> String {
237    let check = crate::dots_policy::DotsPolicy::empty(class.map(str::to_owned))
238        .r_check(formals, Some("environment()"))
239        .expect("the methods take `...`");
240    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", indent, check))
    })format!("{indent}{check}")
241}
242
243/// The first line of an env class's `[[` (#2174): it takes no argument
244/// past `name` but `exact`, which it ignores (field and method names match
245/// exactly), and nothing reads its `...`, on any receiver. Under
246/// `env(r_data_accessors)` the refusal carries the type's `field_error`
247/// classes.
248pub(super) fn env_subset_dots_check(parsed_impl: &ParsedImpl) -> String {
249    let class = parsed_impl
250        .r_data_accessors
251        .enabled()
252        .then(|| Helpers::new(parsed_impl).error_class);
253    dots_check(ENV_SUBSET_FORMALS, class.as_deref(), "  ")
254}
255
256/// The help topic of the field methods (and of the S3 class environment):
257/// the impl block's own `@rdname`, else the class page (#1900).
258pub(super) fn topic(parsed_impl: &ParsedImpl) -> String {
259    crate::roxygen::rdname_value(&parsed_impl.doc_tags)
260        .map_or_else(|| parsed_impl.class_name(), str::to_owned)
261}
262
263/// The page lines of a field method's block: `@rdname` its topic
264/// ([`topic`]) with the `@param` lines of `params` the page needs, or, on a
265/// topic the author names with the impl's `@rdname`, `@order NaN` and no
266/// `@param` lines: the topic's own block documents the arguments, and a
267/// later block's `@param` would replace its text (#1590).
268pub(super) fn page_lines(parsed_impl: &ParsedImpl, params: &[(&str, &str)]) -> Vec<String> {
269    let topic = topic(parsed_impl);
270    let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("#\' @rdname {0}", topic))
                    })]))vec![format!("#' @rdname {topic}")];
271    if topic == parsed_impl.class_name() {
272        lines.extend(param_lines(parsed_impl, params));
273    } else {
274        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#\' {0}",
                crate::roxygen::ORDER_AFTER_TOPIC_BLOCKS))
    })format!("#' {}", crate::roxygen::ORDER_AFTER_TOPIC_BLOCKS));
275    }
276    lines
277}
278
279/// The test of a `[[` / `[[<-` index (or env's `$` / `[[` name): a field
280/// name is a length-1 character vector naming a field.
281fn not_a_field_name(var: &str, fields: &str) -> String {
282    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("!is.character({0}) || length({0}) != 1L || is.na(match({0}, {1}))",
                var, fields))
    })format!("!is.character({var}) || length({var}) != 1L || is.na(match({var}, {fields}))")
283}
284
285/// A top-level check, emitted next to the class's methods, that the type has
286/// the field helpers: an impl that opts in for a type without an `RSidecar`
287/// selector or without a `pub` `#[r_data]` field fails at install time
288/// instead of at the first `$` (for env, at every method call).
289fn load_check(parsed_impl: &ParsedImpl, system: &str) -> String {
290    let helpers = Helpers::new(parsed_impl);
291    let type_name = parsed_impl.type_ident.to_string();
292    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("if (!is.character(get0(\"{0}\", envir = topenv(environment()), inherits = FALSE))) stop(\"`{1}(r_data_accessors)` on `{2}` needs the field helpers `#[derive(ExternalPtr)]` emits for a type with an `#[r_data]` `RSidecar` selector and a `pub` `#[r_data]` field\", call. = FALSE)",
                helpers.fields, system, type_name))
    })format!(
293        "if (!is.character(get0(\"{fields}\", envir = topenv(environment()), inherits = FALSE))) \
294         stop(\"`{system}(r_data_accessors)` on `{type_name}` needs the field helpers \
295         `#[derive(ExternalPtr)]` emits for a type with an `#[r_data]` `RSidecar` selector and a \
296         `pub` `#[r_data]` field\", call. = FALSE)",
297        fields = helpers.fields,
298    )
299}
300
301/// The `@param` lines of the field methods on the class page, without the
302/// names the constructor documents there: roxygen2 keeps the last `@param`
303/// of a name on a page, and these blocks must not replace the constructor's
304/// text. An env class's `Class$new()` lists its arguments in a `\describe{}`
305/// list, not as `@param` lines, so it takes nothing away. (The type's
306/// standalone accessors, which documented `x` / `value` on the page named
307/// after the type, are internal under field syntax, #1900.)
308fn param_lines(parsed_impl: &ParsedImpl, params: &[(&str, &str)]) -> Vec<String> {
309    let documented: Vec<String> = parsed_impl
310        .constructor()
311        .filter(|_| parsed_impl.class_system != ClassSystem::Env)
312        .map(|ctor| {
313            let formals = ctor.formals();
314            crate::r_wrapper_builder::r_formal_names(&ctor.sig.inputs, &formals)
315                .map(|(name, _)| name)
316                .collect()
317        })
318        .unwrap_or_default();
319    params
320        .iter()
321        .filter(|(name, _)| !documented.iter().any(|f| f == name))
322        .map(|(name, text)| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#\' @param {0} {1}", name, text))
    })format!("#' @param {name} {text}"))
323        .collect()
324}
325
326/// The roxygen block of an S3 or env field method `<generic>.<Class>`: on the
327/// class's topic ([`page_lines`]) for an exported class with a page, else no
328/// page. The method is registered (`S3method()`) when `register` is set.
329fn s3_method_doc(
330    lines: &mut Vec<String>,
331    parsed_impl: &ParsedImpl,
332    generic: &str,
333    on_page: bool,
334    register: bool,
335    params: &[(&str, &str)],
336) {
337    let class_name = parsed_impl.class_name();
338    if on_page {
339        lines.extend(page_lines(parsed_impl, params));
340    } else {
341        lines.push("#' @noRd".to_string());
342    }
343    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#\' @method {0} {1}", generic,
                class_name))
    })format!("#' @method {generic} {class_name}"));
344    if register {
345        lines.push("#' @export".to_string());
346    }
347}
348
349/// The roxygen block of a `.DollarNames.<Class>` method: on the class's
350/// topic ([`page_lines`]) for an exported class with a page, else no page,
351/// and registered with `@exportS3Method utils::.DollarNames` when `register`
352/// is set (see the module docs for why not `@method` + `@export`).
353fn dollar_names_doc(
354    lines: &mut Vec<String>,
355    parsed_impl: &ParsedImpl,
356    on_page: bool,
357    register: bool,
358) {
359    if on_page {
360        lines.extend(page_lines(
361            parsed_impl,
362            &[
363                ("x", "An object."),
364                (
365                    "pattern",
366                    "A regular expression; the names matching it are the completions.",
367                ),
368            ],
369        ));
370    } else {
371        lines.push("#' @noRd".to_string());
372    }
373    if register {
374        lines.push("#' @exportS3Method utils::.DollarNames".to_string());
375    }
376}
377
378/// `$.Class`, `[[.Class`, `names.Class`, `as.list.Class` and
379/// `.DollarNames.Class`, and with setters `$<-.Class` / `[[<-.Class`, for an
380/// S3 class with `s3(r_data_accessors)`.
381///
382/// The receiver is the classed pointer the constructor (or the package's own
383/// R code) returns, on which the reads look the fields up as a list's do, or
384/// a list or environment carrying the pointer in `.ptr` (#1469), whose own
385/// elements a name that is not a field reaches through `NextMethod()`.
386pub(super) fn s3_field_methods(
387    parsed_impl: &ParsedImpl,
388    on_page: bool,
389    register: bool,
390) -> Vec<String> {
391    let class_name = parsed_impl.class_name();
392    let h = Helpers::new(parsed_impl);
393    let def = |generic: &str| crate::naming::r_def_name(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.{1}", generic, class_name))
    })format!("{generic}.{class_name}"));
394    let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("# Field syntax for the `#[r_data]` fields of {0} (`s3(r_data_accessors)`).",
                                parsed_impl.type_ident))
                    }), load_check(parsed_impl, "s3"), String::new()]))vec![
395        format!(
396            "# Field syntax for the `#[r_data]` fields of {} (`s3(r_data_accessors)`).",
397            parsed_impl.type_ident
398        ),
399        load_check(parsed_impl, "s3"),
400        String::new(),
401    ];
402
403    let class_lit = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"{0}\"",
                crate::naming::r_string_escape(&class_name)))
    })format!("\"{}\"", crate::naming::r_string_escape(&class_name));
404    let x = ("x", "An object.");
405    // One text for `[[`, `as.list()` and `[[<-`, which share the page.
406    let dots = (
407        "...",
408        "Passed on by a list or an environment carrying the pointer; on the pointer \
409         itself any argument here is refused.",
410    );
411    let exact = (
412        "exact",
413        "Ignored on the pointer itself, whose field names match exactly. A list or an \
414         environment carrying the pointer reads its own elements with `exact = TRUE` \
415         whatever is passed.",
416    );
417    // One text per name for the page: roxygen2 keeps the last `@param` of a
418    // name on a page, so the reader's and the writer's blocks say the same.
419    let fallback = h.fallback.is_some();
420    let (name, i) = match parsed_impl.field_lookup {
421        FieldLookup::Strict if fallback => (
422            (
423                "name",
424                "A field name, exactly; on the pointer itself another name is read through \
425                 the class's fallback, an error when it has no value for it.",
426            ),
427            (
428                "i",
429                "A field name, exactly; `[[` on the pointer itself also takes a whole-number \
430                 position in the field order and reads another name through the class's \
431                 fallback. On a list or an environment carrying the pointer, any other index \
432                 goes to the object's own `[[` / `[[<-`, which matches names exactly.",
433            ),
434        ),
435        FieldLookup::List if fallback => (
436            (
437                "name",
438                "A field name, exactly; on the pointer itself another name is read through \
439                 the class's fallback, `NULL` when it has no value for it.",
440            ),
441            (
442                "i",
443                "A field name, exactly; `[[` on the pointer itself also takes a position in \
444                 the field order, as for a list, and reads another name through the class's \
445                 fallback. On a list or an environment carrying the pointer, any other index \
446                 goes to the object's own `[[` / `[[<-`, which matches names exactly.",
447            ),
448        ),
449        FieldLookup::Strict => (
450            (
451                "name",
452                "A field name, exactly; on the pointer itself any other name is an error.",
453            ),
454            (
455                "i",
456                "A field name, exactly; `[[` on the pointer itself also takes a whole-number \
457                 position in the field order. On a list or an environment carrying the \
458                 pointer, any other index goes to the object's own `[[` / `[[<-`, which \
459                 matches names exactly.",
460            ),
461        ),
462        FieldLookup::List => (
463            (
464                "name",
465                "A field name, exactly; on the pointer itself any other name reads `NULL`.",
466            ),
467            (
468                "i",
469                "A field name, exactly; `[[` on the pointer itself also takes a position in \
470                 the field order, as for a list. On a list or an environment carrying the \
471                 pointer, any other index goes to the object's own `[[` / `[[<-`, which \
472                 matches names exactly.",
473            ),
474        ),
475    };
476    let value = ("value", "The new value of the field.");
477
478    // `$`: an exact field name reads the field. On a bare pointer any other
479    // name raises `miniextendr_no_field`, or reads NULL under
480    // `lookup = "list"`; a list receiver reads its own element by the exact
481    // name (`.subset2()`: R's `$` on a list would match a prefix, #1922), an
482    // environment receiver through R's `$`, which is exact there.
483    s3_method_doc(&mut lines, parsed_impl, "$", on_page, register, &[x, name]);
484    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x, name) {{",
                def("$")))
    })format!("{} <- function(x, name) {{", def("$")));
485    lines.extend(h.every_read_check());
486    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (is.na(match(name, {0}))) {{",
                h.fields))
    })format!("  if (is.na(match(name, {}))) {{", h.fields));
487    // What an unknown name reads on the bare pointer, and what the
488    // fallback's `None` reads (#2150).
489    let unknown = |name: &str| match parsed_impl.field_lookup {
490        FieldLookup::Strict => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}({1}, environment(), {2})",
                h.no_field, name, class_lit))
    })format!("{}({name}, environment(), {class_lit})", h.no_field),
491        FieldLookup::List => "return(NULL)".to_string(),
492    };
493    if fallback {
494        lines.push("    if (typeof(x) == \"externalptr\") {".to_string());
495        lines.extend(h.fallback_read("x", "name", "      "));
496        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      {0}", unknown("name")))
    })format!("      {}", unknown("name")));
497        lines.push("    }".to_string());
498    } else {
499        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    if (typeof(x) == \"externalptr\") {0}",
                unknown("name")))
    })format!(
500            "    if (typeof(x) == \"externalptr\") {}",
501            unknown("name")
502        ));
503    }
504    lines.push("    if (is.list(x)) return(.subset2(x, name))".to_string());
505    lines.push("    return(NextMethod())".to_string());
506    lines.push("  }".to_string());
507    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x, name)", h.get))
    })format!("  .val <- {}(x, name)", h.get));
508    lines.extend(guard("  "));
509    lines.push("  .val".to_string());
510    lines.push("}".to_string());
511    lines.push(String::new());
512
513    // `[[`: on a bare pointer one exact name or one position. The default
514    // takes a whole number only and refuses an unknown name with
515    // `miniextendr_no_field`; `lookup = "list"` takes a number or a logical
516    // as a list's `[[` does (`NA` reads NULL, since a character vector's
517    // `[[NA]]` is `NA` where a list's is NULL; the rest through
518    // `.miniextendr_field_at`) and reads NULL for an unknown name. Any other
519    // index raises the bad-index error there (#1920). The bare pointer first
520    // refuses any argument in `...` (#2174); `exact` is a formal, ignored
521    // there. A list or environment receiver reaches its own `[[` for
522    // everything but an exact field, with its dots and `exact = TRUE`
523    // whatever the call passed (#1922).
524    s3_method_doc(
525        &mut lines,
526        parsed_impl,
527        "[[",
528        on_page,
529        register,
530        &[x, i, dots, exact],
531    );
532    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
                def("[["), SUBSET_FORMALS))
    })format!("{} <- function({SUBSET_FORMALS}) {{", def("[[")));
533    lines.extend(h.every_read_check());
534    lines.push("  if (typeof(x) == \"externalptr\") {".to_string());
535    lines.push(dots_check(SUBSET_FORMALS, Some(&h.error_class), "    "));
536    let field_at = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      i <- .miniextendr_field_at({0}, i, environment(), {1})",
                h.fields, h.error_class))
    })format!(
537        "      i <- .miniextendr_field_at({}, i, environment(), {})",
538        h.fields, h.error_class
539    );
540    match parsed_impl.field_lookup {
541        FieldLookup::List => {
542            lines.push("    if (is.character(i) && length(i) == 1L) {".to_string());
543            if fallback {
544                // `NA` reads NULL, as without the fallback.
545                lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      if (is.na(match(i, {0}))) {{",
                h.fields))
    })format!("      if (is.na(match(i, {}))) {{", h.fields));
546                lines.push("        if (!is.na(i)) {".to_string());
547                lines.extend(h.fallback_read("x", "i", "          "));
548                lines.push("        }".to_string());
549                lines.push("        return(NULL)".to_string());
550                lines.push("      }".to_string());
551            } else {
552                lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      if (is.na(match(i, {0}))) return(NULL)",
                h.fields))
    })format!(
553                    "      if (is.na(match(i, {}))) return(NULL)",
554                    h.fields
555                ));
556            }
557            lines.push(
558                "    } else if (length(i) == 1L && (is.numeric(i) || is.logical(i))) {".to_string(),
559            );
560            lines.push("      if (is.na(i)) return(NULL)".to_string());
561            lines.push(field_at);
562            lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    }} else .miniextendr_field_index_error({1}, environment(), {0})",
                h.error_class, class_lit))
    })format!(
563                "    }} else .miniextendr_field_index_error({class_lit}, environment(), {})",
564                h.error_class
565            ));
566        }
567        FieldLookup::Strict => {
568            lines.push("    if (is.character(i) && length(i) == 1L && !is.na(i)) {".to_string());
569            if fallback {
570                lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      if (is.na(match(i, {0}))) {{",
                h.fields))
    })format!("      if (is.na(match(i, {}))) {{", h.fields));
571                lines.extend(h.fallback_read("x", "i", "        "));
572                lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("        {0}", unknown("i")))
    })format!("        {}", unknown("i")));
573                lines.push("      }".to_string());
574            } else {
575                lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("      if (is.na(match(i, {0}))) {1}",
                h.fields, unknown("i")))
    })format!(
576                    "      if (is.na(match(i, {}))) {}",
577                    h.fields,
578                    unknown("i")
579                ));
580            }
581            lines.push(
582                "    } else if (is.numeric(i) && length(i) == 1L && !is.na(i) && i == trunc(i)) {"
583                    .to_string(),
584            );
585            lines.push(field_at);
586            lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    }} else .miniextendr_field_index_error({1}, environment(), {0}, strict = TRUE)",
                h.error_class, class_lit))
    })format!(
587                "    }} else .miniextendr_field_index_error({class_lit}, environment(), {}, strict = TRUE)",
588                h.error_class
589            ));
590        }
591    }
592    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  }} else if ({0}) {{",
                not_a_field_name("i", &h.fields)))
    })format!(
593        "  }} else if ({}) {{",
594        not_a_field_name("i", &h.fields)
595    ));
596    lines.push("    return(NextMethod(exact = TRUE))".to_string());
597    lines.push("  }".to_string());
598    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x, i)", h.get))
    })format!("  .val <- {}(x, i)", h.get));
599    lines.extend(guard("  "));
600    lines.push("  .val".to_string());
601    lines.push("}".to_string());
602    lines.push(String::new());
603
604    // `names()` and `as.list()` on a bare pointer only (#1890): a list or
605    // environment receiver keeps R's own, so `names(x)` agrees with
606    // `length(x)` and `x[[i]]` there. An environment gets
607    // `as.list.environment()` by name: its class attribute would send
608    // `NextMethod()` to `as.list.default()`, which can't coerce one.
609    // `as.list()` reads every field through the getters, in declared order,
610    // and keeps a NULL field (`out[k] <- list(.val)`; `out[[k]] <- NULL`
611    // would drop it). It takes no argument there and refuses any in `...`
612    // (#2174); an environment's `as.list()` takes `all.names` / `sorted`.
613    s3_method_doc(&mut lines, parsed_impl, "names", on_page, register, &[x]);
614    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x) {{",
                def("names")))
    })format!("{} <- function(x) {{", def("names")));
615    lines.extend(h.every_read_check());
616    lines.push("  if (typeof(x) != \"externalptr\") return(NextMethod())".to_string());
617    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  {0}", h.fields))
    })format!("  {}", h.fields));
618    lines.push("}".to_string());
619    lines.push(String::new());
620
621    s3_method_doc(
622        &mut lines,
623        parsed_impl,
624        "as.list",
625        on_page,
626        register,
627        &[x, dots],
628    );
629    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
                def("as.list"), AS_LIST_FORMALS))
    })format!(
630        "{} <- function({AS_LIST_FORMALS}) {{",
631        def("as.list")
632    ));
633    lines.extend(h.every_read_check());
634    lines.push("  if (is.environment(x)) return(as.list.environment(x, ...))".to_string());
635    lines.push("  if (typeof(x) != \"externalptr\") return(NextMethod())".to_string());
636    lines.push(dots_check(AS_LIST_FORMALS, Some(&h.error_class), "  "));
637    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .out <- vector(\"list\", length({0}))",
                h.fields))
    })format!("  .out <- vector(\"list\", length({}))", h.fields));
638    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  names(.out) <- {0}", h.fields))
    })format!("  names(.out) <- {}", h.fields));
639    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  for (.k in seq_along({0})) {{",
                h.fields))
    })format!("  for (.k in seq_along({})) {{", h.fields));
640    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    .val <- {0}(x, {1}[[.k]])",
                h.get, h.fields))
    })format!("    .val <- {}(x, {}[[.k]])", h.get, h.fields));
641    lines.extend(guard("    "));
642    lines.push("    .out[.k] <- list(.val)".to_string());
643    lines.push("  }".to_string());
644    lines.push("  .out".to_string());
645    lines.push("}".to_string());
646    lines.push(String::new());
647
648    // `.DollarNames()` (#1885): the fields, then a list's or environment's
649    // own names. It reads only names, so it never raises; under
650    // `restored(refuse = "every_read")` a restored pointer completes to
651    // nothing (#1901).
652    dollar_names_doc(&mut lines, parsed_impl, on_page, register);
653    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x, pattern = \"\") {{",
                def(".DollarNames")))
    })format!(
654        "{} <- function(x, pattern = \"\") {{",
655        def(".DollarNames")
656    ));
657    lines.push(h.dollar_names_guard("x"));
658    match h.fallback_names_call("x") {
659        // The fallback's names follow the fields on the bare pointer, where
660        // `$` reads them (#2150).
661        Some(call) => lines.extend(Helpers::dollar_names_with_fallback(
662            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("if (typeof(x) == \"externalptr\") {0} else names(x)",
                call))
    })format!("if (typeof(x) == \"externalptr\") {call} else names(x)"),
663            &h.fields,
664        )),
665        None => lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  grep(pattern, c({0}, if (typeof(x) != \"externalptr\") names(x)), value = TRUE)",
                h.fields))
    })format!(
666            "  grep(pattern, c({}, if (typeof(x) != \"externalptr\") names(x)), value = TRUE)",
667            h.fields
668        )),
669    }
670    lines.push("}".to_string());
671    lines.push(String::new());
672
673    if !parsed_impl.r_data_accessors.setters() {
674        return lines;
675    }
676
677    s3_method_doc(
678        &mut lines,
679        parsed_impl,
680        "$<-",
681        on_page,
682        register,
683        &[x, name, value],
684    );
685    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x, name, value) {{",
                def("$<-")))
    })format!("{} <- function(x, name, value) {{", def("$<-")));
686    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (is.na(match(name, {0}))) {{",
                h.fields))
    })format!("  if (is.na(match(name, {}))) {{", h.fields));
687    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    if (typeof(x) == \"externalptr\") {0}(name, environment(), {1})",
                h.no_field, class_lit))
    })format!(
688        "    if (typeof(x) == \"externalptr\") {}(name, environment(), {class_lit})",
689        h.no_field
690    ));
691    lines.push("    return(NextMethod())".to_string());
692    lines.push("  }".to_string());
693    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x, name, value)",
                h.set))
    })format!("  .val <- {}(x, name, value)", h.set));
694    lines.extend(guard("  "));
695    lines.push("  x".to_string());
696    lines.push("}".to_string());
697    lines.push(String::new());
698
699    s3_method_doc(
700        &mut lines,
701        parsed_impl,
702        "[[<-",
703        on_page,
704        register,
705        &[x, i, dots, value],
706    );
707    // The bare pointer refuses any argument in `...` (#2174): `x[["a", 2]] <-
708    // v` would otherwise write `a`. A list or environment receiver hands
709    // them to its own `[[<-`.
710    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
                def("[[<-"), SUBSET_ASSIGN_FORMALS))
    })format!(
711        "{} <- function({SUBSET_ASSIGN_FORMALS}) {{",
712        def("[[<-")
713    ));
714    lines.push("  if (typeof(x) == \"externalptr\") {".to_string());
715    lines.push(dots_check(
716        SUBSET_ASSIGN_FORMALS,
717        Some(&h.error_class),
718        "    ",
719    ));
720    lines.push("  }".to_string());
721    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if ({0}) {{",
                not_a_field_name("i", &h.fields)))
    })format!("  if ({}) {{", not_a_field_name("i", &h.fields)));
722    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    if (typeof(x) == \"externalptr\" && is.character(i) && length(i) == 1L) {0}(i, environment(), {1})",
                h.no_field, class_lit))
    })format!(
723        "    if (typeof(x) == \"externalptr\" && is.character(i) && length(i) == 1L) {}(i, environment(), {class_lit})",
724        h.no_field
725    ));
726    lines.push("    return(NextMethod())".to_string());
727    lines.push("  }".to_string());
728    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x, i, value)",
                h.set))
    })format!("  .val <- {}(x, i, value)", h.set));
729    lines.extend(guard("  "));
730    lines.push("  x".to_string());
731    lines.push("}".to_string());
732    lines.push(String::new());
733    lines
734}
735
736/// `setMethod("$")`, `.DollarNames.Class`, and with setters
737/// `setMethod("$<-")`, for an S4 class with `s4(r_data_accessors)`. An S4
738/// object of the class is no list (its only slot is `ptr`), so a name that
739/// is not a field raises `miniextendr_no_field`. The methods pass `x@ptr` to
740/// the accessors. `.DollarNames` is an S3 method, which `utils` dispatches on
741/// the S4 class; it is registered unless the class is `noexport`, as an S3
742/// class's methods are.
743pub(super) fn s4_field_methods(
744    parsed_impl: &ParsedImpl,
745    on_page: bool,
746    export: bool,
747) -> Vec<String> {
748    let class_name = parsed_impl.class_name();
749    let class_lit = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"{0}\"",
                crate::naming::r_string_escape(&class_name)))
    })format!("\"{}\"", crate::naming::r_string_escape(&class_name));
750    let h = Helpers::new(parsed_impl);
751    let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("# Field syntax for the `#[r_data]` fields of {0} (`s4(r_data_accessors)`).",
                                parsed_impl.type_ident))
                    }), load_check(parsed_impl, "s4"), String::new()]))vec![
752        format!(
753            "# Field syntax for the `#[r_data]` fields of {} (`s4(r_data_accessors)`).",
754            parsed_impl.type_ident
755        ),
756        load_check(parsed_impl, "s4"),
757        String::new(),
758    ];
759    let doc = |lines: &mut Vec<String>, generic: &str, params: &[(&str, &str)]| {
760        if on_page {
761            lines.extend(page_lines(parsed_impl, params));
762        } else {
763            lines.push("#' @noRd".to_string());
764        }
765        if export {
766            lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#\' @exportMethod {0}", generic))
    })format!("#' @exportMethod {generic}"));
767        }
768    };
769    let x = ("x", "An object.");
770    let name = (
771        "name",
772        if h.fallback.is_some() {
773            "A field name, or a name the class's fallback reads."
774        } else {
775            "A field name."
776        },
777    );
778    let value = ("value", "The new value of the field.");
779
780    doc(&mut lines, "$", &[x, name]);
781    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("methods::setMethod(\"$\", \"{0}\", function(x, name) {{",
                class_name))
    })format!(
782        "methods::setMethod(\"$\", \"{class_name}\", function(x, name) {{"
783    ));
784    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (is.na(match(name, {0}))) {{",
                h.fields))
    })format!("  if (is.na(match(name, {}))) {{", h.fields));
785    lines.extend(h.live_check("x@ptr", "    "));
786    lines.extend(h.fallback_read("x@ptr", "name", "    "));
787    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    {0}(name, environment(), {1})",
                h.no_field, class_lit))
    })format!(
788        "    {}(name, environment(), {class_lit})",
789        h.no_field
790    ));
791    lines.push("  }".to_string());
792    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x@ptr, name)",
                h.get))
    })format!("  .val <- {}(x@ptr, name)", h.get));
793    lines.extend(guard("  "));
794    lines.push("  .val".to_string());
795    lines.push("})".to_string());
796    lines.push(String::new());
797
798    dollar_names_doc(&mut lines, parsed_impl, on_page, !parsed_impl.noexport);
799    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x, pattern = \"\") {{",
                crate::naming::r_def_name(&::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!(".DollarNames.{0}",
                                        class_name))
                            }))))
    })format!(
800        "{} <- function(x, pattern = \"\") {{",
801        crate::naming::r_def_name(&format!(".DollarNames.{class_name}"))
802    ));
803    lines.push(h.dollar_names_guard("x@ptr"));
804    match h.fallback_names_call("x@ptr") {
805        Some(call) => lines.extend(Helpers::dollar_names_with_fallback(&call, &h.fields)),
806        None => lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  grep(pattern, {0}, value = TRUE)",
                h.fields))
    })format!("  grep(pattern, {}, value = TRUE)", h.fields)),
807    }
808    lines.push("}".to_string());
809    lines.push(String::new());
810
811    if parsed_impl.r_data_accessors.setters() {
812        doc(&mut lines, "$<-", &[x, name, value]);
813        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("methods::setMethod(\"$<-\", \"{0}\", function(x, name, value) {{",
                class_name))
    })format!(
814            "methods::setMethod(\"$<-\", \"{class_name}\", function(x, name, value) {{"
815        ));
816        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (is.na(match(name, {0}))) {1}(name, environment(), {2})",
                h.fields, h.no_field, class_lit))
    })format!(
817            "  if (is.na(match(name, {}))) {}(name, environment(), {class_lit})",
818            h.fields, h.no_field
819        ));
820        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x@ptr, name, value)",
                h.set))
    })format!("  .val <- {}(x@ptr, name, value)", h.set));
821        lines.extend(guard("  "));
822        lines.push("  x".to_string());
823        lines.push("})".to_string());
824        lines.push(String::new());
825    }
826    lines
827}
828
829/// The field branch at the top of an env class's `$.Class` (and its
830/// `[[.Class` alias), ahead of the method lookup: a field wins over a method
831/// of the same name, as R6's active bindings do, and a field read doesn't
832/// pay for the lookup.
833pub(super) fn env_field_branch(parsed_impl: &ParsedImpl) -> Vec<String> {
834    let h = Helpers::new(parsed_impl);
835    let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("  if (!({0})) {{",
                                not_a_field_name("name", &h.fields)))
                    })]))vec![format!(
836        "  if (!({})) {{",
837        not_a_field_name("name", &h.fields)
838    )];
839    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    .val <- {0}(self, name)",
                h.get))
    })format!("    .val <- {}(self, name)", h.get));
840    lines.extend(guard("    "));
841    lines.push("    return(.val)".to_string());
842    lines.push("  }".to_string());
843    lines
844}
845
846/// The check in an env class's `$.Class` before it returns `NULL` for a name
847/// that is neither a field nor a method: under `restored(refuse =
848/// "every_read")` a pointer without its Rust value raises the type's
849/// restored error there (#1901). With a `fallback` (#2150) the bare pointer
850/// then asks it, after the fields and the methods, so a value of the
851/// fallback never hides a method; its `None` reads `NULL`, as an unknown
852/// name does.
853pub(super) fn env_unknown_name_check(parsed_impl: &ParsedImpl) -> Vec<String> {
854    let h = Helpers::new(parsed_impl);
855    let mut lines = h.live_check("self", "    ");
856    if h.fallback.is_some() {
857        lines.push("    if (typeof(self) == \"externalptr\") {".to_string());
858        lines.extend(h.fallback_read("self", "name", "      "));
859        lines.push("    }".to_string());
860    }
861    lines
862}
863
864/// The `@param name` text of an env class's `$.Class`.
865pub(super) fn env_name_param(parsed_impl: &ParsedImpl) -> &'static str {
866    if parsed_impl.field_fallback.is_some() {
867        "A method or field name, or a name the class's fallback reads."
868    } else {
869        "A method or field name."
870    }
871}
872
873/// The load check of an env class with `env(r_data_accessors)`.
874pub(super) fn env_load_check(parsed_impl: &ParsedImpl) -> String {
875    load_check(parsed_impl, "env")
876}
877
878/// `.DollarNames.Class` for an env class with `env(r_data_accessors)`: the
879/// fields, then the class's methods (`ls(<Class>)`), since `$` reaches both.
880/// `on_page` follows the `$.Class` block's gating; the method is always
881/// registered, as `$.Class` is.
882pub(super) fn env_dollar_names(parsed_impl: &ParsedImpl, on_page: bool) -> Vec<String> {
883    let class_name = parsed_impl.class_name();
884    let h = Helpers::new(parsed_impl);
885    let mut lines = Vec::new();
886    dollar_names_doc(&mut lines, parsed_impl, on_page, true);
887    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} <- function(x, pattern = \"\") {{",
                crate::naming::r_def_name(&::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!(".DollarNames.{0}",
                                        class_name))
                            }))))
    })format!(
888        "{} <- function(x, pattern = \"\") {{",
889        crate::naming::r_def_name(&format!(".DollarNames.{class_name}"))
890    ));
891    lines.push(h.dollar_names_guard("x"));
892    match h.fallback_names_call("x") {
893        // The fallback's names follow the methods, which `$` tries first
894        // (#2150).
895        Some(call) => lines.extend(Helpers::dollar_names_with_fallback(
896            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("if (typeof(x) == \"externalptr\") {0}",
                call))
    })format!("if (typeof(x) == \"externalptr\") {call}"),
897            &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, ls({1})", h.fields,
                class_name))
    })format!("{}, ls({class_name})", h.fields),
898        )),
899        None => lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  grep(pattern, c({0}, ls({1})), value = TRUE)",
                h.fields, class_name))
    })format!(
900            "  grep(pattern, c({}, ls({})), value = TRUE)",
901            h.fields, class_name
902        )),
903    }
904    lines.push("}".to_string());
905    lines
906}
907
908/// `$<-.Class` and its `[[<-.Class` alias for an env class with
909/// `env(r_data_accessors)`. An env object is a classed pointer, so a name
910/// that is not a field raises `miniextendr_no_field`; a list or environment
911/// carrying the pointer in `.ptr` writes its own element (`NextMethod()`).
912/// `on_page` follows the `$.Class` block's gating; the methods are always
913/// registered, as `$.Class` is.
914pub(super) fn env_replacement_methods(parsed_impl: &ParsedImpl, on_page: bool) -> Vec<String> {
915    let class_name = parsed_impl.class_name();
916    let h = Helpers::new(parsed_impl);
917    let mut lines = Vec::new();
918    let class_lit = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"{0}\"",
                crate::naming::r_string_escape(&class_name)))
    })format!("\"{}\"", crate::naming::r_string_escape(&class_name));
919    let x = ("x", "An object.");
920    let value = ("value", "The new value of the field.");
921    s3_method_doc(&mut lines, parsed_impl, "$<-", on_page, true, &[x, value]);
922    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`$<-.{0}` <- function(x, name, value) {{",
                class_name))
    })format!("`$<-.{class_name}` <- function(x, name, value) {{"));
923    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if ({0}) {{",
                not_a_field_name("name", &h.fields)))
    })format!("  if ({}) {{", not_a_field_name("name", &h.fields)));
924    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("    if (typeof(x) == \"externalptr\" && is.character(name) && length(name) == 1L) {0}(name, environment(), {1})",
                h.no_field, class_lit))
    })format!(
925        "    if (typeof(x) == \"externalptr\" && is.character(name) && length(name) == 1L) {}(name, environment(), {class_lit})",
926        h.no_field
927    ));
928    lines.push("    return(NextMethod())".to_string());
929    lines.push("  }".to_string());
930    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- {0}(x, name, value)",
                h.set))
    })format!("  .val <- {}(x, name, value)", h.set));
931    lines.extend(guard("  "));
932    lines.push("  x".to_string());
933    lines.push("}".to_string());
934    s3_method_doc(&mut lines, parsed_impl, "[[<-", on_page, true, &[]);
935    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`[[<-.{0}` <- `$<-.{0}`",
                class_name))
    })format!("`[[<-.{class_name}` <- `$<-.{class_name}`"));
936    lines
937}
938
939/// Refuses an impl method on a generic the field methods define: two
940/// definitions of `$.Class` (or `setMethod("$", "Class")`) would follow, and
941/// the later one would win. The getters-only form generates no `$<-` /
942/// `[[<-`, so a hand-written one is the point of it; the readers (`$`, `[[`,
943/// `names`, `as.list` and `.DollarNames` on S3, `$` and `.DollarNames` on
944/// S4) are generated in both forms. Env classes have no check: their
945/// methods are not S3 methods.
946pub(super) fn check_collisions(parsed_impl: &ParsedImpl) -> syn::Result<()> {
947    let setters = parsed_impl.r_data_accessors.setters();
948    let generated: &[&str] = match (parsed_impl.class_system, setters) {
949        _ if !parsed_impl.r_data_accessors.enabled() => return Ok(()),
950        (ClassSystem::S3, true) => &["$", "[[", "names", "as.list", ".DollarNames", "$<-", "[[<-"],
951        (ClassSystem::S3, false) => &["$", "[[", "names", "as.list", ".DollarNames"],
952        (ClassSystem::S4, true) => &["$", ".DollarNames", "$<-"],
953        (ClassSystem::S4, false) => &["$", ".DollarNames"],
954        _ => return Ok(()),
955    };
956    let class_name = parsed_impl.class_name();
957    for method in parsed_impl.instance_methods() {
958        // S3 dispatches an instance method under its generic, else its R
959        // name; S4 under its generic, else `s4_<name>`.
960        let generic = match parsed_impl.class_system {
961            ClassSystem::S3 => method
962                .method_attrs
963                .generic
964                .clone()
965                .unwrap_or_else(|| method.r_method_name()),
966            _ => match &method.method_attrs.generic {
967                Some(generic) => generic.clone(),
968                None => continue,
969            },
970        };
971        // A method on another class (`s3(generic = "$", class = "other")`)
972        // defines another class's method.
973        if method
974            .method_attrs
975            .class
976            .as_deref()
977            .is_some_and(|class| class != class_name)
978        {
979            continue;
980        }
981        if !generated.contains(&generic.as_str()) {
982            continue;
983        }
984        let system = if parsed_impl.class_system == ClassSystem::S3 {
985            "s3"
986        } else {
987            "s4"
988        };
989        let advice = if setters && generic.ends_with("<-") {
990            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" To write the fields with your own replacement methods, use the getters-only form `{0}(r_data_accessors = \"get\")`, which generates no `$<-` / `[[<-`.",
                system))
    })format!(
991                " To write the fields with your own replacement methods, use the getters-only \
992                 form `{system}(r_data_accessors = \"get\")`, which generates no `$<-` / `[[<-`."
993            )
994        } else {
995            String::new()
996        };
997        return Err(syn::Error::new_spanned(
998            &method.ident,
999            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` defines the `{1}` method of `{2}`, which `{3}(r_data_accessors)` generates for the `#[r_data]` fields: the class would get two `{1}` methods. Remove the method or the option.{4}",
                method.ident, generic, class_name, system, advice))
    })format!(
1000                "`{}` defines the `{generic}` method of `{class_name}`, which \
1001                 `{system}(r_data_accessors)` generates for the `#[r_data]` fields: the class \
1002                 would get two `{generic}` methods. Remove the method or the option.{advice}",
1003                method.ident
1004            ),
1005        ));
1006    }
1007    Ok(())
1008}
1009
1010/// The `.Call` entries of the impl's field fallback (#2150): `fallback =
1011/// "Self::f"` as `C_<crate>__mx_rdata_fallback_<Type>(x, name, none)`, and
1012/// `fallback_names = "Self::g"` as `C_<crate>__mx_rdata_names_<Type>(x)`.
1013/// Nothing without a fallback.
1014///
1015/// They are the sidecar getters' kind (`externalptr_derive`): no call slot
1016/// (#344, #348), the body under `with_r_unwind_protect`, so a panic or the
1017/// function's own `rust_error!(class = ...)` reaches R as a tagged condition
1018/// the method raises on its call, and the deferred conditions signalled at
1019/// the call. They borrow the value through `sidecar_r_struct`, as a struct
1020/// field's getter does: a restored pointer raises the type's restored error
1021/// before the function runs, a pointer of another type the receiver error,
1022/// and a running method holding the value mutably
1023/// `miniextendr_borrow_conflict`.
1024///
1025/// `none` is the value of `None`: the method passes its own frame, which the
1026/// entry returns untouched, so the entry holds no R value across an
1027/// allocation and the method tells `None` from any value with
1028/// `identical()`. `Some(v)` converts `v` with `IntoR`, so `Some(None)` of an
1029/// `Option<Option<i32>>` reads `NA`. The names entry gives `character(0)`
1030/// for a pointer without its Rust value, since `.DollarNames()` never
1031/// raises; a live one calls the function on the value.
1032///
1033/// The paths resolve a leading `Self` to the impl's type, since the entries
1034/// are free functions; a function of the wrong signature is reported at the
1035/// attribute's string.
1036pub(super) fn fallback_c_entries(parsed_impl: &ParsedImpl) -> proc_macro2::TokenStream {
1037    use quote::{format_ident, quote, quote_spanned};
1038
1039    let Some(fallback) = &parsed_impl.field_fallback else {
1040        return proc_macro2::TokenStream::new();
1041    };
1042    let ty = &parsed_impl.type_ident;
1043    let type_name = crate::naming::ident_name(ty);
1044    let cfg_attrs = &parsed_impl.cfg_attrs;
1045    let path = |lit: &syn::LitStr| {
1046        let mut path: syn::Path = lit
1047            .parse()
1048            .expect("the impl attribute parser checked the path");
1049        crate::util::resolve_self(&mut path, ty);
1050        path
1051    };
1052
1053    let get = path(&fallback.get);
1054    let span = fallback.get.span();
1055    // The `Option` and the conversion are spanned at the attribute's string,
1056    // so a function that returns no `Option`, or an `Option` of a type
1057    // without `IntoR`, is reported there.
1058    let value = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "match");
    ::quote::ToTokens::to_tokens(&get, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_value");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_name");
            _s
        });
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Some");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "miniextendr_api");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "into_r");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "IntoR");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "into_sexp");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span, "v");
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "core");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "None");
            ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "none");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {span=>
1059        match #get(__mx_value, &__mx_name) {
1060            ::core::option::Option::Some(v) => ::miniextendr_api::into_r::IntoR::into_sexp(v),
1061            ::core::option::Option::None => none,
1062        }
1063    };
1064    let c_ident = match ::quote::__private::IdentFragmentAdapter(&crate::naming::sidecar_fallback_c_name(&type_name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}", crate::naming::sidecar_fallback_c_name(&type_name));
1065    let def_ident = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__MX_CALL_DEF_RDATA_FALLBACK_{0}",
                        type_name))
            }), ::quote::__private::Option::None)format_ident!("__MX_CALL_DEF_RDATA_FALLBACK_{type_name}");
1066    let registration = crate::call_method_def::call_method_def(&def_ident, &c_ident, 3);
1067    let doc = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Generated fallback of the field methods of Rust type `{1}` (`fallback = {0:?}`).",
                fallback.get.value(), type_name))
    })format!(
1068        "Generated fallback of the field methods of Rust type `{type_name}` (`fallback = {:?}`).",
1069        fallback.get.value()
1070    );
1071    let mut entries = {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_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, "doc");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&doc, &mut _s);
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "hidden");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "no_mangle");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "non_snake_case");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "pub");
    ::quote::__private::push_ident(&mut _s, "unsafe");
    ::quote::__private::push_ident(&mut _s, "extern");
    ::quote::__private::parse(&mut _s, "\"C-unwind\"");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&c_ident, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "x");
            ::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, "name");
            ::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, "none");
            ::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, "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, "let");
            ::quote::__private::push_ident(&mut _s,
                "__miniextendr_deferred_mark");
            ::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, "deferred_condition");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mark");
            ::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, "__miniextendr_value");
            ::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, "unwind_protect");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "with_r_unwind_protect");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_or_or(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "__mx_name");
                            ::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, "string");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "String");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "match");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "TryFromSexp");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "try_from_sexp");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_ident(&mut _s, "name");
                                    _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, "core");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "result");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "Result");
                                    ::quote::__private::push_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::__private::push_ident(&mut _s, "name");
                                            _s
                                        });
                                    ::quote::__private::push_fat_arrow(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "name");
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "core");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "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_ident(&mut _s, "err");
                                            _s
                                        });
                                    ::quote::__private::push_fat_arrow(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Brace,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_colon2(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "core");
                                            ::quote::__private::push_colon2(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "panic");
                                            ::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,
                                                        "\"the field fallback takes one name: {err}\"");
                                                    _s
                                                });
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "__mx_data");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "unsafe");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "externalptr");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "sidecar_r_struct");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_lt(&mut _s);
                                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                                    ::quote::__private::push_gt(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "x");
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "__mx_value");
                            ::quote::__private::push_colon(&mut _s);
                            ::quote::__private::push_and(&mut _s);
                            ::quote::ToTokens::to_tokens(&ty, &mut _s);
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_and(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "__mx_data");
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::ToTokens::to_tokens(&value, &mut _s);
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "core");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "deferred_condition");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "finish");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s,
                                "__miniextendr_deferred_mark");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "__miniextendr_value");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "core");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "Option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "None");
                            ::quote::__private::push_comma(&mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_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, "doc");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "hidden");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&registration, &mut _s);
    _s
}quote! {
1072        #(#cfg_attrs)*
1073        #[doc = #doc]
1074        #[doc(hidden)]
1075        #[unsafe(no_mangle)]
1076        #[allow(non_snake_case)]
1077        pub unsafe extern "C-unwind" fn #c_ident(
1078            x: ::miniextendr_api::SEXP,
1079            name: ::miniextendr_api::SEXP,
1080            none: ::miniextendr_api::SEXP,
1081        ) -> ::miniextendr_api::SEXP {
1082            let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
1083            let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
1084                || {
1085                    // The readers pass one name, a string.
1086                    let __mx_name: ::std::string::String =
1087                        match ::miniextendr_api::TryFromSexp::try_from_sexp(name) {
1088                            ::core::result::Result::Ok(name) => name,
1089                            ::core::result::Result::Err(err) => {
1090                                ::core::panic!("the field fallback takes one name: {err}")
1091                            }
1092                        };
1093                    let __mx_data =
1094                        unsafe { ::miniextendr_api::externalptr::sidecar_r_struct::<#ty>(x) };
1095                    let __mx_value: &#ty = &__mx_data;
1096                    #value
1097                },
1098                ::core::option::Option::None,
1099            );
1100            unsafe {
1101                ::miniextendr_api::deferred_condition::finish(
1102                    __miniextendr_deferred_mark,
1103                    __miniextendr_value,
1104                    ::core::option::Option::None,
1105                )
1106            }
1107        }
1108
1109        #(#cfg_attrs)*
1110        #[doc(hidden)]
1111        #registration
1112    };
1113
1114    if let Some(names) = &fallback.names {
1115        let names_path = path(names);
1116        let span = names.span();
1117        let value = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "let");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "__mx_names");
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "std");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "vec");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Vec");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "std");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "string");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "String");
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_eq_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&names_path, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "__mx_value");
            _s
        });
    ::quote::__private::push_semi_spanned(&mut _s, _span);
    _s
}quote_spanned! {span=>
1118            let __mx_names: ::std::vec::Vec<::std::string::String> = #names_path(__mx_value);
1119        };
1120        let c_ident = match ::quote::__private::IdentFragmentAdapter(&crate::naming::sidecar_fallback_names_c_name(&type_name))
    {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!(
1121            "{}",
1122            crate::naming::sidecar_fallback_names_c_name(&type_name)
1123        );
1124        let def_ident = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__MX_CALL_DEF_RDATA_NAMES_{0}",
                        type_name))
            }), ::quote::__private::Option::None)format_ident!("__MX_CALL_DEF_RDATA_NAMES_{type_name}");
1125        let registration = crate::call_method_def::call_method_def(&def_ident, &c_ident, 1);
1126        let doc = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Generated completions of the field fallback of Rust type `{1}` (`fallback_names = {0:?}`).",
                names.value(), type_name))
    })format!(
1127            "Generated completions of the field fallback of Rust type `{type_name}` \
1128             (`fallback_names = {:?}`).",
1129            names.value()
1130        );
1131        entries.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_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, "doc");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&doc, &mut _s);
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "hidden");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "no_mangle");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "non_snake_case");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "pub");
    ::quote::__private::push_ident(&mut _s, "unsafe");
    ::quote::__private::push_ident(&mut _s, "extern");
    ::quote::__private::parse(&mut _s, "\"C-unwind\"");
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::ToTokens::to_tokens(&c_ident, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "x");
            ::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, "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, "let");
            ::quote::__private::push_ident(&mut _s,
                "__miniextendr_deferred_mark");
            ::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, "deferred_condition");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "mark");
            ::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, "__miniextendr_value");
            ::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, "unwind_protect");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "with_r_unwind_protect");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_or_or(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_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, "into_r");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "IntoR");
                            ::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, "unsafe");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "externalptr");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "sidecar_r_live");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_lt(&mut _s);
                                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                                    ::quote::__private::push_gt(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "x");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "false");
                                            _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, "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, "vec");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "Vec");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_lt(&mut _s);
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "std");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "string");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "String");
                                    ::quote::__private::push_gt(&mut _s);
                                    ::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_dot(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "into_sexp");
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        ::quote::__private::TokenStream::new());
                                    ::quote::__private::push_semi(&mut _s);
                                    _s
                                });
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "__mx_data");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "unsafe");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "externalptr");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "sidecar_r_struct");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_lt(&mut _s);
                                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                                    ::quote::__private::push_gt(&mut _s);
                                    ::quote::__private::push_group(&mut _s,
                                        ::quote::__private::Delimiter::Parenthesis,
                                        {
                                            let mut _s = ::quote::__private::TokenStream::new();
                                            ::quote::__private::push_ident(&mut _s, "x");
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "__mx_value");
                            ::quote::__private::push_colon(&mut _s);
                            ::quote::__private::push_and(&mut _s);
                            ::quote::ToTokens::to_tokens(&ty, &mut _s);
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_and(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "__mx_data");
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::ToTokens::to_tokens(&value, &mut _s);
                            ::quote::__private::push_ident(&mut _s, "__mx_names");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "into_sexp");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                ::quote::__private::TokenStream::new());
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "core");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "None");
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "unsafe");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "deferred_condition");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "finish");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s,
                                "__miniextendr_deferred_mark");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "__miniextendr_value");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "core");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "Option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "None");
                            ::quote::__private::push_comma(&mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_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, "doc");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "hidden");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&registration, &mut _s);
    _s
}quote! {
1132            #(#cfg_attrs)*
1133            #[doc = #doc]
1134            #[doc(hidden)]
1135            #[unsafe(no_mangle)]
1136            #[allow(non_snake_case)]
1137            pub unsafe extern "C-unwind" fn #c_ident(
1138                x: ::miniextendr_api::SEXP,
1139            ) -> ::miniextendr_api::SEXP {
1140                let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
1141                let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
1142                    || {
1143                        use ::miniextendr_api::into_r::IntoR;
1144                        if !unsafe { ::miniextendr_api::externalptr::sidecar_r_live::<#ty>(x, false) } {
1145                            return ::std::vec::Vec::<::std::string::String>::new().into_sexp();
1146                        }
1147                        let __mx_data =
1148                            unsafe { ::miniextendr_api::externalptr::sidecar_r_struct::<#ty>(x) };
1149                        let __mx_value: &#ty = &__mx_data;
1150                        #value
1151                        __mx_names.into_sexp()
1152                    },
1153                    ::core::option::Option::None,
1154                );
1155                unsafe {
1156                    ::miniextendr_api::deferred_condition::finish(
1157                        __miniextendr_deferred_mark,
1158                        __miniextendr_value,
1159                        ::core::option::Option::None,
1160                    )
1161                }
1162            }
1163
1164            #(#cfg_attrs)*
1165            #[doc(hidden)]
1166            #registration
1167        });
1168    }
1169    entries
1170}