Skip to main content

miniextendr_macros/
all_equal_derive.rs

1//! # `#[derive(AllEqual)]` - `all.equal()` for a pointer-backed class (#2149)
2//!
3//! `all.equal()` on two objects of a class backed by an external pointer
4//! returns `TRUE` whatever they hold: `all.equal.default()` compares only
5//! `data.class()` for an external pointer, and an env-based (R6) or S4 object
6//! leads base R to the pointer, which it again can't look into. The derive
7//! gives the type's class an `all.equal()` method that compares the struct
8//! field by field, each with base `all.equal()` on the field's R value, so
9//! each field dispatches on its own class: numbers keep R's tolerance, lists
10//! and data frames use base's methods, and a field holding another pointer
11//! class (`T`, `ExternalPtr<T>`, `Option<ExternalPtr<T>>`, or a `Vec` of `T`
12//! or `ExternalPtr<T>`) uses `T`'s method.
13//!
14//! ## What the derive emits
15//!
16//! - One `.Call` entry, `C_<crate>__mx_all_equal_<Type>(x, i)`, of the
17//!   sidecar accessors' kind (no call slot): it returns compared field `i`
18//!   (1-based) of the Rust value `x` carries, `x` being any receiver
19//!   `sidecar_r_struct` reads (a pointer, or an R6 / S4 / S7 object, a list
20//!   or an environment holding one in `.ptr`). Reading the value refuses a
21//!   restored object with the type's `miniextendr_restored_*` error. A
22//!   field's R value is
23//!   - by default a clone converted with `IntoR` (`Clone + IntoR`);
24//!   - `#[all_equal(with = "Self::f")]`: the getter's value, a
25//!     `fn(&Self) -> impl IntoR`;
26//!   - a `Computed` field (`#[r_data(get = "Self::f")]`): its getter's value;
27//!   - a `Sidecar<T>` field: its slot in the pointer's protection list;
28//!   - an `ExternalPtr<T>` or `Option<ExternalPtr<T>>` field: the pointer
29//!     itself (no copy).
30//!
31//!   The `RSidecar` selector holds nothing and is never compared. Each call
32//!   returns one value, so no R value is held across an allocation.
33//! - The R value of a field whose type names a pointer class is a bare
34//!   external pointer (or a list of them), which base `all.equal()` would
35//!   find equal to any other. The method gives it the class's R class, as a
36//!   method returning that type does (`.__MX_WRAP_RETURN_T__` and
37//!   `.__MX_WRAP_LIST_RETURN_T__`, resolved when the wrappers are written),
38//!   so the comparison dispatches to the class's own `all.equal()`. The
39//!   field types are read as the method return types are
40//!   (`ParsedMethod::inner_class_ident`), so `T`, `ExternalPtr<T>`,
41//!   `Option<ExternalPtr<T>>` and a `Vec` of `T` or `ExternalPtr<T>` are
42//!   wrapped (`Option<T>` of a class `T` is not `IntoR`, so it does not
43//!   compile); a `T` that is not a class is left as it is. A getter's type (`with`, `Computed`) is
44//!   not known to the derive, so a getter returning a pointer gives a bare
45//!   pointer (#2191).
46//! - A `registry::AllEqualEntry` with the method's R source and its page.
47//!   The class system and R class name are on the type's impl block, a
48//!   separate expansion, so the wrapper writer names and registers the
49//!   method (`registry::all_equal_fragments`).
50//!
51//! ## The method
52//!
53//! `all.equal.<Class>(target, current, tolerance, scale, ..., check.attributes,
54//! check.names)`, in the argument order of `all.equal.numeric()`, so a third
55//! positional argument is the tolerance as it is for numbers:
56//!
57//! - A `current` whose `data.class()` differs from `target`'s gives base's
58//!   one string, `"target is <class>, current is <class>"`, before any field
59//!   is read.
60//! - Each compared field is compared with
61//!   `all.equal(target_field, current_field, <settings>, ...)`. A setting is
62//!   passed only when something sets it, so a field's own method keeps its
63//!   default otherwise: the field's `#[all_equal(...)]` fixes it, else the
64//!   call gives it, else the struct's `#[all_equal(...)]` is the formal's
65//!   default. The settings are formals, so a call's `check.attributes` can't
66//!   also reach a field through `...`.
67//! - The result is `TRUE`, or every field's messages in field order, each
68//!   with `all.equal.list()`'s prefix (`Component “estimates”: `, or
69//!   `Component 1: ` for a tuple field) or the field's
70//!   `#[all_equal(label = "...")]` (`Estimates: `).
71
72use proc_macro2::{Span, TokenStream};
73use quote::{format_ident, quote, quote_spanned};
74use syn::spanned::Spanned;
75use syn::{DeriveInput, LitStr};
76
77use crate::externalptr_derive::{SlotKind, is_rsidecar_type, parse_sidecar_info};
78use crate::miniextendr_impl::{ClassSystem, ParsedMethod};
79
80// region: settings
81
82/// An argument of base `all.equal()` the struct or a field can set.
83#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Setting { }
#[automatically_derived]
impl ::core::clone::Clone for Setting {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Setting { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for Setting {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                Setting::Tolerance => "Tolerance",
                Setting::Scale => "Scale",
                Setting::CheckAttributes => "CheckAttributes",
                Setting::CheckNames => "CheckNames",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Setting { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Setting {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Setting { }Eq)]
84enum Setting {
85    Tolerance,
86    Scale,
87    CheckAttributes,
88    CheckNames,
89}
90
91impl Setting {
92    /// Every setting, in the method's formal order.
93    const ALL: [Self; 4] = [
94        Self::Tolerance,
95        Self::Scale,
96        Self::CheckAttributes,
97        Self::CheckNames,
98    ];
99
100    /// The name in `#[all_equal(...)]`.
101    fn rust_name(self) -> &'static str {
102        match self {
103            Self::Tolerance => "tolerance",
104            Self::Scale => "scale",
105            Self::CheckAttributes => "check_attributes",
106            Self::CheckNames => "check_names",
107        }
108    }
109
110    /// The method's formal, and the argument of `all.equal()` it fills.
111    fn r_name(self) -> &'static str {
112        match self {
113            Self::Tolerance => "tolerance",
114            Self::Scale => "scale",
115            Self::CheckAttributes => "check.attributes",
116            Self::CheckNames => "check.names",
117        }
118    }
119
120    /// Whether the formal comes before `...`, as in `all.equal.numeric()`.
121    fn before_dots(self) -> bool {
122        #[allow(non_exhaustive_omitted_patterns)] match self {
    Self::Tolerance | Self::Scale => true,
    _ => false,
}matches!(self, Self::Tolerance | Self::Scale)
123    }
124
125    fn from_path(path: &syn::Path) -> Option<Self> {
126        Self::ALL
127            .into_iter()
128            .find(|setting| path.is_ident(setting.rust_name()))
129    }
130
131    /// The value of `name = value` as R source: a number for `tolerance`
132    /// (not negative) and `scale` (positive), `TRUE` / `FALSE` for the checks.
133    fn parse_value(self, meta: &syn::meta::ParseNestedMeta) -> syn::Result<String> {
134        let expr: syn::Expr = meta.value()?.parse()?;
135        let lit = match &expr {
136            syn::Expr::Lit(lit) => Some(&lit.lit),
137            _ => None,
138        };
139        match self {
140            Self::Tolerance | Self::Scale => {
141                let number = match lit {
142                    Some(syn::Lit::Float(lit)) => lit.base10_parse::<f64>().ok(),
143                    Some(syn::Lit::Int(lit)) => lit.base10_parse::<f64>().ok(),
144                    _ => None,
145                };
146                let (kind, example) = if self == Self::Scale {
147                    ("a positive", "scale = 1")
148                } else {
149                    ("a non-negative", "tolerance = 1e-6")
150                };
151                match number {
152                    Some(n) if n.is_finite() && (n > 0.0 || (n == 0.0 && self != Self::Scale)) => {
153                        Ok(r_number(n))
154                    }
155                    _ => Err(syn::Error::new_spanned(
156                        &expr,
157                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` takes {1} number, e.g. `{2}`",
                self.rust_name(), kind, example))
    })format!(
158                            "`{}` takes {kind} number, e.g. `{example}`",
159                            self.rust_name()
160                        ),
161                    )),
162                }
163            }
164            Self::CheckAttributes | Self::CheckNames => match lit {
165                Some(syn::Lit::Bool(lit)) => {
166                    Ok(if lit.value { "TRUE" } else { "FALSE" }.to_owned())
167                }
168                _ => Err(syn::Error::new_spanned(
169                    &expr,
170                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` takes `true` or `false`",
                self.rust_name()))
    })format!("`{}` takes `true` or `false`", self.rust_name()),
171                )),
172            },
173        }
174    }
175}
176
177/// A finite number as R source: a whole number without a fraction
178/// (`0`, `2`), any other in Rust's shortest form (`1e-6`, `0.5`).
179fn r_number(n: f64) -> String {
180    if n.fract() == 0.0 && n.abs() < 1e15 {
181        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:.0}", n))
    })format!("{n:.0}")
182    } else {
183        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", n))
    })format!("{n:?}")
184    }
185}
186
187/// The settings given, with their values as R source, in source order.
188type Settings = Vec<(Setting, String)>;
189
190/// Adds the setting `meta` names to `settings`, refusing a second one.
191fn push_setting(
192    settings: &mut Settings,
193    setting: Setting,
194    meta: &syn::meta::ParseNestedMeta,
195) -> syn::Result<()> {
196    if settings.iter().any(|(given, _)| *given == setting) {
197        return Err(meta.error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` is given twice",
                setting.rust_name()))
    })format!("`{}` is given twice", setting.rust_name())));
198    }
199    let value = setting.parse_value(meta)?;
200    settings.push((setting, value));
201    Ok(())
202}
203
204/// The value `settings` gives `setting`.
205fn setting_value(settings: &Settings, setting: Setting) -> Option<&str> {
206    settings
207        .iter()
208        .find(|(given, _)| *given == setting)
209        .map(|(_, value)| value.as_str())
210}
211
212/// The struct's `#[all_equal(...)]`: the defaults of the method's formals.
213fn parse_struct_settings(input: &DeriveInput) -> syn::Result<Settings> {
214    let mut settings = Settings::new();
215    for attr in input
216        .attrs
217        .iter()
218        .filter(|a| a.path().is_ident("all_equal"))
219    {
220        attr.parse_nested_meta(|meta| {
221            if let Some(setting) = Setting::from_path(&meta.path) {
222                return push_setting(&mut settings, setting, &meta);
223            }
224            let key = path_name(&meta.path);
225            if ["skip", "label", "with"].contains(&key.as_str()) {
226                Err(meta.error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` applies to a field; the struct\'s `#[all_equal(...)]` takes `tolerance`, `scale`, `check_attributes` and `check_names`",
                key))
    })format!(
227                    "`{key}` applies to a field; the struct's `#[all_equal(...)]` takes \
228                     `tolerance`, `scale`, `check_attributes` and `check_names`"
229                )))
230            } else {
231                Err(meta.error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unknown `all_equal` option `{0}`; the struct\'s `#[all_equal(...)]` takes `tolerance`, `scale`, `check_attributes` and `check_names`",
                key))
    })format!(
232                    "unknown `all_equal` option `{key}`; the struct's `#[all_equal(...)]` takes \
233                     `tolerance`, `scale`, `check_attributes` and `check_names`"
234                )))
235            }
236        })?;
237    }
238    Ok(settings)
239}
240
241fn path_name(path: &syn::Path) -> String {
242    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&path, &mut _s);
    _s
}quote!(#path).to_string().replace(' ', "")
243}
244
245// endregion
246
247// region: fields
248
249/// A field's `#[all_equal(...)]`.
250#[derive(#[automatically_derived]
impl ::core::default::Default for FieldOptions {
    #[inline]
    fn default() -> Self {
        FieldOptions {
            skip: ::core::default::Default::default(),
            label: ::core::default::Default::default(),
            with: ::core::default::Default::default(),
            settings: ::core::default::Default::default(),
        }
    }
}Default)]
251struct FieldOptions {
252    /// `skip`: the field is not compared.
253    skip: Option<Span>,
254    /// `label = "..."`: the prefix of the field's messages, before `": "`.
255    label: Option<LitStr>,
256    /// `with = "Self::f"`: the getter whose value is compared.
257    with: Option<LitStr>,
258    /// The settings that field fixes.
259    settings: Settings,
260}
261
262fn parse_field_options(field: &syn::Field) -> syn::Result<FieldOptions> {
263    let mut options = FieldOptions::default();
264    // Where the first option other than `skip` is given.
265    let mut other: Option<Span> = None;
266    for attr in field
267        .attrs
268        .iter()
269        .filter(|a| a.path().is_ident("all_equal"))
270    {
271        attr.parse_nested_meta(|meta| {
272            let key = path_name(&meta.path);
273            let twice = || meta.error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` is given twice", key))
    })format!("`{key}` is given twice"));
274            if key == "skip" {
275                if options.skip.is_some() {
276                    return Err(twice());
277                }
278                options.skip = Some(meta.path.span());
279                return Ok(());
280            }
281            other.get_or_insert(meta.path.span());
282            match key.as_str() {
283                "label" => {
284                    if options.label.is_some() {
285                        return Err(twice());
286                    }
287                    options.label = Some(meta.value()?.parse()?);
288                }
289                "with" => {
290                    if options.with.is_some() {
291                        return Err(twice());
292                    }
293                    options.with = Some(meta.value()?.parse()?);
294                }
295                _ => match Setting::from_path(&meta.path) {
296                    Some(setting) => push_setting(&mut options.settings, setting, &meta)?,
297                    None => {
298                        return Err(meta.error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unknown `all_equal` option `{0}`; a field takes `skip`, `label = \"...\"`, `with = \"Self::f\"`, `tolerance`, `scale`, `check_attributes` and `check_names`",
                key))
    })format!(
299                            "unknown `all_equal` option `{key}`; a field takes `skip`, \
300                             `label = \"...\"`, `with = \"Self::f\"`, `tolerance`, `scale`, \
301                             `check_attributes` and `check_names`"
302                        )));
303                    }
304                },
305            }
306            Ok(())
307        })?;
308    }
309    if let (Some(skip), Some(_)) = (options.skip, other) {
310        return Err(syn::Error::new(
311            skip,
312            "`skip` leaves the field out of the comparison, so it takes no other option",
313        ));
314    }
315    Ok(options)
316}
317
318/// Where a compared field's R value comes from (see the module docs).
319enum FieldValue {
320    /// A clone of the field, converted with `IntoR`.
321    Converted,
322    /// A getter's value: `with = "..."`, or a `Computed` field's `get`. The
323    /// path has its leading `Self` replaced; the span is the attribute's.
324    Getter(syn::Path, Span),
325    /// A `Sidecar<T>` field: this slot of the pointer's protection list.
326    Sidecar(usize),
327    /// An `ExternalPtr<T>` field (`optional`: `Option<ExternalPtr<T>>`): the
328    /// pointer itself.
329    Pointer { optional: bool },
330}
331
332/// The class the method gives a field's R value: the R class of the Rust
333/// type `class`, on the value (`list`: on each element of the list), unless
334/// the value is `NULL` (`optional`: an `Option` field's `None`).
335struct ClassWrap {
336    class: String,
337    list: bool,
338    optional: bool,
339}
340
341impl ClassWrap {
342    /// The wrap marker for `.val`, which the wrappers writer resolves.
343    fn r_expression(&self) -> String {
344        let class = &self.class;
345        let wrapped = if self.list {
346            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".__MX_WRAP_LIST_RETURN_{0}__(.val)",
                class))
    })format!(".__MX_WRAP_LIST_RETURN_{class}__(.val)")
347        } else {
348            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".__MX_WRAP_RETURN_{0}__(.val)",
                class))
    })format!(".__MX_WRAP_RETURN_{class}__(.val)")
349        };
350        if self.optional {
351            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("if (is.null(.val)) NULL else {0}",
                wrapped))
    })format!("if (is.null(.val)) NULL else {wrapped}")
352        } else {
353            wrapped
354        }
355    }
356}
357
358/// A field the method compares.
359struct ComparedField {
360    member: syn::Member,
361    ty: syn::Type,
362    /// The field's R name: `#[r_data(name = "...")]`, else the identifier,
363    /// or the 1-based position of a tuple field.
364    name: String,
365    label: Option<String>,
366    settings: Settings,
367    value: FieldValue,
368    /// The class of a field whose type names a pointer class.
369    wrap: Option<ClassWrap>,
370}
371
372impl ComparedField {
373    /// The R expression of the prefix of the field's messages.
374    fn prefix(&self) -> String {
375        match (&self.label, &self.member) {
376            (Some(label), _) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"{0}: \"",
                crate::naming::r_string_escape(label)))
    })format!("\"{}: \"", crate::naming::r_string_escape(label)),
377            (None, syn::Member::Named(_)) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("paste0(\"Component \", dQuote(\"{0}\"), \": \")",
                crate::naming::r_string_escape(&self.name)))
    })format!(
378                "paste0(\"Component \", dQuote(\"{}\"), \": \")",
379                crate::naming::r_string_escape(&self.name)
380            ),
381            (None, syn::Member::Unnamed(_)) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"Component {0}: \"", self.name))
    })format!("\"Component {}: \"", self.name),
382        }
383    }
384}
385
386/// The class of a field of type `ty` when it names a pointer class, read as a
387/// method's return type is: `T` or `ExternalPtr<T>` (`T` a capitalized path
388/// that is not a builtin), in `Option<..>`, `Vec<..>` or `Option<Vec<..>>`.
389/// Whether `T` is a class is known when the wrappers are written; a `T` that
390/// is not keeps the value as it is.
391fn class_wrap(ty: &syn::Type) -> Option<ClassWrap> {
392    let (inner, optional) = match option_inner(ty) {
393        Some(inner) => (inner, true),
394        None => (ty, false),
395    };
396    let (class, list) = match ParsedMethod::vec_inner_class_ident(inner) {
397        Some(class) => (class, true),
398        None => (ParsedMethod::inner_class_ident(inner)?, false),
399    };
400    Some(ClassWrap {
401        class: class.to_string(),
402        list,
403        optional,
404    })
405}
406
407/// `T` of `Option<T>`.
408fn option_inner(ty: &syn::Type) -> Option<&syn::Type> {
409    let syn::Type::Path(path) = ty else {
410        return None;
411    };
412    let segment = path.path.segments.last()?;
413    if segment.ident != "Option" {
414        return None;
415    }
416    crate::first_type_argument(segment)
417}
418
419/// Whether `ty` is `ExternalPtr<T>`.
420fn is_external_ptr(ty: &syn::Type) -> bool {
421    #[allow(non_exhaustive_omitted_patterns)] match ty {
    syn::Type::Path(path) if
        path.path.segments.last().is_some_and(|segment|
                segment.ident == "ExternalPtr") => true,
    _ => false,
}matches!(ty, syn::Type::Path(path)
422        if path.path.segments.last().is_some_and(|segment| segment.ident == "ExternalPtr"))
423}
424
425/// A getter path from `with = "..."`, its leading `Self` replaced by the
426/// struct's name: the `.Call` entry is a free function, outside any impl.
427fn getter_path(lit: &LitStr, struct_name: &syn::Ident) -> syn::Result<syn::Path> {
428    let mut path: syn::Path = lit.parse().map_err(|err| {
429        syn::Error::new_spanned(
430            lit,
431            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`with` must be a path to a getter function, e.g. `Self::f`: {0}",
                err))
    })format!("`with` must be a path to a getter function, e.g. `Self::f`: {err}"),
432        )
433    })?;
434    if let Some(first) = path.segments.first_mut()
435        && first.ident == "Self"
436    {
437        first.ident = syn::Ident::new(&struct_name.to_string(), first.ident.span());
438    }
439    Ok(path)
440}
441
442/// The fields the method compares, in declaration order.
443fn compared_fields(input: &DeriveInput) -> syn::Result<Vec<ComparedField>> {
444    let syn::Data::Struct(data) = &input.data else {
445        return Err(syn::Error::new_spanned(
446            &input.ident,
447            "`AllEqual` derives on a struct: it compares the struct's fields",
448        ));
449    };
450    // The `#[r_data]` fields; `#[derive(ExternalPtr)]` reports what is wrong
451    // with them, so a struct it refuses compares no sidecar field here.
452    let slots = parse_sidecar_info(input, ClassSystem::Env)
453        .map(|info| info.slots)
454        .unwrap_or_default();
455    let mut fields = Vec::new();
456    for (i, field) in data.fields.iter().enumerate() {
457        let options = parse_field_options(field)?;
458        if options.skip.is_some() || is_rsidecar_type(field) {
459            continue;
460        }
461        let member = match &field.ident {
462            Some(ident) => syn::Member::Named(ident.clone()),
463            None => syn::Member::Unnamed(syn::Index::from(i)),
464        };
465        let slot = field
466            .ident
467            .as_ref()
468            .and_then(|ident| slots.iter().find(|slot| slot.name == *ident));
469        let name = match (slot, &field.ident) {
470            (Some(slot), _) => slot.r_name.clone(),
471            (None, Some(ident)) => crate::naming::ident_name(ident),
472            (None, None) => (i + 1).to_string(),
473        };
474        let (value, wrap) = if let Some(with) = &options.with {
475            let getter = getter_path(with, &input.ident)?;
476            (FieldValue::Getter(getter, with.span()), None)
477        } else if let Some(slot) = slot
478            && let SlotKind::Sidecar(index) = slot.kind
479        {
480            (FieldValue::Sidecar(index), None)
481        } else if let Some(slot) = slot
482            && let SlotKind::Computed(path) = &slot.kind
483        {
484            (FieldValue::Getter(path.clone(), field.ty.span()), None)
485        } else {
486            let wrap = class_wrap(&field.ty);
487            let optional = option_inner(&field.ty);
488            let value = match &wrap {
489                // The pointer itself, not a clone of its value.
490                Some(ClassWrap { list: false, .. })
491                    if is_external_ptr(optional.unwrap_or(&field.ty)) =>
492                {
493                    FieldValue::Pointer {
494                        optional: optional.is_some(),
495                    }
496                }
497                _ => FieldValue::Converted,
498            };
499            (value, wrap)
500        };
501        fields.push(ComparedField {
502            member,
503            ty: field.ty.clone(),
504            name,
505            label: options.label.as_ref().map(LitStr::value),
506            settings: options.settings,
507            value,
508            wrap,
509        });
510    }
511    if fields.is_empty() {
512        return Err(syn::Error::new_spanned(
513            &input.ident,
514            "`#[derive(AllEqual)]` has no field to compare: every field is skipped \
515             (`#[all_equal(skip)]`, or the `RSidecar` selector)",
516        ));
517    }
518    Ok(fields)
519}
520
521// endregion
522
523// region: the R method
524
525/// The method's R source, `function(target, current, ...) { ... }`, reading
526/// the fields through the `.Call` entry `c_name`.
527fn r_method(c_name: &str, struct_settings: &Settings, fields: &[ComparedField]) -> String {
528    let formal = |setting: Setting| match setting_value(struct_settings, setting) {
529        Some(value) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} = {1}", setting.r_name(),
                value))
    })format!("{} = {value}", setting.r_name()),
530        None => setting.r_name().to_owned(),
531    };
532    let mut formals = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["target".to_owned(), "current".to_owned()]))vec!["target".to_owned(), "current".to_owned()];
533    formals.extend(
534        Setting::ALL
535            .into_iter()
536            .filter(|s| s.before_dots())
537            .map(formal),
538    );
539    formals.push("...".to_owned());
540    formals.extend(
541        Setting::ALL
542            .into_iter()
543            .filter(|s| !s.before_dots())
544            .map(formal),
545    );
546
547    let guard =
548        crate::method_return_builder::condition_check_lines_with_default("  ", "environment()");
549    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!("function({0}) {{",
                                formals.join(", ")))
                    }),
                "  if (data.class(target) != data.class(current)) {".to_owned(),
                "    return(gettextf(\"target is %s, current is %s\", data.class(target), \
         data.class(current), domain = \"R-base\"))".to_owned(),
                "  }".to_owned(), "  .settings <- list()".to_owned()]))vec![
550        format!("function({}) {{", formals.join(", ")),
551        "  if (data.class(target) != data.class(current)) {".to_owned(),
552        "    return(gettextf(\"target is %s, current is %s\", data.class(target), \
553         data.class(current), domain = \"R-base\"))"
554            .to_owned(),
555        "  }".to_owned(),
556        "  .settings <- list()".to_owned(),
557    ];
558    for setting in Setting::ALL {
559        let r = setting.r_name();
560        let set = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".settings[\"{0}\"] <- list({0})",
                r))
    })format!(".settings[\"{r}\"] <- list({r})");
561        lines.push(if setting_value(struct_settings, setting).is_some() {
562            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  {0}", set))
    })format!("  {set}")
563        } else {
564            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (!missing({0})) {1}", r, set))
    })format!("  if (!missing({r})) {set}")
565        });
566    }
567    lines.push("  .dots <- list(...)".to_owned());
568    lines.push("  .msg <- character(0)".to_owned());
569    for (i, field) in fields.iter().enumerate() {
570        let index = i + 1;
571        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  # `{0}`", field.name))
    })format!("  # `{}`", field.name));
572        for (receiver, var) in [("target", ".target"), ("current", ".current")] {
573            lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- .Call({0}, {1}, {2}L)",
                c_name, receiver, index))
    })format!("  .val <- .Call({c_name}, {receiver}, {index}L)"));
574            lines.extend(guard.iter().cloned());
575            let value = field.wrap.as_ref().map(ClassWrap::r_expression);
576            lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  {1} <- {0}",
                value.as_deref().unwrap_or(".val"), var))
    })format!("  {var} <- {}", value.as_deref().unwrap_or(".val")));
577        }
578        let args = if field.settings.is_empty() {
579            ".settings"
580        } else {
581            lines.push("  .args <- .settings".to_owned());
582            for setting in Setting::ALL {
583                if let Some(value) = setting_value(&field.settings, setting) {
584                    lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .args[\"{0}\"] <- list({1})",
                setting.r_name(), value))
    })format!(
585                        "  .args[\"{}\"] <- list({value})",
586                        setting.r_name()
587                    ));
588                }
589            }
590            ".args"
591        };
592        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  .val <- do.call(all.equal, c(list(.target, .current), {0}, .dots))",
                args))
    })format!(
593            "  .val <- do.call(all.equal, c(list(.target, .current), {args}, .dots))"
594        ));
595        lines.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("  if (is.character(.val)) .msg <- c(.msg, paste0({0}, .val))",
                field.prefix()))
    })format!(
596            "  if (is.character(.val)) .msg <- c(.msg, paste0({}, .val))",
597            field.prefix()
598        ));
599    }
600    lines.push("  if (length(.msg)) .msg else TRUE".to_owned());
601    lines.push("}".to_owned());
602    lines.join("\n")
603}
604
605/// The roxygen lines of the method's page after its title.
606fn r_docs(type_name: &str, struct_settings: &Settings, fields: &[ComparedField]) -> String {
607    let listed: Vec<String> = fields
608        .iter()
609        .map(|field| {
610            let fixed: Vec<String> = Setting::ALL
611                .into_iter()
612                .filter_map(|setting| {
613                    setting_value(&field.settings, setting)
614                        .map(|value| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0} = {1}`", setting.r_name(),
                value))
    })format!("`{} = {value}`", setting.r_name()))
615                })
616                .collect();
617            if fixed.is_empty() {
618                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", field.name))
    })format!("`{}`", field.name)
619            } else {
620                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` ({1})", field.name,
                fixed.join(", ")))
    })format!("`{}` ({})", field.name, fixed.join(", "))
621            }
622        })
623        .collect();
624    let listed = match &listed[..] {
625        [one] => one.clone(),
626        [init @ .., last] => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} and {1}", init.join(", "),
                last))
    })format!("{} and {last}", init.join(", ")),
627        [] => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("a derive compares at least one field")));
}unreachable!("a derive compares at least one field"),
628    };
629    let defaults: Vec<String> = Setting::ALL
630        .into_iter()
631        .filter_map(|setting| {
632            setting_value(struct_settings, setting)
633                .map(|value| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0} = {1}`", setting.r_name(),
                value))
    })format!("`{} = {value}`", setting.r_name()))
634        })
635        .collect();
636    let defaults = if defaults.is_empty() {
637        String::new()
638    } else {
639        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\n#\'   The type\'s defaults are {0}.",
                match &defaults[..] {
                    [one] => one.clone(),
                    [init @ .., last] =>
                        ::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("{0} and {1}",
                                        init.join(", "), last))
                            }),
                    [] =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }))
    })format!(
640            "\n#'   The type's defaults are {}.",
641            match &defaults[..] {
642                [one] => one.clone(),
643                [init @ .., last] => format!("{} and {last}", init.join(", ")),
644                [] => unreachable!(),
645            }
646        )
647    };
648    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("#\' The `all.equal()` method of the Rust type `{0}`, from\n#\' `#[derive(AllEqual)]`. It compares `target` and `current` field by field,\n#\' each field with `all.equal()`, which dispatches on the field\'s own class.\n#\' The fields compared: {1}.\n#\'\n#\' @param target,current The objects to compare.\n#\' @param tolerance,scale,check.attributes,check.names Passed on to the\n#\'   comparison of each field when the call or the type gives them, unless\n#\'   the field fixes its own; see [base::all.equal()].{2}\n#\' @param ... Passed on to the comparison of each field.\n#\' @return `TRUE` when every field is equal, otherwise a character vector of\n#\'   the differences, each prefixed with its field.",
                type_name, listed, defaults))
    })format!(
649        "#' The `all.equal()` method of the Rust type `{type_name}`, from\n\
650         #' `#[derive(AllEqual)]`. It compares `target` and `current` field by field,\n\
651         #' each field with `all.equal()`, which dispatches on the field's own class.\n\
652         #' The fields compared: {listed}.\n\
653         #'\n\
654         #' @param target,current The objects to compare.\n\
655         #' @param tolerance,scale,check.attributes,check.names Passed on to the\n\
656         #'   comparison of each field when the call or the type gives them, unless\n\
657         #'   the field fixes its own; see [base::all.equal()].{defaults}\n\
658         #' @param ... Passed on to the comparison of each field.\n\
659         #' @return `TRUE` when every field is equal, otherwise a character vector of\n\
660         #'   the differences, each prefixed with its field."
661    )
662}
663
664// endregion
665
666/// `#[derive(AllEqual)]`: see the module docs.
667pub(crate) fn derive_all_equal(input: DeriveInput) -> syn::Result<TokenStream> {
668    if !input.generics.params.is_empty() {
669        return Err(syn::Error::new_spanned(
670            &input.generics,
671            "`AllEqual` does not support generic structs: its `.Call` entry cannot be generic",
672        ));
673    }
674    let struct_settings = parse_struct_settings(&input)?;
675    let fields = compared_fields(&input)?;
676
677    let name = &input.ident;
678    let type_name = crate::naming::ident_name(name);
679    let c_name = crate::naming::all_equal_c_name(&type_name);
680    let c_ident = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("{0}", c_name))
            }), ::quote::__private::Option::None)format_ident!("{c_name}");
681
682    let arms = fields.iter().enumerate().map(|(i, field)| {
683        let index = i32::try_from(i + 1).expect("a struct has fewer than i32::MAX fields");
684        let member = &field.member;
685        let borrow = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::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(&name, &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(&name, &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);
    _s
}quote! {
686            let __mx_data = unsafe { ::miniextendr_api::externalptr::sidecar_r_struct::<#name>(x) };
687            let __mx_value: &#name = &__mx_data;
688        };
689        let body = match &field.value {
690            // The conversion is spanned at the field's type, so a type that
691            // is not `Clone + IntoR` is reported there.
692            FieldValue::Converted => {
693                let convert = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(field.ty.span()).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "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_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, "clone");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Clone");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "clone");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_and_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "__mx_value");
                    ::quote::__private::push_dot_spanned(&mut _s, _span);
                    ::quote::ToTokens::to_tokens(&member, &mut _s);
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote_spanned! {field.ty.span()=>
694                    ::miniextendr_api::into_r::IntoR::into_sexp(
695                        ::core::clone::Clone::clone(&__mx_value.#member),
696                    )
697                };
698                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&borrow, &mut _s);
            ::quote::ToTokens::to_tokens(&convert, &mut _s);
            _s
        });
    _s
}quote! {{ #borrow #convert }}
699            }
700            FieldValue::Getter(path, span) => {
701                let convert = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(*span).__into_span();
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "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::ToTokens::to_tokens(&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
                });
            _s
        });
    _s
}quote_spanned! {*span=>
702                    ::miniextendr_api::into_r::IntoR::into_sexp(#path(__mx_value))
703                };
704                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&borrow, &mut _s);
            ::quote::ToTokens::to_tokens(&convert, &mut _s);
            _s
        });
    _s
}quote! {{ #borrow #convert }}
705            }
706            FieldValue::Sidecar(index) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "unsafe");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "externalptr");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "sidecar_r_get");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&name, &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::ToTokens::to_tokens(&index, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "true");
                    _s
                });
            _s
        });
    _s
}quote! {
707                unsafe { ::miniextendr_api::externalptr::sidecar_r_get::<#name>(x, #index, true) }
708            },
709            FieldValue::Pointer { optional: false } => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&borrow, &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, "into_r");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "IntoR");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_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, "ExternalPtr");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "same_object");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_and(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "__mx_value");
                            ::quote::__private::push_dot(&mut _s);
                            ::quote::ToTokens::to_tokens(&member, &mut _s);
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            _s
        });
    _s
}quote! {{
710                #borrow
711                ::miniextendr_api::into_r::IntoR::into_sexp(
712                    ::miniextendr_api::externalptr::ExternalPtr::same_object(&__mx_value.#member),
713                )
714            }},
715            FieldValue::Pointer { optional: true } => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&borrow, &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, "into_r");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "IntoR");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into_sexp");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "core");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Option");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "map");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "core");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "Option");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "as_ref");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::push_and(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "__mx_value");
                                    ::quote::__private::push_dot(&mut _s);
                                    ::quote::ToTokens::to_tokens(&member, &mut _s);
                                    _s
                                });
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "externalptr");
                            ::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, "same_object");
                            ::quote::__private::push_comma(&mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {{
716                #borrow
717                ::miniextendr_api::into_r::IntoR::into_sexp(::core::option::Option::map(
718                    ::core::option::Option::as_ref(&__mx_value.#member),
719                    ::miniextendr_api::externalptr::ExternalPtr::same_object,
720                ))
721            }},
722        };
723        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&index, &mut _s);
    ::quote::__private::push_fat_arrow(&mut _s);
    ::quote::ToTokens::to_tokens(&body, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    _s
}quote! { #index => #body, }
724    });
725
726    let def_ident = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__MX_CALL_DEF_ALL_EQUAL_{0}",
                        type_name))
            }), ::quote::__private::Option::None)format_ident!("__MX_CALL_DEF_ALL_EQUAL_{type_name}");
727    let registration = crate::call_method_def::call_method_def(&def_ident, &c_ident, 2);
728    let entry_ident = ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__MX_ALL_EQUAL_{0}",
                        type_name))
            }), ::quote::__private::Option::None)format_ident!("__MX_ALL_EQUAL_{type_name}");
729    let c_doc =
730        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Generated field reader of the `all.equal()` method of Rust type `{0}`.",
                type_name))
    })format!("Generated field reader of the `all.equal()` method of Rust type `{type_name}`.");
731    let source_location_doc = crate::source_location_doc(name.span());
732    let start = name.span().start();
733    let source_line = syn::LitInt::new(&start.line.to_string(), name.span());
734    let source_column = syn::LitInt::new(&(start.column + 1).to_string(), name.span());
735    let method = LitStr::new(&r_method(&c_name, &struct_settings, &fields), name.span());
736    let docs = LitStr::new(&r_docs(&type_name, &struct_settings, &fields), name.span());
737
738    Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&c_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_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "clippy");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "clone_on_copy");
                    _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, "i");
            ::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_index");
                            ::quote::__private::push_colon(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "i32");
                            ::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, "i");
                                    _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, "index");
                                            _s
                                        });
                                    ::quote::__private::push_fat_arrow(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "index");
                                    ::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,
                                                        "\"`all.equal()` reads a field by its position: {err}\"");
                                                    _s
                                                });
                                            _s
                                        });
                                    _s
                                });
                            ::quote::__private::push_semi(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "match");
                            ::quote::__private::push_ident(&mut _s, "__mx_index");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut arms, i) = arms.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let arms =
                                                match arms.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&arms, &mut _s);
                                        }
                                    }
                                    ::quote::__private::push_underscore(&mut _s);
                                    ::quote::__private::push_fat_arrow(&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, "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,
                                                "\"`all.equal()` compares no field {} of `{}`\"");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::__private::push_ident(&mut _s, "__mx_index");
                                            ::quote::__private::push_comma(&mut _s);
                                            ::quote::ToTokens::to_tokens(&type_name, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                            _s
                                        });
                                    ::quote::__private::push_comma(&mut _s);
                                    _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
        });
    ::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);
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::parse(&mut _s,
                "r\" The `all.equal()` method\'s R source, via distributed slice.\"");
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&source_location_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, "cfg_attr");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "not");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "target_arch");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::parse(&mut _s, "\"wasm32\"");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "distributed_slice");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "registry");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "MX_ALL_EQUAL");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "crate");
                            ::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, "linkme");
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s,
                        "non_upper_case_globals");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "static");
    ::quote::ToTokens::to_tokens(&entry_ident, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "AllEqualEntry");
    ::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, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "AllEqualEntry");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "rust_type");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&type_name, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "method");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&method, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "docs");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&docs, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "source_file");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "file");
            ::quote::__private::push_bang(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "source_line");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&source_line, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "source_column");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&source_column, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
739        #[doc = #c_doc]
740        #[doc(hidden)]
741        #[unsafe(no_mangle)]
742        #[allow(non_snake_case)]
743        // A field's clone is spanned at its type, so a `Copy` field is
744        // linted in the user's crate.
745        #[allow(clippy::clone_on_copy)]
746        pub unsafe extern "C-unwind" fn #c_ident(
747            x: ::miniextendr_api::SEXP,
748            i: ::miniextendr_api::SEXP,
749        ) -> ::miniextendr_api::SEXP {
750            let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
751            let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
752                || {
753                    let __mx_index: i32 = match ::miniextendr_api::TryFromSexp::try_from_sexp(i) {
754                        ::core::result::Result::Ok(index) => index,
755                        ::core::result::Result::Err(err) => {
756                            ::core::panic!("`all.equal()` reads a field by its position: {err}")
757                        }
758                    };
759                    match __mx_index {
760                        #(#arms)*
761                        _ => ::core::panic!(
762                            "`all.equal()` compares no field {} of `{}`",
763                            __mx_index,
764                            #type_name,
765                        ),
766                    }
767                },
768                ::core::option::Option::None,
769            );
770            unsafe {
771                ::miniextendr_api::deferred_condition::finish(
772                    __miniextendr_deferred_mark,
773                    __miniextendr_value,
774                    ::core::option::Option::None,
775                )
776            }
777        }
778
779        #[doc(hidden)]
780        #registration
781
782        /// The `all.equal()` method's R source, via distributed slice.
783        #[doc = #source_location_doc]
784        #[doc(hidden)]
785        #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_ALL_EQUAL), linkme(crate = ::miniextendr_api::linkme))]
786        #[allow(non_upper_case_globals)]
787        static #entry_ident: ::miniextendr_api::registry::AllEqualEntry =
788            ::miniextendr_api::registry::AllEqualEntry {
789                rust_type: #type_name,
790                method: #method,
791                docs: #docs,
792                source_file: ::core::file!(),
793                source_line: #source_line,
794                source_column: #source_column,
795            };
796    })
797}
798
799#[cfg(test)]
800mod tests;