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.
7374use super::{ClassSystem, FieldLookup, ParsedImpl};
75use crate::naming::{RDataHelper, rdata_helper_name};
7677/// 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(...)`.
85error_class: String,
86/// `TRUE` under `restored(refuse = "every_read")` (#1901): it gates the
87 /// calls of `live`.
88every_read: String,
89/// The liveness check of `restored(refuse = "every_read")` (#1901), a
90 /// stub that is never called without it.
91live: String,
92/// The `.Call` entry of the impl's `fallback = "..."` (#2150), for a
93 /// name no field has ([`fallback_c_entries`]).
94fallback: Option<String>,
95/// The `.Call` entry of its `fallback_names = "..."`, for
96 /// `.DollarNames()`.
97fallback_names: Option<String>,
98}
99100impl Helpers {
101fn new(parsed_impl: &ParsedImpl) -> Self {
102let type_name = parsed_impl.type_ident.to_string();
103Helpers {
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_impl112 .field_fallback
113 .as_ref()
114 .map(|_| crate::naming::sidecar_fallback_c_name(&type_name)),
115 fallback_names: parsed_impl116 .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 }
122123/// 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.
129fn fallback_read(&self, receiver: &str, name: &str, indent: &str) -> Vec<String> {
130let Some(entry) = &self.fallback else {
131return Vec::new();
132 };
133let 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)];
136lines.extend(guard(indent));
137lines.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));
140lines141 }
142143/// 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.
147fn fallback_names_call(&self, receiver: &str) -> Option<String> {
148let entry = self.fallback_names.as_ref()?;
149Some(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".Call({0}, {1})", entry, receiver))
})format!(".Call({entry}, {receiver})"))
150 }
151152/// 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).
156fn dollar_names_with_fallback(value: &str, known: &str) -> Vec<String> {
157let 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}")];
158lines.extend(guard(" "));
159lines.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));
162lines163 }
164165/// 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`).
169fn live_check(&self, receiver: &str, indent: &str) -> Vec<String> {
170let 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)];
171lines.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));
172lines.extend(guard(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} ", indent))
})format!("{indent} ")));
173lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}}}", indent))
})format!("{indent}}}"));
174lines175 }
176177/// 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.
184fn every_read_check(&self) -> Vec<String> {
185let 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\")) {{",
187self.every_read
188 )];
189lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, TRUE)",
self.live))
})format!(" .val <- {}(x, TRUE)", self.live));
190lines.extend(guard(" "));
191lines.push(" }".to_string());
192lines193 }
194195/// 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.
200fn 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}
208209/// 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> {
212crate::method_return_builder::condition_check_lines_with_default(indent, "environment()")
213}
214215/// 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";
219220/// The formals of the S3 `as.list()` reader, its generic's.
221const AS_LIST_FORMALS: &str = "x, ...";
222223/// The formals of the S3 `[[<-` writer, `value` last (#1853).
224const SUBSET_ASSIGN_FORMALS: &str = "x, i, ..., value";
225226/// 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";
229230/// 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 {
237let 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}
242243/// 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 {
249let class = parsed_impl250 .r_data_accessors
251 .enabled()
252 .then(|| Helpers::new(parsed_impl).error_class);
253dots_check(ENV_SUBSET_FORMALS, class.as_deref(), " ")
254}
255256/// 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 {
259crate::roxygen::rdname_value(&parsed_impl.doc_tags)
260 .map_or_else(|| parsed_impl.class_name(), str::to_owned)
261}
262263/// 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> {
269let topic = topic(parsed_impl);
270let 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}")];
271if topic == parsed_impl.class_name() {
272lines.extend(param_lines(parsed_impl, params));
273 } else {
274lines.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 }
276lines277}
278279/// 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}
284285/// 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 {
290let helpers = Helpers::new(parsed_impl);
291let 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}
300301/// 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> {
309let documented: Vec<String> = parsed_impl310 .constructor()
311 .filter(|_| parsed_impl.class_system != ClassSystem::Env)
312 .map(|ctor| {
313let formals = ctor.formals();
314crate::r_wrapper_builder::r_formal_names(&ctor.sig.inputs, &formals)
315 .map(|(name, _)| name)
316 .collect()
317 })
318 .unwrap_or_default();
319params320 .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}
325326/// 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) {
337let class_name = parsed_impl.class_name();
338if on_page {
339lines.extend(page_lines(parsed_impl, params));
340 } else {
341lines.push("#' @noRd".to_string());
342 }
343lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method {0} {1}", generic,
class_name))
})format!("#' @method {generic} {class_name}"));
344if register {
345lines.push("#' @export".to_string());
346 }
347}
348349/// 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) {
359if on_page {
360lines.extend(page_lines(
361parsed_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 {
371lines.push("#' @noRd".to_string());
372 }
373if register {
374lines.push("#' @exportS3Method utils::.DollarNames".to_string());
375 }
376}
377378/// `$.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> {
391let class_name = parsed_impl.class_name();
392let h = Helpers::new(parsed_impl);
393let 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}"));
394let 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![
395format!(
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 ];
402403let 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));
404let x = ("x", "An object.");
405// One text for `[[`, `as.list()` and `[[<-`, which share the page.
406let 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 );
411let 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.
419let fallback = h.fallback.is_some();
420let (name, i) = match parsed_impl.field_lookup {
421 FieldLookup::Strictif 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::Listif 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 };
476let value = ("value", "The new value of the field.");
477478// `$`: 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.
483s3_method_doc(&mut lines, parsed_impl, "$", on_page, register, &[x, name]);
484lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function(x, name) {{",
def("$")))
})format!("{} <- function(x, name) {{", def("$")));
485lines.extend(h.every_read_check());
486lines.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).
489let 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 };
493if fallback {
494lines.push(" if (typeof(x) == \"externalptr\") {".to_string());
495lines.extend(h.fallback_read("x", "name", " "));
496lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", unknown("name")))
})format!(" {}", unknown("name")));
497lines.push(" }".to_string());
498 } else {
499lines.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 }
504lines.push(" if (is.list(x)) return(.subset2(x, name))".to_string());
505lines.push(" return(NextMethod())".to_string());
506lines.push(" }".to_string());
507lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, name)", h.get))
})format!(" .val <- {}(x, name)", h.get));
508lines.extend(guard(" "));
509lines.push(" .val".to_string());
510lines.push("}".to_string());
511lines.push(String::new());
512513// `[[`: 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).
524s3_method_doc(
525&mut lines,
526parsed_impl,
527"[[",
528on_page,
529register,
530&[x, i, dots, exact],
531 );
532lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
def("[["), SUBSET_FORMALS))
})format!("{} <- function({SUBSET_FORMALS}) {{", def("[[")));
533lines.extend(h.every_read_check());
534lines.push(" if (typeof(x) == \"externalptr\") {".to_string());
535lines.push(dots_check(SUBSET_FORMALS, Some(&h.error_class), " "));
536let 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 );
540match parsed_impl.field_lookup {
541 FieldLookup::List => {
542lines.push(" if (is.character(i) && length(i) == 1L) {".to_string());
543if fallback {
544// `NA` reads NULL, as without the fallback.
545lines.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));
546lines.push(" if (!is.na(i)) {".to_string());
547lines.extend(h.fallback_read("x", "i", " "));
548lines.push(" }".to_string());
549lines.push(" return(NULL)".to_string());
550lines.push(" }".to_string());
551 } else {
552lines.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 }
557lines.push(
558" } else if (length(i) == 1L && (is.numeric(i) || is.logical(i))) {".to_string(),
559 );
560lines.push(" if (is.na(i)) return(NULL)".to_string());
561lines.push(field_at);
562lines.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 => {
568lines.push(" if (is.character(i) && length(i) == 1L && !is.na(i)) {".to_string());
569if fallback {
570lines.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));
571lines.extend(h.fallback_read("x", "i", " "));
572lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", unknown("i")))
})format!(" {}", unknown("i")));
573lines.push(" }".to_string());
574 } else {
575lines.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 }
581lines.push(
582" } else if (is.numeric(i) && length(i) == 1L && !is.na(i) && i == trunc(i)) {"
583.to_string(),
584 );
585lines.push(field_at);
586lines.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 }
592lines.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 ));
596lines.push(" return(NextMethod(exact = TRUE))".to_string());
597lines.push(" }".to_string());
598lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, i)", h.get))
})format!(" .val <- {}(x, i)", h.get));
599lines.extend(guard(" "));
600lines.push(" .val".to_string());
601lines.push("}".to_string());
602lines.push(String::new());
603604// `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`.
613s3_method_doc(&mut lines, parsed_impl, "names", on_page, register, &[x]);
614lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function(x) {{",
def("names")))
})format!("{} <- function(x) {{", def("names")));
615lines.extend(h.every_read_check());
616lines.push(" if (typeof(x) != \"externalptr\") return(NextMethod())".to_string());
617lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", h.fields))
})format!(" {}", h.fields));
618lines.push("}".to_string());
619lines.push(String::new());
620621s3_method_doc(
622&mut lines,
623parsed_impl,
624"as.list",
625on_page,
626register,
627&[x, dots],
628 );
629lines.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 ));
633lines.extend(h.every_read_check());
634lines.push(" if (is.environment(x)) return(as.list.environment(x, ...))".to_string());
635lines.push(" if (typeof(x) != \"externalptr\") return(NextMethod())".to_string());
636lines.push(dots_check(AS_LIST_FORMALS, Some(&h.error_class), " "));
637lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .out <- vector(\"list\", length({0}))",
h.fields))
})format!(" .out <- vector(\"list\", length({}))", h.fields));
638lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" names(.out) <- {0}", h.fields))
})format!(" names(.out) <- {}", h.fields));
639lines.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));
640lines.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));
641lines.extend(guard(" "));
642lines.push(" .out[.k] <- list(.val)".to_string());
643lines.push(" }".to_string());
644lines.push(" .out".to_string());
645lines.push("}".to_string());
646lines.push(String::new());
647648// `.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).
652dollar_names_doc(&mut lines, parsed_impl, on_page, register);
653lines.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 ));
657lines.push(h.dollar_names_guard("x"));
658match h.fallback_names_call("x") {
659// The fallback's names follow the fields on the bare pointer, where
660 // `$` reads them (#2150).
661Some(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 )),
665None => 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 }
670lines.push("}".to_string());
671lines.push(String::new());
672673if !parsed_impl.r_data_accessors.setters() {
674return lines;
675 }
676677s3_method_doc(
678&mut lines,
679parsed_impl,
680"$<-",
681on_page,
682register,
683&[x, name, value],
684 );
685lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function(x, name, value) {{",
def("$<-")))
})format!("{} <- function(x, name, value) {{", def("$<-")));
686lines.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));
687lines.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 ));
691lines.push(" return(NextMethod())".to_string());
692lines.push(" }".to_string());
693lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, name, value)",
h.set))
})format!(" .val <- {}(x, name, value)", h.set));
694lines.extend(guard(" "));
695lines.push(" x".to_string());
696lines.push("}".to_string());
697lines.push(String::new());
698699s3_method_doc(
700&mut lines,
701parsed_impl,
702"[[<-",
703on_page,
704register,
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 `[[<-`.
710lines.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 ));
714lines.push(" if (typeof(x) == \"externalptr\") {".to_string());
715lines.push(dots_check(
716SUBSET_ASSIGN_FORMALS,
717Some(&h.error_class),
718" ",
719 ));
720lines.push(" }".to_string());
721lines.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)));
722lines.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 ));
726lines.push(" return(NextMethod())".to_string());
727lines.push(" }".to_string());
728lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, i, value)",
h.set))
})format!(" .val <- {}(x, i, value)", h.set));
729lines.extend(guard(" "));
730lines.push(" x".to_string());
731lines.push("}".to_string());
732lines.push(String::new());
733lines734}
735736/// `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> {
748let class_name = parsed_impl.class_name();
749let 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));
750let h = Helpers::new(parsed_impl);
751let 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![
752format!(
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 ];
759let doc = |lines: &mut Vec<String>, generic: &str, params: &[(&str, &str)]| {
760if on_page {
761lines.extend(page_lines(parsed_impl, params));
762 } else {
763lines.push("#' @noRd".to_string());
764 }
765if export {
766lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @exportMethod {0}", generic))
})format!("#' @exportMethod {generic}"));
767 }
768 };
769let x = ("x", "An object.");
770let name = (
771"name",
772if h.fallback.is_some() {
773"A field name, or a name the class's fallback reads."
774} else {
775"A field name."
776},
777 );
778let value = ("value", "The new value of the field.");
779780doc(&mut lines, "$", &[x, name]);
781lines.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));
784lines.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));
785lines.extend(h.live_check("x@ptr", " "));
786lines.extend(h.fallback_read("x@ptr", "name", " "));
787lines.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 ));
791lines.push(" }".to_string());
792lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x@ptr, name)",
h.get))
})format!(" .val <- {}(x@ptr, name)", h.get));
793lines.extend(guard(" "));
794lines.push(" .val".to_string());
795lines.push("})".to_string());
796lines.push(String::new());
797798dollar_names_doc(&mut lines, parsed_impl, on_page, !parsed_impl.noexport);
799lines.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 = \"\") {{",
801crate::naming::r_def_name(&format!(".DollarNames.{class_name}"))
802 ));
803lines.push(h.dollar_names_guard("x@ptr"));
804match h.fallback_names_call("x@ptr") {
805Some(call) => lines.extend(Helpers::dollar_names_with_fallback(&call, &h.fields)),
806None => 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 }
808lines.push("}".to_string());
809lines.push(String::new());
810811if parsed_impl.r_data_accessors.setters() {
812doc(&mut lines, "$<-", &[x, name, value]);
813lines.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));
816lines.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 ));
820lines.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));
821lines.extend(guard(" "));
822lines.push(" x".to_string());
823lines.push("})".to_string());
824lines.push(String::new());
825 }
826lines827}
828829/// 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> {
834let h = Helpers::new(parsed_impl);
835let 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 )];
839lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(self, name)",
h.get))
})format!(" .val <- {}(self, name)", h.get));
840lines.extend(guard(" "));
841lines.push(" return(.val)".to_string());
842lines.push(" }".to_string());
843lines844}
845846/// 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> {
854let h = Helpers::new(parsed_impl);
855let mut lines = h.live_check("self", " ");
856if h.fallback.is_some() {
857lines.push(" if (typeof(self) == \"externalptr\") {".to_string());
858lines.extend(h.fallback_read("self", "name", " "));
859lines.push(" }".to_string());
860 }
861lines862}
863864/// The `@param name` text of an env class's `$.Class`.
865pub(super) fn env_name_param(parsed_impl: &ParsedImpl) -> &'static str {
866if 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}
872873/// The load check of an env class with `env(r_data_accessors)`.
874pub(super) fn env_load_check(parsed_impl: &ParsedImpl) -> String {
875load_check(parsed_impl, "env")
876}
877878/// `.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> {
883let class_name = parsed_impl.class_name();
884let h = Helpers::new(parsed_impl);
885let mut lines = Vec::new();
886dollar_names_doc(&mut lines, parsed_impl, on_page, true);
887lines.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 = \"\") {{",
889crate::naming::r_def_name(&format!(".DollarNames.{class_name}"))
890 ));
891lines.push(h.dollar_names_guard("x"));
892match h.fallback_names_call("x") {
893// The fallback's names follow the methods, which `$` tries first
894 // (#2150).
895Some(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 )),
899None => 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 }
904lines.push("}".to_string());
905lines906}
907908/// `$<-.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> {
915let class_name = parsed_impl.class_name();
916let h = Helpers::new(parsed_impl);
917let mut lines = Vec::new();
918let 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));
919let x = ("x", "An object.");
920let value = ("value", "The new value of the field.");
921s3_method_doc(&mut lines, parsed_impl, "$<-", on_page, true, &[x, value]);
922lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`$<-.{0}` <- function(x, name, value) {{",
class_name))
})format!("`$<-.{class_name}` <- function(x, name, value) {{"));
923lines.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)));
924lines.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 ));
928lines.push(" return(NextMethod())".to_string());
929lines.push(" }".to_string());
930lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}(x, name, value)",
h.set))
})format!(" .val <- {}(x, name, value)", h.set));
931lines.extend(guard(" "));
932lines.push(" x".to_string());
933lines.push("}".to_string());
934s3_method_doc(&mut lines, parsed_impl, "[[<-", on_page, true, &[]);
935lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`[[<-.{0}` <- `$<-.{0}`",
class_name))
})format!("`[[<-.{class_name}` <- `$<-.{class_name}`"));
936lines937}
938939/// 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<()> {
947let setters = parsed_impl.r_data_accessors.setters();
948let 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 };
956let class_name = parsed_impl.class_name();
957for 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>`.
960let 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 {
967Some(generic) => generic.clone(),
968None => continue,
969 },
970 };
971// A method on another class (`s3(generic = "$", class = "other")`)
972 // defines another class's method.
973if method
974 .method_attrs
975 .class
976 .as_deref()
977 .is_some_and(|class| class != class_name)
978 {
979continue;
980 }
981if !generated.contains(&generic.as_str()) {
982continue;
983 }
984let system = if parsed_impl.class_system == ClassSystem::S3 {
985"s3"
986} else {
987"s4"
988};
989let 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 };
997return 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 }
1007Ok(())
1008}
10091010/// 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 {
1037use quote::{format_ident, quote, quote_spanned};
10381039let Some(fallback) = &parsed_impl.field_fallback else {
1040return proc_macro2::TokenStream::new();
1041 };
1042let ty = &parsed_impl.type_ident;
1043let type_name = crate::naming::ident_name(ty);
1044let cfg_attrs = &parsed_impl.cfg_attrs;
1045let path = |lit: &syn::LitStr| {
1046let mut path: syn::Path = lit1047 .parse()
1048 .expect("the impl attribute parser checked the path");
1049crate::util::resolve_self(&mut path, ty);
1050path1051 };
10521053let get = path(&fallback.get);
1054let 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.
1058let 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=>
1059match #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 };
1064let 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));
1065let 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}");
1066let registration = crate::call_method_def::call_method_def(&def_ident, &c_ident, 3);
1067let 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 );
1071let 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(®istration, &mut _s);
_s
}quote! {
1072 #(#cfg_attrs)*
1073#[doc = #doc]
1074 #[doc(hidden)]
1075 #[unsafe(no_mangle)]
1076 #[allow(non_snake_case)]
1077pub 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 {
1082let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
1083let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
1084 || {
1085// The readers pass one name, a string.
1086let __mx_name: ::std::string::String =
1087match ::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 };
1093let __mx_data =
1094unsafe { ::miniextendr_api::externalptr::sidecar_r_struct::<#ty>(x) };
1095let __mx_value: &#ty = &__mx_data;
1096 #value
1097 },
1098 ::core::option::Option::None,
1099 );
1100unsafe {
1101 ::miniextendr_api::deferred_condition::finish(
1102 __miniextendr_deferred_mark,
1103 __miniextendr_value,
1104 ::core::option::Option::None,
1105 )
1106 }
1107 }
11081109 #(#cfg_attrs)*
1110#[doc(hidden)]
1111#registration
1112 };
11131114if let Some(names) = &fallback.names {
1115let names_path = path(names);
1116let span = names.span();
1117let 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=>
1118let __mx_names: ::std::vec::Vec<::std::string::String> = #names_path(__mx_value);
1119 };
1120let 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"{}",
1122crate::naming::sidecar_fallback_names_c_name(&type_name)
1123 );
1124let 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}");
1125let registration = crate::call_method_def::call_method_def(&def_ident, &c_ident, 1);
1126let 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 );
1131entries.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(®istration, &mut _s);
_s
}quote! {
1132 #(#cfg_attrs)*
1133#[doc = #doc]
1134 #[doc(hidden)]
1135 #[unsafe(no_mangle)]
1136 #[allow(non_snake_case)]
1137pub unsafe extern "C-unwind" fn #c_ident(
1138 x: ::miniextendr_api::SEXP,
1139 ) -> ::miniextendr_api::SEXP {
1140let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
1141let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
1142 || {
1143use ::miniextendr_api::into_r::IntoR;
1144if !unsafe { ::miniextendr_api::externalptr::sidecar_r_live::<#ty>(x, false) } {
1145return ::std::vec::Vec::<::std::string::String>::new().into_sexp();
1146 }
1147let __mx_data =
1148unsafe { ::miniextendr_api::externalptr::sidecar_r_struct::<#ty>(x) };
1149let __mx_value: &#ty = &__mx_data;
1150 #value
1151 __mx_names.into_sexp()
1152 },
1153 ::core::option::Option::None,
1154 );
1155unsafe {
1156 ::miniextendr_api::deferred_condition::finish(
1157 __miniextendr_deferred_mark,
1158 __miniextendr_value,
1159 ::core::option::Option::None,
1160 )
1161 }
1162 }
11631164 #(#cfg_attrs)*
1165#[doc(hidden)]
1166#registration
1167 });
1168 }
1169entries1170}