1use proc_macro2::{Span, TokenStream};
227use syn::{DeriveInput, Field, Ident, Visibility};
228
229use crate::miniextendr_impl::ClassSystem;
230
231#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RestoredOptions {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"RestoredOptions", "class", &self.class, "message", &self.message,
"every_read", &&self.every_read)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for RestoredOptions {
#[inline]
fn default() -> Self {
RestoredOptions {
class: ::core::default::Default::default(),
message: ::core::default::Default::default(),
every_read: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::clone::Clone for RestoredOptions {
#[inline]
fn clone(&self) -> Self {
RestoredOptions {
class: ::core::clone::Clone::clone(&self.class),
message: ::core::clone::Clone::clone(&self.message),
every_read: ::core::clone::Clone::clone(&self.every_read),
}
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for RestoredOptions { }
#[automatically_derived]
impl ::core::cmp::PartialEq for RestoredOptions {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.every_read == other.every_read && self.class == other.class &&
self.message == other.message
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RestoredOptions {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Vec<String>>;
let _: ::core::cmp::AssertParamIsEq<Option<String>>;
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq)]
238struct RestoredOptions {
239 class: Vec<String>,
242 message: Option<String>,
244 every_read: bool,
249}
250
251struct ExternalPtrAttrs {
253 class_system: ClassSystem,
254 restored: RestoredOptions,
255 field_error: FieldErrorOptions,
258 rebuild: Option<syn::Path>,
261 any_version: bool,
264}
265
266#[derive(#[automatically_derived]
impl ::core::default::Default for FieldErrorOptions {
#[inline]
fn default() -> Self {
FieldErrorOptions {
class: ::core::default::Default::default(),
message: ::core::default::Default::default(),
no_field_hint: ::core::default::Default::default(),
}
}
}Default)]
268struct FieldErrorOptions {
269 class: Vec<String>,
272 message: Option<String>,
275 no_field_hint: Option<String>,
278}
279
280fn parse_externalptr_attrs(input: &DeriveInput) -> syn::Result<ExternalPtrAttrs> {
298 let mut class_system = ClassSystem::Env; let mut restored: Option<RestoredOptions> = None;
300 let mut field_error: Option<FieldErrorOptions> = None;
301 let mut rebuild: Option<syn::Path> = None;
302 let mut any_version: Option<proc_macro2::Span> = None;
303
304 for attr in &input.attrs {
305 if attr.path().is_ident("externalptr") {
306 attr.parse_nested_meta(|meta| {
307 let ident_str = meta
308 .path
309 .get_ident()
310 .map(|i| i.to_string())
311 .unwrap_or_default();
312
313 match ident_str.as_str() {
314 "env" => class_system = ClassSystem::Env,
315 "r6" => class_system = ClassSystem::R6,
316 "s3" => class_system = ClassSystem::S3,
317 "s4" => class_system = ClassSystem::S4,
318 "s7" => class_system = ClassSystem::S7,
319 "vctrs" => class_system = ClassSystem::Vctrs,
320 "restored" => {
321 if restored.is_some() {
322 return Err(meta.error("`restored(...)` is given twice"));
323 }
324 restored = Some(parse_restored_options(&meta)?);
325 }
326 "field_error" => {
327 if field_error.is_some() {
328 return Err(meta.error("`field_error(...)` is given twice"));
329 }
330 field_error = Some(parse_field_error_options(&meta)?);
331 }
332 "rebuild" => {
333 if rebuild.is_some() {
334 return Err(meta.error("`rebuild = ...` is given twice"));
335 }
336 rebuild = Some(meta.value()?.parse::<syn::Path>().map_err(|e| {
337 syn::Error::new(
338 e.span(),
339 "`rebuild` takes the path of a function `fn(&Saved<'_, Self>) -> Result<Self, E>`, e.g. `rebuild = Self::from_saved`",
340 )
341 })?);
342 }
343 "any_version" => {
344 if any_version.is_some() {
345 return Err(meta.error("`any_version` is given twice"));
346 }
347 any_version = Some(syn::spanned::Spanned::span(&meta.path));
348 }
349 _ => {
350 return Err(syn::Error::new_spanned(
351 &meta.path,
352 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown `externalptr` option \'{0}\'; expected a class system (env, r6, s3, s4, s7, vctrs), `restored(class = ..., message = ..., refuse = ...)`, `field_error(class = ..., message = ...)`, `rebuild = path` or `any_version`",
ident_str))
})format!(
353 "unknown `externalptr` option '{}'; expected a class system (env, r6, s3, s4, s7, vctrs), `restored(class = ..., message = ..., refuse = ...)`, `field_error(class = ..., message = ...)`, `rebuild = path` or `any_version`",
354 ident_str
355 ),
356 ));
357 }
358 }
359 Ok(())
360 })?;
361 }
362 }
363
364 if let (Some(span), None) = (any_version, &rebuild) {
365 return Err(syn::Error::new(
366 span,
367 "`any_version` lets the rebuild hook read a save by another version of the crate; \
368 it needs `rebuild = path` next to it",
369 ));
370 }
371
372 Ok(ExternalPtrAttrs {
373 class_system,
374 restored: restored.unwrap_or_default(),
375 field_error: field_error.unwrap_or_default(),
376 rebuild,
377 any_version: any_version.is_some(),
378 })
379}
380
381fn parse_class_list(inner: &syn::meta::ParseNestedMeta) -> syn::Result<Vec<String>> {
384 let value = inner.value()?;
385 let classes: Vec<syn::LitStr> = if value.peek(syn::token::Bracket) {
386 let content;
387 match ::syn::__private::parse_brackets(&value) {
::syn::__private::Ok(brackets) => {
content = brackets.content;
_ = content;
brackets.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::bracketed!(content in value);
388 content
389 .parse_terminated(<syn::LitStr as syn::parse::Parse>::parse, ::syn::token::Commasyn::Token![,])?
390 .into_iter()
391 .collect()
392 } else {
393 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[value.parse()?]))vec![value.parse()?]
394 };
395 if classes.is_empty() {
396 return Err(inner.error("`class` needs at least one condition class"));
397 }
398 for class in &classes {
399 if class.value().is_empty() {
400 return Err(syn::Error::new_spanned(
401 class,
402 "a condition class can't be empty",
403 ));
404 }
405 }
406 Ok(classes.iter().map(syn::LitStr::value).collect())
407}
408
409fn parse_restored_options(meta: &syn::meta::ParseNestedMeta) -> syn::Result<RestoredOptions> {
414 let mut options = RestoredOptions::default();
415 let mut class_given = false;
416 let mut refuse_given = false;
417 meta.parse_nested_meta(|inner| {
418 if inner.path.is_ident("class") {
419 if std::mem::replace(&mut class_given, true) {
420 return Err(inner.error("`class` is given twice"));
421 }
422 options.class = parse_class_list(&inner)?;
423 Ok(())
424 } else if inner.path.is_ident("message") {
425 if options.message.is_some() {
426 return Err(inner.error("`message` is given twice"));
427 }
428 let message: syn::LitStr = inner.value()?.parse()?;
429 if message.value().is_empty() {
430 return Err(syn::Error::new_spanned(
431 message,
432 "`message` can't be empty",
433 ));
434 }
435 options.message = Some(message.value());
436 Ok(())
437 } else if inner.path.is_ident("refuse") {
438 if std::mem::replace(&mut refuse_given, true) {
439 return Err(inner.error("`refuse` is given twice"));
440 }
441 let refuse: syn::LitStr = inner.value()?.parse()?;
442 if refuse.value() != "every_read" {
443 return Err(syn::Error::new_spanned(
444 refuse,
445 "`refuse` takes \"every_read\": the field methods then refuse a restored pointer \
446 on `names()` and on a name that is not a field too",
447 ));
448 }
449 options.every_read = true;
450 Ok(())
451 } else {
452 Err(inner.error(
453 "unknown `restored` option; expected `class = \"...\"` (or `class = [\"...\", ...]`), `message = \"...\"` and `refuse = \"every_read\"`",
454 ))
455 }
456 })?;
457 Ok(options)
458}
459
460fn parse_field_error_options(meta: &syn::meta::ParseNestedMeta) -> syn::Result<FieldErrorOptions> {
463 let mut class: Option<Vec<String>> = None;
464 let mut message: Option<String> = None;
465 let mut no_field_hint: Option<String> = None;
466 meta.parse_nested_meta(|inner| {
467 if inner.path.is_ident("class") {
468 if class.is_some() {
469 return Err(inner.error("`class` is given twice"));
470 }
471 class = Some(parse_class_list(&inner)?);
472 Ok(())
473 } else if inner.path.is_ident("message") {
474 if message.is_some() {
475 return Err(inner.error("`message` is given twice"));
476 }
477 let value: syn::LitStr = inner.value()?.parse()?;
478 if value.value().is_empty() {
479 return Err(syn::Error::new_spanned(value, "`message` is empty"));
480 }
481 message = Some(value.value());
482 Ok(())
483 } else if inner.path.is_ident("no_field_hint") {
484 if no_field_hint.is_some() {
485 return Err(inner.error("`no_field_hint` is given twice"));
486 }
487 let value: syn::LitStr = inner.value()?.parse()?;
488 if value.value().is_empty() {
489 return Err(syn::Error::new_spanned(value, "`no_field_hint` is empty"));
490 }
491 no_field_hint = Some(value.value());
492 Ok(())
493 } else {
494 Err(inner.error(
495 "unknown `field_error` option; expected `class = \"...\"` (or `class = [\"...\", ...]`), `message = \"...\"` and `no_field_hint = \"...\"`",
496 ))
497 }
498 })?;
499 Ok(FieldErrorOptions {
500 class: class.unwrap_or_default(),
501 message,
502 no_field_hint,
503 })
504}
505
506fn has_r_data_attr(field: &Field) -> bool {
508 field.attrs.iter().any(|a| a.path().is_ident("r_data"))
509}
510
511const SIDECAR_TYPE_NAME: &str = "Sidecar";
515
516fn sidecar_inner_type(ty: &syn::Type) -> Option<&syn::Type> {
518 let syn::Type::Path(type_path) = ty else {
519 return None;
520 };
521 let seg = type_path.path.segments.last()?;
522 if seg.ident != SIDECAR_TYPE_NAME {
523 return None;
524 }
525 let syn::PathArguments::AngleBracketed(args) = &seg.arguments else {
526 return None;
527 };
528 let mut types = args.args.iter().filter_map(|arg| match arg {
529 syn::GenericArgument::Type(ty) => Some(ty),
530 _ => None,
531 });
532 let inner = types.next()?;
533 types.next().is_none().then_some(inner)
534}
535
536const COMPUTED_TYPE_NAME: &str = "Computed";
539
540fn is_computed_type(ty: &syn::Type) -> bool {
544 #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Path(type_path) if
type_path.path.segments.last().is_some_and(|seg|
seg.ident == COMPUTED_TYPE_NAME) => true,
_ => false,
}matches!(ty, syn::Type::Path(type_path)
545 if type_path.path.segments.last().is_some_and(|seg| seg.ident == COMPUTED_TYPE_NAME))
546}
547
548#[derive(#[automatically_derived]
impl ::core::default::Default for RDataOptions {
#[inline]
fn default() -> Self {
RDataOptions {
prop_doc: ::core::default::Default::default(),
setter_invisible: ::core::default::Default::default(),
access_ref: ::core::default::Default::default(),
access_mut: ::core::default::Default::default(),
name: ::core::default::Default::default(),
get: ::core::default::Default::default(),
}
}
}Default)]
551struct RDataOptions {
552 prop_doc: Option<String>,
553 setter_invisible: Option<bool>,
554 access_ref: Option<Span>,
556 access_mut: Option<Span>,
558 name: Option<syn::LitStr>,
561 get: Option<syn::LitStr>,
564}
565
566#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SidecarAccess {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SidecarAccess",
"get", &self.get, "set", &&self.set)
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SidecarAccess { }
#[automatically_derived]
impl ::core::clone::Clone for SidecarAccess {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SidecarAccess { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for SidecarAccess { }
#[automatically_derived]
impl ::core::cmp::PartialEq for SidecarAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.get == other.get && self.set == other.set
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SidecarAccess {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq, #[automatically_derived]
impl ::core::default::Default for SidecarAccess {
#[inline]
fn default() -> Self {
SidecarAccess {
get: ::core::default::Default::default(),
set: ::core::default::Default::default(),
}
}
}Default)]
570struct SidecarAccess {
571 get: bool,
572 set: bool,
573}
574
575enum RDataArg {
578 Ref(Span),
579 Mut(Span),
580 KeyValue { key: Ident, value: syn::LitStr },
581}
582
583impl syn::parse::Parse for RDataArg {
584 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
585 let lookahead = input.lookahead1();
586 if lookahead.peek(::syn::token::Refsyn::Token![ref]) {
587 let token: ::syn::token::Refsyn::Token![ref] = input.parse()?;
588 Ok(Self::Ref(token.span))
589 } else if lookahead.peek(::syn::token::Mutsyn::Token![mut]) {
590 let token: ::syn::token::Mutsyn::Token![mut] = input.parse()?;
591 Ok(Self::Mut(token.span))
592 } else if lookahead.peek(Ident) {
593 let key: Ident = input.parse()?;
594 let _eq: ::syn::token::Eqsyn::Token![=] = input.parse()?;
595 let value: syn::LitStr = input.parse()?;
596 Ok(Self::KeyValue { key, value })
597 } else {
598 Err(lookahead.error())
599 }
600 }
601}
602
603fn parse_r_data_options(field: &Field) -> syn::Result<RDataOptions> {
606 let mut options = RDataOptions::default();
607 for attr in &field.attrs {
608 if !attr.path().is_ident("r_data") || #[allow(non_exhaustive_omitted_patterns)] match attr.meta {
syn::Meta::Path(_) => true,
_ => false,
}matches!(attr.meta, syn::Meta::Path(_)) {
609 continue;
610 }
611 let args = attr.parse_args_with(
612 syn::punctuated::Punctuated::<RDataArg, ::syn::token::Commasyn::Token![,]>::parse_terminated,
613 )?;
614 for arg in args {
615 match arg {
616 RDataArg::Ref(span) => {
617 if options.access_ref.replace(span).is_some() {
618 return Err(syn::Error::new(span, "duplicate `ref` option"));
619 }
620 }
621 RDataArg::Mut(span) => {
622 if options.access_mut.replace(span).is_some() {
623 return Err(syn::Error::new(span, "duplicate `mut` option"));
624 }
625 }
626 RDataArg::KeyValue { key, value } if key == "prop_doc" => {
627 options.prop_doc = Some(value.value());
628 }
629 RDataArg::KeyValue { key, value } if key == "setter" => {
630 if options.setter_invisible.is_some() {
631 return Err(syn::Error::new_spanned(key, "duplicate `setter` option"));
632 }
633 options.setter_invisible = Some(match value.value().as_str() {
634 "visible" => false,
635 "invisible" => true,
636 _ => {
637 return Err(syn::Error::new_spanned(
638 value,
639 "setter must be \"visible\" or \"invisible\"",
640 ));
641 }
642 });
643 }
644 RDataArg::KeyValue { key, value } if key == "name" => {
645 if options.name.is_some() {
646 return Err(syn::Error::new_spanned(key, "duplicate `name` option"));
647 }
648 options.name = Some(value);
649 }
650 RDataArg::KeyValue { key, value } if key == "get" => {
651 if options.get.is_some() {
652 return Err(syn::Error::new_spanned(key, "duplicate `get` option"));
653 }
654 options.get = Some(value);
655 }
656 RDataArg::KeyValue { key, .. } => {
657 return Err(syn::Error::new_spanned(
658 &key,
659 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown key `{0}`; supported: `ref`, `mut`, `name`, `get`, `prop_doc`, `setter`",
key))
})format!(
660 "unknown key `{key}`; supported: `ref`, `mut`, `name`, `get`, `prop_doc`, `setter`"
661 ),
662 ));
663 }
664 }
665 }
666 }
667 if options.setter_invisible.is_some()
668 && (is_rsidecar_type(field)
669 || is_computed_type(&field.ty)
670 || !is_pub(field)
671 || field.ident.is_none())
672 {
673 return Err(syn::Error::new_spanned(
674 field,
675 "`setter` requires a public named sidecar slot with a setter, not the RSidecar \
676 selector or a `Computed` field",
677 ));
678 }
679 if let Some(span) = options.access_ref.or(options.access_mut)
680 && sidecar_inner_type(&field.ty).is_none()
681 {
682 return Err(syn::Error::new(
683 span,
684 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`ref` and `mut` in `#[r_data(...)]` apply to `{1}<T>` fields only; a plain `#[r_data]` field stays a struct field with its R accessors{0}",
if is_computed_type(&field.ty) {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", and a `{0}` field is read through its `get` function",
COMPUTED_TYPE_NAME))
})
} else { String::new() }, SIDECAR_TYPE_NAME))
})format!(
685 "`ref` and `mut` in `#[r_data(...)]` apply to `{SIDECAR_TYPE_NAME}<T>` fields only; \
686 a plain `#[r_data]` field stays a struct field with its R accessors{}",
687 if is_computed_type(&field.ty) {
688 format!(
689 ", and a `{COMPUTED_TYPE_NAME}` field is read through its `get` function"
690 )
691 } else {
692 String::new()
693 }
694 ),
695 ));
696 }
697 if let Some(name) = &options.name {
698 if is_rsidecar_type(field) {
699 return Err(syn::Error::new_spanned(
700 name,
701 "`name` applies to a sidecar slot, not the RSidecar selector, which has no R name",
702 ));
703 }
704 let value = name.value();
705 if value.is_empty() {
706 return Err(syn::Error::new_spanned(
707 name,
708 "an R field name can't be empty",
709 ));
710 }
711 if value == ".ptr" {
712 return Err(syn::Error::new_spanned(
713 name,
714 "`.ptr` is the element that carries the pointer in a list or environment receiver, \
715 so it can't be an R field name",
716 ));
717 }
718 if !crate::naming::is_syntactic_r_name(&value) {
719 return Err(syn::Error::new_spanned(
720 name,
721 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is not a syntactic R name; an R field name has letters, digits, `.` and `_` only, starts with a letter or a `.` not followed by a digit, and is not a reserved word",
value))
})format!(
722 "`{value}` is not a syntactic R name; an R field name has letters, digits, `.` and `_` \
723 only, starts with a letter or a `.` not followed by a digit, and is not a reserved word"
724 ),
725 ));
726 }
727 }
728 match (&options.get, is_computed_type(&field.ty)) {
729 (Some(get), false) => {
730 return Err(syn::Error::new_spanned(
731 get,
732 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`get` applies to a `{0}` field only: declare the field as `pub <name>: {0}`, and `get` names the function that computes its value",
COMPUTED_TYPE_NAME))
})format!(
733 "`get` applies to a `{COMPUTED_TYPE_NAME}` field only: declare the field as \
734 `pub <name>: {COMPUTED_TYPE_NAME}`, and `get` names the function that computes its value"
735 ),
736 ));
737 }
738 (None, true) => {
739 return Err(syn::Error::new_spanned(
740 &field.ty,
741 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a `{0}` field needs `#[r_data(get = \"Self::f\")]`, the function `fn(&Self) -> impl IntoR` that computes its value",
COMPUTED_TYPE_NAME))
})format!(
742 "a `{COMPUTED_TYPE_NAME}` field needs `#[r_data(get = \"Self::f\")]`, the function \
743 `fn(&Self) -> impl IntoR` that computes its value"
744 ),
745 ));
746 }
747 _ => {}
748 }
749 Ok(options)
750}
751
752pub(crate) fn is_rsidecar_type(field: &Field) -> bool {
757 if let syn::Type::Path(type_path) = &field.ty {
758 type_path
759 .path
760 .segments
761 .last()
762 .map(|seg| seg.ident == "RSidecar")
763 .unwrap_or(false)
764 } else {
765 false
766 }
767}
768
769fn is_pub(field: &Field) -> bool {
771 #[allow(non_exhaustive_omitted_patterns)] match field.vis {
Visibility::Public(_) => true,
_ => false,
}matches!(field.vis, Visibility::Public(_))
772}
773
774#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SlotKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Sidecar(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Sidecar", &__self_0),
Self::Computed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Computed", &__self_0),
Self::ScalarInt =>
::core::fmt::Formatter::write_str(f, "ScalarInt"),
Self::ScalarReal =>
::core::fmt::Formatter::write_str(f, "ScalarReal"),
Self::ScalarLogical =>
::core::fmt::Formatter::write_str(f, "ScalarLogical"),
Self::ScalarRaw =>
::core::fmt::Formatter::write_str(f, "ScalarRaw"),
Self::Conversion =>
::core::fmt::Formatter::write_str(f, "Conversion"),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SlotKind {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Sidecar(__self_0) =>
SlotKind::Sidecar(::core::clone::Clone::clone(__self_0)),
Self::Computed(__self_0) =>
SlotKind::Computed(::core::clone::Clone::clone(__self_0)),
Self::ScalarInt => SlotKind::ScalarInt,
Self::ScalarReal => SlotKind::ScalarReal,
Self::ScalarLogical => SlotKind::ScalarLogical,
Self::ScalarRaw => SlotKind::ScalarRaw,
Self::Conversion => SlotKind::Conversion,
}
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for SlotKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for SlotKind {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::Sidecar(__self_0), Self::Sidecar(__arg1_0)) =>
__self_0 == __arg1_0,
(Self::Computed(__self_0), Self::Computed(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SlotKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<usize>;
let _: ::core::cmp::AssertParamIsEq<syn::Path>;
}
}Eq)]
784pub(crate) enum SlotKind {
785 Sidecar(usize),
790 Computed(syn::Path),
794 ScalarInt,
796 ScalarReal,
798 ScalarLogical,
800 ScalarRaw,
802 Conversion,
804}
805
806pub(crate) struct SidecarSlot {
811 pub(crate) name: Ident,
814 pub(crate) r_name: String,
821 ty: syn::Type,
823 vis: Visibility,
825 is_public: bool,
827 pub(crate) kind: SlotKind,
829 access: SidecarAccess,
832 prop_doc: Option<String>,
836 setter_invisible: Option<bool>,
838}
839
840pub(crate) struct SidecarInfo {
845 has_selector: bool,
848 pub(crate) slots: Vec<SidecarSlot>,
851 class_system: ClassSystem,
854}
855
856fn computed_getter_path(get: &syn::LitStr, struct_name: &Ident) -> syn::Result<syn::Path> {
861 let mut path: syn::Path = get.parse().map_err(|err| {
862 syn::Error::new_spanned(
863 get,
864 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`get` must be a path to the getter function, e.g. `Self::f`: {0}",
err))
})format!("`get` must be a path to the getter function, e.g. `Self::f`: {err}"),
865 )
866 })?;
867 crate::util::resolve_self(&mut path, struct_name);
868 Ok(path)
869}
870
871fn contains_unrooted_r_view(ty: &syn::Type) -> bool {
875 if crate::type_inspect::is_rooted_reference(ty) {
876 return true;
877 }
878 match ty {
879 syn::Type::Array(t) => contains_unrooted_r_view(&t.elem),
880 syn::Type::Slice(t) => contains_unrooted_r_view(&t.elem),
881 syn::Type::Tuple(t) => t.elems.iter().any(contains_unrooted_r_view),
882 syn::Type::Reference(t) => contains_unrooted_r_view(&t.elem),
883 syn::Type::Paren(t) => contains_unrooted_r_view(&t.elem),
884 syn::Type::Group(t) => contains_unrooted_r_view(&t.elem),
885 syn::Type::Path(t) if t.qself.is_none() => {
886 let Some(segment) = t.path.segments.last() else {
887 return false;
888 };
889 match segment.ident.to_string().as_str() {
890 "SEXP" | "List" | "ListMut" | "NamedList" | "DataFrame" | "StrVec" | "RCow"
891 | "RArray" | "RVector" | "RMatrix" | "RArray3D" | "Factor" | "FactorMut" => true,
892 "Option" | "Result" | "Vec" | "VecDeque" | "LinkedList" | "BinaryHeap"
893 | "HashSet" | "BTreeSet" | "HashMap" | "BTreeMap" | "Box" | "Rc" | "Arc"
894 | "Cow" | "Cell" | "RefCell" | "Mutex" | "RwLock" | "OnceCell" | "OnceLock" => {
895 let syn::PathArguments::AngleBracketed(args) = &segment.arguments else {
896 return false;
897 };
898 args.args.iter().any(|arg| {
899 #[allow(non_exhaustive_omitted_patterns)] match arg {
syn::GenericArgument::Type(ty) if contains_unrooted_r_view(ty) => true,
_ => false,
}matches!(arg, syn::GenericArgument::Type(ty) if contains_unrooted_r_view(ty))
900 })
901 }
902 _ => false,
903 }
904 }
905 _ => false,
906 }
907}
908
909fn slot_kind_for_type(
918 ty: &syn::Type,
919 sidecars: usize,
920 get: Option<&syn::LitStr>,
921 struct_name: &Ident,
922) -> syn::Result<SlotKind> {
923 if sidecar_inner_type(ty).is_some() {
924 return Ok(SlotKind::Sidecar(sidecars));
925 }
926 if is_computed_type(ty) {
927 let get = get.expect("a Computed field has a `get` option");
929 return Ok(SlotKind::Computed(computed_getter_path(get, struct_name)?));
930 }
931 if contains_unrooted_r_view(ty) {
932 let field_type = crate::type_inspect::type_display(ty);
933 return Err(syn::Error::new_spanned(
934 ty,
935 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a `{0}` sidecar field is not rooted: the GC frees its value once R drops its own references. Declare the field as `{1}<{0}>`, which keeps the value in the external pointer\'s protection list",
field_type, SIDECAR_TYPE_NAME))
})format!(
936 "a `{field_type}` sidecar field is not rooted: the GC frees its value once R drops \
937 its own references. Declare the field as `{SIDECAR_TYPE_NAME}<{field_type}>`, which \
938 keeps the value in the external pointer's protection list"
939 ),
940 ));
941 }
942 if let syn::Type::Path(type_path) = ty
943 && let Some(seg) = type_path.path.segments.last()
944 {
945 let ident = &seg.ident;
946 if ident == SIDECAR_TYPE_NAME {
947 return Err(syn::Error::new_spanned(
948 ty,
949 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` takes one type argument: `{0}<T>`",
SIDECAR_TYPE_NAME))
})format!("`{SIDECAR_TYPE_NAME}` takes one type argument: `{SIDECAR_TYPE_NAME}<T>`"),
950 ));
951 }
952 if ident == "i32" || ident == "i16" || ident == "i8" {
953 return Ok(SlotKind::ScalarInt);
954 }
955 if ident == "f64" || ident == "f32" {
956 return Ok(SlotKind::ScalarReal);
957 }
958 if ident == "bool" || ident == "Rbool" {
959 return Ok(SlotKind::ScalarLogical);
960 }
961 if ident == "u8" {
962 return Ok(SlotKind::ScalarRaw);
963 }
964 }
965 Ok(SlotKind::Conversion)
967}
968
969pub(crate) fn parse_sidecar_info(
978 input: &DeriveInput,
979 class_system: ClassSystem,
980) -> syn::Result<SidecarInfo> {
981 let fields = match &input.data {
982 syn::Data::Struct(data) => &data.fields,
983 _ => {
984 return Ok(SidecarInfo {
985 has_selector: false,
986 slots: ::alloc::vec::Vec::new()vec![],
987 class_system,
988 });
989 }
990 };
991
992 let mut selector_fields: Vec<&Field> = ::alloc::vec::Vec::new()vec![];
993 let mut slots = ::alloc::vec::Vec::new()vec![];
994 let mut sidecars = 0usize;
995
996 for field in fields.iter() {
997 if !has_r_data_attr(field) {
998 if sidecar_inner_type(&field.ty).is_some() {
999 return Err(syn::Error::new_spanned(
1000 &field.ty,
1001 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a `{0}<T>` field needs `#[r_data]`, `#[r_data(ref)]`, `#[r_data(mut)]` or `#[r_data(ref, mut)]`: the derive attaches only the fields it knows to the external pointer",
SIDECAR_TYPE_NAME))
})format!(
1002 "a `{SIDECAR_TYPE_NAME}<T>` field needs `#[r_data]`, `#[r_data(ref)]`, \
1003 `#[r_data(mut)]` or `#[r_data(ref, mut)]`: the derive attaches only the \
1004 fields it knows to the external pointer"
1005 ),
1006 ));
1007 }
1008 continue;
1009 }
1010
1011 let options = parse_r_data_options(field)?;
1012 if is_rsidecar_type(field) {
1013 selector_fields.push(field);
1015 } else if let Some(ref ident) = field.ident {
1016 let kind = slot_kind_for_type(&field.ty, sidecars, options.get.as_ref(), &input.ident)?;
1018 if #[allow(non_exhaustive_omitted_patterns)] match kind {
SlotKind::Computed(_) => true,
_ => false,
}matches!(kind, SlotKind::Computed(_)) {
1019 if !is_pub(field) {
1022 return Err(syn::Error::new_spanned(
1023 field,
1024 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a `{0}` field must be `pub`: it exists only as an R field, and only `pub` `#[r_data]` fields reach R",
COMPUTED_TYPE_NAME))
})format!(
1025 "a `{COMPUTED_TYPE_NAME}` field must be `pub`: it exists only as an R field, \
1026 and only `pub` `#[r_data]` fields reach R"
1027 ),
1028 ));
1029 }
1030 if #[allow(non_exhaustive_omitted_patterns)] match class_system {
ClassSystem::R6 | ClassSystem::S7 => true,
_ => false,
}matches!(class_system, ClassSystem::R6 | ClassSystem::S7) {
1033 return Err(syn::Error::new_spanned(
1034 field,
1035 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a `{1}` field is not supported under `#[externalptr({0})]`: its R6 active bindings / S7 properties need a setter, and a computed field has none (#1888). Use an active method / a computed property, or an S3, S4 or env class",
if class_system == ClassSystem::R6 { "r6" } else { "s7" },
COMPUTED_TYPE_NAME))
})format!(
1036 "a `{COMPUTED_TYPE_NAME}` field is not supported under `#[externalptr({})]`: \
1037 its R6 active bindings / S7 properties need a setter, and a computed field \
1038 has none (#1888). Use an active method / a computed property, or an S3, S4 \
1039 or env class",
1040 if class_system == ClassSystem::R6 {
1041 "r6"
1042 } else {
1043 "s7"
1044 }
1045 ),
1046 ));
1047 }
1048 }
1049 let access = if #[allow(non_exhaustive_omitted_patterns)] match kind {
SlotKind::Sidecar(_) => true,
_ => false,
}matches!(kind, SlotKind::Sidecar(_)) {
1050 sidecars += 1;
1051 let (get, set) = (options.access_ref.is_some(), options.access_mut.is_some());
1052 SidecarAccess {
1054 get: get || !set,
1055 set: set || !get,
1056 }
1057 } else {
1058 SidecarAccess::default()
1059 };
1060 let r_name = options
1061 .name
1062 .as_ref()
1063 .map_or_else(|| crate::naming::ident_name(ident), syn::LitStr::value);
1064 slots.push(SidecarSlot {
1065 name: ident.clone(),
1066 r_name,
1067 ty: field.ty.clone(),
1068 vis: field.vis.clone(),
1069 is_public: is_pub(field),
1070 kind,
1071 access,
1072 prop_doc: options.prop_doc,
1073 setter_invisible: options.setter_invisible,
1074 });
1075 }
1076 }
1077
1078 if selector_fields.len() > 1 {
1080 return Err(syn::Error::new_spanned(
1081 selector_fields[1],
1082 "only one RSidecar field is allowed per struct",
1083 ));
1084 }
1085
1086 for (i, slot) in slots.iter().enumerate() {
1089 if let Some(earlier) = slots[..i].iter().find(|other| other.r_name == slot.r_name) {
1090 return Err(syn::Error::new(
1091 slot.name.span(),
1092 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the R field name `{0}` is already taken by the field `{1}`; every `#[r_data]` field of a type needs its own R name (`#[r_data(name = \"...\")]` renames one)",
slot.r_name, earlier.name))
})format!(
1093 "the R field name `{}` is already taken by the field `{}`; every `#[r_data]` field \
1094 of a type needs its own R name (`#[r_data(name = \"...\")]` renames one)",
1095 slot.r_name, earlier.name
1096 ),
1097 ));
1098 }
1099 }
1100
1101 Ok(SidecarInfo {
1102 has_selector: !selector_fields.is_empty(),
1103 slots,
1104 class_system,
1105 })
1106}
1107
1108fn uses_require_live(slot: &SidecarSlot) -> bool {
1112 #[allow(non_exhaustive_omitted_patterns)] match slot.kind {
SlotKind::Sidecar(_) => true,
_ => false,
}matches!(slot.kind, SlotKind::Sidecar(_))
1113}
1114
1115fn require_live_param(slot: &SidecarSlot) -> Ident {
1118 if uses_require_live(slot) {
1119 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("require_live"))
}), ::quote::__private::Option::None)quote::format_ident!("require_live")
1120 } else {
1121 ::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("_require_live"))
}), ::quote::__private::Option::None)quote::format_ident!("_require_live")
1122 }
1123}
1124
1125fn generate_getter_body(struct_name: &syn::Ident, slot: &SidecarSlot) -> TokenStream {
1148 let field_name = &slot.name;
1149
1150 let extract_ref = {
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_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(&struct_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
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&struct_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::quote! {
1157 let __mx_data = ::miniextendr_api::externalptr::sidecar_r_struct::<#struct_name>(x);
1158 let data: &#struct_name = &__mx_data;
1159 };
1160
1161 match &slot.kind {
1162 SlotKind::Sidecar(index) => {
1163 {
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(&struct_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_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_require_live");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "require_live");
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
}quote::quote! {
1164 unsafe {
1165 ::miniextendr_api::externalptr::sidecar_r_get::<#struct_name>(
1166 x,
1167 #index,
1168 ::miniextendr_api::externalptr::sidecar_require_live(require_live),
1169 )
1170 }
1171 }
1172 }
1173 SlotKind::Computed(getter) => {
1174 {
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, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::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, "Computed");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_semi(&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::ToTokens::to_tokens(&getter, &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, "data");
_s
});
_s
});
_s
});
_s
}quote::quote! {
1179 use ::miniextendr_api::into_r::IntoR;
1180 unsafe {
1181 #extract_ref
1182 let ::miniextendr_api::externalptr::Computed = data.#field_name;
1183 IntoR::into_sexp(#getter(data))
1184 }
1185 }
1186 }
1187 SlotKind::ScalarInt => {
1188 {
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, "SEXP");
::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::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_integer");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
_s
});
_s
});
_s
}quote::quote! {
1189 use ::miniextendr_api::SEXP;
1190 unsafe {
1191 #extract_ref
1192 SEXP::scalar_integer(data.#field_name)
1193 }
1194 }
1195 }
1196 SlotKind::ScalarReal => {
1197 {
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, "SEXP");
::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::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
_s
});
_s
});
_s
}quote::quote! {
1198 use ::miniextendr_api::SEXP;
1199 unsafe {
1200 #extract_ref
1201 SEXP::scalar_real(data.#field_name)
1202 }
1203 }
1204 }
1205 SlotKind::ScalarLogical => {
1206 {
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, "SEXP");
::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::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_logical");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
_s
});
_s
});
_s
}quote::quote! {
1207 use ::miniextendr_api::SEXP;
1208 unsafe {
1209 #extract_ref
1210 SEXP::scalar_logical(data.#field_name)
1211 }
1212 }
1213 }
1214 SlotKind::ScalarRaw => {
1215 {
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, "SEXP");
::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::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
_s
});
_s
});
_s
}quote::quote! {
1216 use ::miniextendr_api::SEXP;
1217 unsafe {
1218 #extract_ref
1219 SEXP::scalar_raw(data.#field_name)
1220 }
1221 }
1222 }
1223 SlotKind::Conversion => {
1224 let ty = &slot.ty;
1229 let span = syn::spanned::Spanned::span(ty);
1230 let clone = {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span =
::quote::__private::get_span(span).__into_span();
::quote::__private::push_lt_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident_spanned(&mut _s, _span, "as");
::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_gt_spanned(&mut _s, _span);
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "clone");
_s
}quote::quote_spanned! {span=> <#ty as ::core::clone::Clone>::clone };
1231 {
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, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&extract_ref, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "val");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&clone, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "IntoR");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "into_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "val");
_s
});
_s
});
_s
}quote::quote! {
1232 use ::miniextendr_api::into_r::IntoR;
1233 unsafe {
1234 #extract_ref
1235 let val: #ty = #clone(&data.#field_name);
1236 <#ty as IntoR>::into_sexp(val)
1237 }
1238 }
1239 }
1240 }
1241}
1242
1243fn generate_setter_body(struct_name: &syn::Ident, slot: &SidecarSlot) -> TokenStream {
1269 let field_name = &slot.name;
1270
1271 let extract_mut = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_ident(&mut _s, "__mx_data");
::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, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "sidecar_r_struct_mut");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&struct_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
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&struct_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_ident(&mut _s, "__mx_data");
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
1276 let mut __mx_data =
1277 ::miniextendr_api::externalptr::sidecar_r_struct_mut::<#struct_name>(x);
1278 let data: &mut #struct_name = &mut __mx_data;
1279 };
1280
1281 let crate_class = crate::crate_config::conversion_error_class();
1295 let value_ty = sidecar_inner_type(&slot.ty).unwrap_or(&slot.ty);
1297 let rust_type = crate::type_inspect::type_display(value_ty);
1298 let field_r_name = slot.r_name.clone();
1300 let scalar_err = |expected: &str| -> proc_macro2::TokenStream {
1301 let prefix = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}\' must be {1}", field_r_name,
expected))
})format!("'{field_r_name}' must be {expected}");
1302 {
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, "error_value");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "conversion_condition_value");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&prefix, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"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, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&rust_type, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut crate_class, i) = crate_class.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let crate_class =
match crate_class.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&crate_class, &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,
"__mx_conversion_err_parts");
::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::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_r");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"scalar_rejection_reason");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "true");
_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);
::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
}quote::quote! {
1303 ::miniextendr_api::error_value::conversion_condition_value(
1304 #prefix,
1305 "value",
1306 ::core::option::Option::Some(#rust_type),
1307 &[#(#crate_class),*],
1308 ::miniextendr_api::__mx_conversion_err_parts!(
1309 ::miniextendr_api::from_r::scalar_rejection_reason(value),
1310 true
1311 ),
1312 ::core::option::Option::None,
1313 ::core::option::Option::None,
1314 )
1315 }
1316 };
1317
1318 let conversion_err = |ty: &syn::Type| -> proc_macro2::TokenStream {
1322 let prefix = crate::r_preconditions::conversion_expectation(ty, false)
1323 .map(|expected| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}\' must be {1}", field_r_name,
expected))
})format!("'{field_r_name}' must be {expected}"));
1324 let declared = crate::rust_conversion_builder::declared_expectation(ty);
1325 crate::rust_conversion_builder::conversion_value_tokens(
1326 &crate::rust_conversion_builder::ConversionSubject {
1327 expected: prefix.as_deref().map_or(
1328 crate::rust_conversion_builder::Expected::FromError(Some(&declared)),
1329 crate::rust_conversion_builder::Expected::Literal,
1330 ),
1331 quoted: &field_r_name,
1332 param: "value",
1333 nullable: crate::type_inspect::is_option_type(ty),
1334 rust_type: &rust_type,
1335 },
1336 &crate_class,
1337 &{
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, "None");
_s
}quote::quote!(::core::option::Option::None),
1338 syn::spanned::Spanned::span(ty),
1339 )
1340 };
1341
1342 match &slot.kind {
1343 SlotKind::Computed(_) => TokenStream::new(),
1344 SlotKind::Sidecar(index) => {
1345 let err_value = conversion_err(value_ty);
1346 {
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, "TryFromSexp");
::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_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "require_live");
::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, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "sidecar_require_live");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "require_live");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "sidecar_r_check");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&struct_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::__private::push_ident(&mut _s, "require_live");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_ident(&mut _s, "let");
::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, "e");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&value_ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "TryFromSexp");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "try_from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "value");
_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::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_semi(&mut _s);
_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, "sidecar_r_set");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&struct_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, "value");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "require_live");
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1349 use ::miniextendr_api::TryFromSexp;
1350 unsafe {
1351 let require_live =
1352 ::miniextendr_api::externalptr::sidecar_require_live(require_live);
1353 ::miniextendr_api::externalptr::sidecar_r_check::<#struct_name>(x, require_live);
1354 if let ::core::result::Result::Err(e) = <#value_ty as TryFromSexp>::try_from_sexp(value) {
1355 return #err_value;
1356 }
1357 ::miniextendr_api::externalptr::sidecar_r_set::<#struct_name>(
1358 x, #index, value, require_live,
1359 );
1360 x
1361 }
1362 }
1363 }
1364 SlotKind::ScalarInt => {
1365 let err_value = scalar_err("a number");
1366 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "use");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SexpExt");
::quote::__private::push_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::ToTokens::to_tokens(&extract_mut, &mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_integer");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "v");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "v");
::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_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1367 use ::miniextendr_api::SexpExt;
1368 unsafe {
1369 #extract_mut
1370 data.#field_name = match value.as_integer() {
1371 ::core::option::Option::Some(v) => v,
1372 ::core::option::Option::None => return #err_value,
1373 };
1374 x
1375 }
1376 }
1377 }
1378 SlotKind::ScalarReal => {
1379 let err_value = scalar_err("a number");
1380 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "use");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SexpExt");
::quote::__private::push_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::ToTokens::to_tokens(&extract_mut, &mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "v");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "v");
::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_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1381 use ::miniextendr_api::SexpExt;
1382 unsafe {
1383 #extract_mut
1384 data.#field_name = match value.as_real() {
1385 ::core::option::Option::Some(v) => v,
1386 ::core::option::Option::None => return #err_value,
1387 };
1388 x
1389 }
1390 }
1391 }
1392 SlotKind::ScalarLogical => {
1393 let err_value = scalar_err("TRUE or FALSE");
1394 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "use");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SexpExt");
::quote::__private::push_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::ToTokens::to_tokens(&extract_mut, &mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_logical");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "v");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "v");
::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_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1395 use ::miniextendr_api::SexpExt;
1396 unsafe {
1397 #extract_mut
1398 data.#field_name = match value.as_logical() {
1399 ::core::option::Option::Some(v) => v,
1400 ::core::option::Option::None => return #err_value,
1401 };
1402 x
1403 }
1404 }
1405 }
1406 SlotKind::ScalarRaw => {
1407 let err_value = scalar_err("a raw value");
1408 {
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_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "SexpExt");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXPTYPE");
_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::ToTokens::to_tokens(&extract_mut, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "raw_vec");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "coerce");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "SEXPTYPE");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RAWSXP");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_ident(&mut _s, "raw_vec");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "len");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_eq_eq(&mut _s);
::quote::__private::parse(&mut _s, "0");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
});
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "raw_vec");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "raw_elt");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::parse(&mut _s, "0");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1409 use ::miniextendr_api::{SexpExt, SEXPTYPE};
1410 unsafe {
1411 #extract_mut
1412 let raw_vec = value.coerce(SEXPTYPE::RAWSXP);
1413 if raw_vec.len() == 0 {
1414 return #err_value;
1415 }
1416 data.#field_name = raw_vec.raw_elt(0);
1417 x
1418 }
1419 }
1420 }
1421 SlotKind::Conversion => {
1422 let ty = &slot.ty;
1423 let err_value = conversion_err(ty);
1424 {
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, "TryFromSexp");
::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::ToTokens::to_tokens(&extract_mut, &mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "TryFromSexp");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "try_from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "value");
_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, "val");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "val");
::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, "e");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&err_value, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "x");
_s
});
_s
}quote::quote! {
1425 use ::miniextendr_api::TryFromSexp;
1426 unsafe {
1427 #extract_mut
1428 data.#field_name = match <#ty as TryFromSexp>::try_from_sexp(value) {
1429 ::core::result::Result::Ok(val) => val,
1430 ::core::result::Result::Err(e) => return #err_value,
1431 };
1432 x
1433 }
1434 }
1435 }
1436 }
1437}
1438
1439fn generate_r_wrapper_for_slot(
1466 class_system: ClassSystem,
1467 type_name: &str,
1468 field_name: &str,
1469 getter_c_name: &str,
1470 setter_c_name: Option<&str>,
1471 setter_invisible: bool,
1472 exported: bool,
1473) -> String {
1474 let suffix = match class_system {
1476 ClassSystem::Env => "",
1477 ClassSystem::R6 => " (for R6)",
1478 ClassSystem::S3 => " (for S3)",
1479 ClassSystem::S4 => " (for S4)",
1480 ClassSystem::S7 => " (for S7)",
1481 ClassSystem::Vctrs => " (for vctrs)",
1482 };
1483 let r_getter_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_get_{1}", type_name,
field_name))
})format!("{}_get_{}", type_name, field_name);
1484 let getter_body = crate::method_return_builder::standalone_body(
1485 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".Call({0}, x, FALSE)",
getter_c_name))
})format!(".Call({getter_c_name}, x, FALSE)"),
1486 ".val",
1487 " ",
1488 );
1489 let getter_tags = if exported {
1490 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}\n#\' @param x The {0} external pointer\n#\' @return The value of the `{1}` field\n#\' @export",
type_name, field_name))
})format!(
1491 "#' @rdname {type_name}\n#' @param x The {type_name} external pointer\n\
1492 #' @return The value of the `{field_name}` field\n#' @export"
1493 )
1494 } else {
1495 "#' @noRd".to_string()
1496 };
1497 let mut out = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n#\' Get `{1}` field from {0}{2}\n{5}\n{3} <- function(x) {{\n {4}\n}}\n",
type_name, field_name, suffix, r_getter_name, getter_body,
getter_tags))
})format!(
1498 r#"
1499#' Get `{field}` field from {type}{suffix}
1500{getter_tags}
1501{r_getter} <- function(x) {{
1502 {getter_body}
1503}}
1504"#,
1505 type = type_name,
1506 field = field_name,
1507 suffix = suffix,
1508 r_getter = r_getter_name,
1509 getter_body = getter_body,
1510 );
1511 let Some(setter_c_name) = setter_c_name else {
1512 return out;
1513 };
1514 let r_setter_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_set_{1}", type_name,
field_name))
})format!("{}_set_{}", type_name, field_name);
1515 let setter_body = crate::method_return_builder::standalone_body(
1516 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".Call({0}, x, value, FALSE)",
setter_c_name))
})format!(".Call({setter_c_name}, x, value, FALSE)"),
1517 if setter_invisible {
1518 "invisible(x)"
1519 } else {
1520 "x"
1521 },
1522 " ",
1523 );
1524 let setter_tags = if exported {
1525 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {1}\n#\' @param x The {1} external pointer\n#\' @param value The new value to set\n#\' @return The {1} pointer ({0})\n#\' @export",
if setter_invisible { "invisibly" } else { "visibly" },
type_name))
})format!(
1526 "#' @rdname {type_name}\n#' @param x The {type_name} external pointer\n\
1527 #' @param value The new value to set\n#' @return The {type_name} pointer ({visibility})\n\
1528 #' @export",
1529 visibility = if setter_invisible {
1530 "invisibly"
1531 } else {
1532 "visibly"
1533 },
1534 )
1535 } else {
1536 "#' @noRd".to_string()
1537 };
1538 out.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n#\' Set `{1}` field on {0}{2}\n{5}\n{3} <- function(x, value) {{\n {4}\n}}\n",
type_name, field_name, suffix, r_setter_name, setter_body,
setter_tags))
})format!(
1539 r#"
1540#' Set `{field}` field on {type}{suffix}
1541{setter_tags}
1542{r_setter} <- function(x, value) {{
1543 {setter_body}
1544}}
1545"#,
1546 type = type_name,
1547 field = field_name,
1548 suffix = suffix,
1549 r_setter = r_setter_name,
1550 setter_body = setter_body,
1551 ));
1552 out
1553}
1554
1555fn generate_class_integration_r_code(
1565 class_system: ClassSystem,
1566 type_name: &str,
1567 pub_slots: &[&SidecarSlot],
1568) -> String {
1569 if pub_slots.is_empty() {
1570 return String::new();
1571 }
1572
1573 let guard =
1577 |indent: &str| crate::method_return_builder::condition_check_lines(indent).join("\n");
1578
1579 match class_system {
1580 ClassSystem::R6 => {
1581 let mut code = String::new();
1585 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n# Auto-generated active bindings for {0} sidecar fields.\n",
type_name))
})format!(
1586 "\n# Auto-generated active bindings for {type} sidecar fields.\n",
1587 type = type_name,
1588 ));
1589 code.push_str(
1590 "# These are applied when `r_data_accessors` is set on the impl block.\n",
1591 );
1592 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".rdata_active_bindings_{0} <- function(cls) {{\n # R CMD check: self/private are R6 runtime bindings (set by cls$set)\n self <- private <- NULL\n",
type_name))
})format!(
1593 ".rdata_active_bindings_{type} <- function(cls) {{\n\
1594 \x20 # R CMD check: self/private are R6 runtime bindings (set by cls$set)\n\
1595 \x20 self <- private <- NULL\n",
1596 type = type_name,
1597 ));
1598 for slot in pub_slots {
1599 let field = &slot.r_name;
1602 let rust_field = crate::naming::ident_name(&slot.name);
1603 let getter_c = crate::naming::sidecar_getter_c_name(type_name, &rust_field);
1606 let setter_c = crate::naming::sidecar_setter_c_name(type_name, &rust_field);
1607 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" cls$set(\"active\", \"{0}\", function(value) {{\n if (missing(value)) {{\n .val <- .Call({1}, private$.ptr, FALSE)\n{3}\n .val\n }} else {{\n .val <- .Call({2}, private$.ptr, value, FALSE)\n{4}\n {5}\n }}\n }}, overwrite = TRUE)\n",
field, getter_c, setter_c, guard(" "), guard(" "),
if slot.setter_invisible.unwrap_or(true) {
"invisible(self)"
} else { "self" }))
})format!(
1609 " cls$set(\"active\", \"{field}\", function(value) {{\n\
1610 \x20 if (missing(value)) {{\n\
1611 \x20 .val <- .Call({getter_c}, private$.ptr, FALSE)\n\
1612 {getter_guard}\n\
1613 \x20 .val\n\
1614 \x20 }} else {{\n\
1615 \x20 .val <- .Call({setter_c}, private$.ptr, value, FALSE)\n\
1616 {setter_guard}\n\
1617 \x20 {setter_return}\n\
1618 \x20 }}\n\
1619 \x20 }}, overwrite = TRUE)\n",
1620 field = field,
1621 getter_c = getter_c,
1622 setter_c = setter_c,
1623 getter_guard = guard(" "),
1624 setter_guard = guard(" "),
1625 setter_return = if slot.setter_invisible.unwrap_or(true) {
1626 "invisible(self)"
1627 } else {
1628 "self"
1629 },
1630 ));
1631 }
1632 code.push_str("}\n");
1633 code
1634 }
1635 ClassSystem::S7 => {
1636 let mut code = String::new();
1639 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n# Auto-generated S7 property definitions for {0} sidecar fields.\n",
type_name))
})format!(
1640 "\n# Auto-generated S7 property definitions for {type} sidecar fields.\n",
1641 type = type_name,
1642 ));
1643 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".rdata_properties_{0} <- list(\n",
type_name))
})format!(
1644 ".rdata_properties_{type} <- list(\n",
1645 type = type_name,
1646 ));
1647 for (i, slot) in pub_slots.iter().enumerate() {
1648 let field = &slot.r_name;
1651 let rust_field = crate::naming::ident_name(&slot.name);
1652 let getter_c = crate::naming::sidecar_getter_c_name(type_name, &rust_field);
1655 let setter_c = crate::naming::sidecar_setter_c_name(type_name, &rust_field);
1656 let comma = if i < pub_slots.len() - 1 { "," } else { "" };
1657 code.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0} = S7::new_property(\n getter = function(self) {{\n .val <- .Call({1}, self@.ptr, FALSE)\n{3}\n .val\n }},\n setter = function(self, value) {{\n .val <- .Call({2}, self@.ptr, value, FALSE)\n{4}\n {5}\n }}\n ){6}\n",
field, getter_c, setter_c, guard(" "),
guard(" "),
if slot.setter_invisible.unwrap_or(false) {
"invisible(self)"
} else { "self" }, comma))
})format!(
1659 " {field} = S7::new_property(\n\
1660 \x20 getter = function(self) {{\n\
1661 \x20 .val <- .Call({getter_c}, self@.ptr, FALSE)\n\
1662 {getter_guard}\n\
1663 \x20 .val\n\
1664 \x20 }},\n\
1665 \x20 setter = function(self, value) {{\n\
1666 \x20 .val <- .Call({setter_c}, self@.ptr, value, FALSE)\n\
1667 {setter_guard}\n\
1668 \x20 {setter_return}\n\
1669 \x20 }}\n\
1670 \x20 ){comma}\n",
1671 field = field,
1672 getter_c = getter_c,
1673 setter_c = setter_c,
1674 getter_guard = guard(" "),
1675 setter_guard = guard(" "),
1676 setter_return = if slot.setter_invisible.unwrap_or(false) {
1677 "invisible(self)"
1678 } else {
1679 "self"
1680 },
1681 comma = comma,
1682 ));
1683 }
1684 code.push_str(")\n");
1685 code
1686 }
1687 _ => String::new(),
1689 }
1690}
1691
1692fn generate_field_syntax_helpers(
1723 type_name: &str,
1724 pub_slots: &[&SidecarSlot],
1725 field_error: &[String],
1726 no_field_hint: Option<&str>,
1727 every_read: bool,
1728) -> String {
1729 use crate::naming::{RDataHelper, rdata_helper_name};
1730
1731 let error_class_var = rdata_helper_name(RDataHelper::ErrorClass, type_name);
1732 let names = pub_slots
1733 .iter()
1734 .map(|slot| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\"{0}\"", slot.r_name))
})format!("\"{}\"", slot.r_name))
1735 .collect::<Vec<_>>()
1736 .join(", ");
1737 let listed = pub_slots
1738 .iter()
1739 .map(|slot| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", slot.r_name))
})format!("`{}`", slot.r_name))
1740 .collect::<Vec<_>>()
1741 .join(", ");
1742 let arms = |setter: bool| {
1746 pub_slots
1747 .iter()
1748 .map(|slot| {
1749 let rust_field = crate::naming::ident_name(&slot.name);
1750 let call = match (&slot.kind, setter) {
1751 (SlotKind::Computed(_), true) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("stop(errorCondition(sprintf(\"`{0}` of `%s` is computed from the Rust value and can\'t be assigned\", if (is.null(oldClass(x))) \"{1}\" else oldClass(x)[[1L]]), class = c({2}, \"miniextendr_read_only_field\"), call = .miniextendr_frame_call(parent.frame())))",
slot.r_name, type_name, error_class_var))
})format!(
1754 "stop(errorCondition(sprintf(\"`{field}` of `%s` is computed from the Rust \
1755 value and can't be assigned\", if (is.null(oldClass(x))) \"{type_name}\" else oldClass(x)[[1L]]), \
1756 class = c({error_class_var}, \"miniextendr_read_only_field\"), \
1757 call = .miniextendr_frame_call(parent.frame())))",
1758 field = slot.r_name,
1759 ),
1760 (_, true) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".Call({0}, x, value, TRUE)",
crate::naming::sidecar_setter_c_name(type_name, &rust_field)))
})format!(
1761 ".Call({}, x, value, TRUE)",
1762 crate::naming::sidecar_setter_c_name(type_name, &rust_field)
1763 ),
1764 (_, false) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".Call({0}, x, TRUE)",
crate::naming::sidecar_getter_c_name(type_name, &rust_field)))
})format!(
1765 ".Call({}, x, TRUE)",
1766 crate::naming::sidecar_getter_c_name(type_name, &rust_field)
1767 ),
1768 };
1769 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0} = {1}",
crate::naming::r_def_name(&slot.r_name), call))
})format!(" {} = {call}", crate::naming::r_def_name(&slot.r_name))
1770 })
1771 .collect::<Vec<_>>()
1772 .join(",\n")
1773 };
1774 let error_class = if field_error.is_empty() {
1775 "NULL".to_string()
1776 } else {
1777 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("c({0})",
field_error.iter().map(|class|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\"{0}\"",
crate::naming::r_string_escape(class)))
})).collect::<Vec<_>>().join(", ")))
})format!(
1778 "c({})",
1779 field_error
1780 .iter()
1781 .map(|class| format!("\"{}\"", crate::naming::r_string_escape(class)))
1782 .collect::<Vec<_>>()
1783 .join(", ")
1784 )
1785 };
1786 let live = if every_read {
1790 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("function(x, raise) .Call({0}, x, raise)",
crate::naming::sidecar_live_c_name(type_name)))
})format!(
1791 "function(x, raise) .Call({}, x, raise)",
1792 crate::naming::sidecar_live_c_name(type_name)
1793 )
1794 } else {
1795 "function(x, raise) TRUE".to_string()
1796 };
1797 let every_read = if every_read { "TRUE" } else { "FALSE" };
1798 let no_field_message =
1799 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("sprintf(\"`%s` is not a field of `%s`; its fields are {0}\", name, cls)",
listed))
})format!("sprintf(\"`%s` is not a field of `%s`; its fields are {listed}\", name, cls)");
1800 let no_field_message = match no_field_hint {
1801 None => no_field_message,
1802 Some(hint) => {
1803 let hint = hint
1804 .split("%s")
1805 .map(|part| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\"{0}\"",
crate::naming::r_string_escape(part)))
})format!("\"{}\"", crate::naming::r_string_escape(part)))
1806 .collect::<Vec<_>>()
1807 .join(", name, ");
1808 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("paste0({0}, \". \", {1})",
no_field_message, hint))
})format!("paste0({no_field_message}, \". \", {hint})")
1809 }
1810 };
1811 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n# Field syntax helpers for {8} sidecar fields, shared by the `$` / `[[`\n# methods `r_data_accessors` generates on S3, S4 and env classes. The `TRUE`\n# is the accessors\' `require_live` flag: the methods refuse a restored pointer.\n{0} <- c({9})\n{1} <- function(x, name) switch(name,\n{6})\n{2} <- function(x, name, value) switch(name,\n{7})\n{10} <- {11}\n{3} <- function(name, env, cls) stop(errorCondition(\n {12},\n class = c({10}, \"miniextendr_no_field\"), call = .miniextendr_frame_call(env)))\n{4} <- {13}\n{5} <- {14}\n",
rdata_helper_name(RDataHelper::Fields, type_name),
rdata_helper_name(RDataHelper::Get, type_name),
rdata_helper_name(RDataHelper::Set, type_name),
rdata_helper_name(RDataHelper::NoField, type_name),
rdata_helper_name(RDataHelper::EveryRead, type_name),
rdata_helper_name(RDataHelper::Live, type_name), arms(false),
arms(true), type_name, names, error_class_var, error_class,
no_field_message, every_read, live))
})format!(
1812 "\n# Field syntax helpers for {type_name} sidecar fields, shared by the `$` / `[[`\n\
1813 # methods `r_data_accessors` generates on S3, S4 and env classes. The `TRUE`\n\
1814 # is the accessors' `require_live` flag: the methods refuse a restored pointer.\n\
1815 {fields_var} <- c({names})\n\
1816 {get_fn} <- function(x, name) switch(name,\n{get_arms})\n\
1817 {set_fn} <- function(x, name, value) switch(name,\n{set_arms})\n\
1818 {error_class_var} <- {error_class}\n\
1819 {no_field_fn} <- function(name, env, cls) stop(errorCondition(\n\
1820 \x20 {no_field_message},\n\
1821 \x20 class = c({error_class_var}, \"miniextendr_no_field\"), call = .miniextendr_frame_call(env)))\n\
1822 {every_read_var} <- {every_read}\n\
1823 {live_fn} <- {live}\n",
1824 fields_var = rdata_helper_name(RDataHelper::Fields, type_name),
1825 get_fn = rdata_helper_name(RDataHelper::Get, type_name),
1826 set_fn = rdata_helper_name(RDataHelper::Set, type_name),
1827 no_field_fn = rdata_helper_name(RDataHelper::NoField, type_name),
1828 every_read_var = rdata_helper_name(RDataHelper::EveryRead, type_name),
1829 live_fn = rdata_helper_name(RDataHelper::Live, type_name),
1830 get_arms = arms(false),
1831 set_arms = arms(true),
1832 )
1833}
1834
1835fn generate_sidecar_accessors(
1860 input: &DeriveInput,
1861 info: &SidecarInfo,
1862 restored: &RestoredOptions,
1863 field_error: &FieldErrorOptions,
1864) -> syn::Result<TokenStream> {
1865 if !input.generics.params.is_empty() {
1867 return Err(syn::Error::new_spanned(
1868 &input.generics,
1869 "ExternalPtr does not support generic structs; \
1870 .Call entrypoints cannot be generic",
1871 ));
1872 }
1873
1874 let pub_slots: Vec<_> = info.slots.iter().filter(|s| s.is_public).collect();
1876 if !info.has_selector || pub_slots.is_empty() {
1877 return Ok(::quote::__private::TokenStream::new()quote::quote! {});
1878 }
1879
1880 let name = &input.ident;
1881 let name_str = name.to_string();
1882 let name_symbol = crate::naming::ident_name(name);
1883
1884 let mut c_functions = ::alloc::vec::Vec::new()vec![];
1886 let mut exported = String::new();
1889 let mut internal = String::new();
1890
1891 let source_line = crate::roxygen::source_tag(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Generated by miniextendr from `#[derive(ExternalPtr)]` on `{0}`",
name_str))
})format!(
1894 "Generated by miniextendr from `#[derive(ExternalPtr)]` on `{name_str}`"
1895 ))
1896 .map(|line| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}\n", line))
})format!("{line}\n"))
1897 .unwrap_or_default();
1898 exported.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n#\' @title {0} Sidecar Accessors\n#\' @name {0}\n#\' @description Getter and setter functions for `#[r_data]` fields on `{0}`.\n{1}NULL\n\n",
name_str, source_line))
})format!(
1899 r#"
1900#' @title {type} Sidecar Accessors
1901#' @name {type}
1902#' @description Getter and setter functions for `#[r_data]` fields on `{type}`.
1903{source_line}NULL
1904
1905"#,
1906 type = name_str,
1907 ));
1908
1909 for slot in &pub_slots {
1910 let field_name = &slot.name;
1911 let field_name_str = crate::naming::ident_name(field_name);
1915 let r_name = &slot.r_name;
1916 let computed = #[allow(non_exhaustive_omitted_patterns)] match slot.kind {
SlotKind::Computed(_) => true,
_ => false,
}matches!(slot.kind, SlotKind::Computed(_));
1917
1918 let getter_c_name = crate::naming::sidecar_getter_c_name(&name_str, &field_name_str);
1921 let setter_c_name = crate::naming::sidecar_setter_c_name(&name_str, &field_name_str);
1922 let getter_fn_name = Ident::new(&getter_c_name, Span::call_site());
1923 let setter_fn_name = Ident::new(&setter_c_name, Span::call_site());
1924 let source_location_doc = crate::source_location_doc(field_name.span());
1925 let getter_doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Generated sidecar getter for `{0}` field on Rust type `{1}`.",
field_name_str, name_str))
})format!(
1926 "Generated sidecar getter for `{}` field on Rust type `{}`.",
1927 field_name_str, name_str
1928 );
1929 let setter_doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Generated sidecar setter for `{0}` field on Rust type `{1}`.",
field_name_str, name_str))
})format!(
1930 "Generated sidecar setter for `{}` field on Rust type `{}`.",
1931 field_name_str, name_str
1932 );
1933 let getter_doc_lit = syn::LitStr::new(&getter_doc, field_name.span());
1934 let setter_doc_lit = syn::LitStr::new(&setter_doc, field_name.span());
1935 let require_live = require_live_param(slot);
1939
1940 let getter_body = generate_getter_body(name, slot);
1942 let setter_body = generate_setter_body(name, slot);
1943
1944 c_functions.push({
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(&getter_doc_lit, &mut _s);
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "doc");
::quote::__private::push_eq(&mut _s);
::quote::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_eq(&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, "concat");
::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,
"\"Generated from source file `\"");
::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, "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::parse(&mut _s, "\"`.\"");
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "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(&getter_fn_name, &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::ToTokens::to_tokens(&require_live, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_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::ToTokens::to_tokens(&getter_body, &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
});
_s
}quote::quote! {
1956 #[doc = #getter_doc_lit]
1957 #[doc = #source_location_doc]
1958 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
1959 #[doc(hidden)]
1960 #[unsafe(no_mangle)]
1961 #[allow(non_snake_case)]
1962 pub unsafe extern "C-unwind" fn #getter_fn_name(
1963 x: ::miniextendr_api::SEXP,
1964 #require_live: ::miniextendr_api::SEXP,
1965 ) -> ::miniextendr_api::SEXP {
1966 let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
1967 let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
1968 || { #getter_body },
1969 ::core::option::Option::None,
1970 );
1971 unsafe {
1972 ::miniextendr_api::deferred_condition::finish(
1973 __miniextendr_deferred_mark,
1974 __miniextendr_value,
1975 ::core::option::Option::None,
1976 )
1977 }
1978 }
1979 });
1980
1981 let getter_def_ident = Ident::new(
1983 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_CALL_DEF_RDATA_GET_{0}_{1}",
name_symbol, field_name_str))
})format!("__MX_CALL_DEF_RDATA_GET_{}_{}", name_symbol, field_name_str),
1984 Span::call_site(),
1985 );
1986 let getter_registration =
1987 crate::call_method_def::call_method_def(&getter_def_ident, &getter_fn_name, 2);
1988 c_functions.push({
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_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(&getter_registration, &mut _s);
_s
}quote::quote! {
1989 #[doc(hidden)]
1990 #getter_registration
1991 });
1992
1993 if !computed {
1996 c_functions.push({
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(&setter_doc_lit, &mut _s);
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "doc");
::quote::__private::push_eq(&mut _s);
::quote::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_eq(&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, "concat");
::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,
"\"Generated from source file `\"");
::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, "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::parse(&mut _s, "\"`.\"");
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "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(&setter_fn_name, &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, "value");
::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::ToTokens::to_tokens(&require_live, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_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::ToTokens::to_tokens(&setter_body, &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
});
_s
}quote::quote! {
1999 #[doc = #setter_doc_lit]
2000 #[doc = #source_location_doc]
2001 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
2002 #[doc(hidden)]
2003 #[unsafe(no_mangle)]
2004 #[allow(non_snake_case)]
2005 pub unsafe extern "C-unwind" fn #setter_fn_name(
2006 x: ::miniextendr_api::SEXP,
2007 value: ::miniextendr_api::SEXP,
2008 #require_live: ::miniextendr_api::SEXP,
2009 ) -> ::miniextendr_api::SEXP {
2010 let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
2011 let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
2012 || { #setter_body },
2013 ::core::option::Option::None,
2014 );
2015 unsafe {
2016 ::miniextendr_api::deferred_condition::finish(
2017 __miniextendr_deferred_mark,
2018 __miniextendr_value,
2019 ::core::option::Option::None,
2020 )
2021 }
2022 }
2023 });
2024
2025 let setter_def_ident = Ident::new(
2026 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_CALL_DEF_RDATA_SET_{0}_{1}",
name_symbol, field_name_str))
})format!("__MX_CALL_DEF_RDATA_SET_{}_{}", name_symbol, field_name_str),
2027 Span::call_site(),
2028 );
2029 let setter_registration =
2030 crate::call_method_def::call_method_def(&setter_def_ident, &setter_fn_name, 3);
2031 c_functions.push({
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_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(&setter_registration, &mut _s);
_s
}quote::quote! {
2032 #[doc(hidden)]
2033 #setter_registration
2034 });
2035 }
2036
2037 let field_start = field_name.span().start();
2039 let via = if computed {
2040 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", getter_c_name))
})format!("`{getter_c_name}`")
2041 } else {
2042 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` and `{1}`", getter_c_name,
setter_c_name))
})format!("`{getter_c_name}` and `{setter_c_name}`")
2043 };
2044 let comment = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("# Generated from Rust source line {0}:{1}\n# Wraps {2} `{3}` on Rust type `{4}` via {5}.\n",
field_start.line, field_start.column + 1,
if computed { "computed field" } else { "sidecar field" },
r_name, name_str, via))
})format!(
2045 "# Generated from Rust source line {}:{}\n# Wraps {} `{}` on Rust type `{}` via {}.\n",
2046 field_start.line,
2047 field_start.column + 1,
2048 if computed {
2049 "computed field"
2050 } else {
2051 "sidecar field"
2052 },
2053 r_name,
2054 name_str,
2055 via,
2056 );
2057 for (out, is_exported) in [(&mut exported, true), (&mut internal, false)] {
2058 out.push_str(&comment);
2059 out.push_str(&generate_r_wrapper_for_slot(
2060 info.class_system,
2061 &name_str,
2062 r_name,
2063 &getter_c_name,
2064 (!computed).then_some(setter_c_name.as_str()),
2065 slot.setter_invisible.unwrap_or(true),
2066 is_exported,
2067 ));
2068 }
2069 }
2070
2071 if restored.every_read {
2076 let live_c_name = crate::naming::sidecar_live_c_name(&name_str);
2077 let live_fn_name = Ident::new(&live_c_name, Span::call_site());
2078 let live_doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Generated liveness check of the field methods of Rust type `{0}` (`restored(refuse = \"every_read\")`).",
name_str))
})format!(
2079 "Generated liveness check of the field methods of Rust type `{name_str}` \
2080 (`restored(refuse = \"every_read\")`)."
2081 );
2082 let live_def_ident = Ident::new(
2083 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_CALL_DEF_RDATA_LIVE_{0}",
name_symbol))
})format!("__MX_CALL_DEF_RDATA_LIVE_{name_symbol}"),
2084 Span::call_site(),
2085 );
2086 let live_registration =
2087 crate::call_method_def::call_method_def(&live_def_ident, &live_fn_name, 2);
2088 c_functions.push({
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(&live_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(&live_fn_name, &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, "raise");
::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, "SEXP");
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "raise");
::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, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"sidecar_require_live");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "raise");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_logical");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
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_live");
::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::__private::push_ident(&mut _s, "raise");
_s
});
_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(&live_registration, &mut _s);
_s
}quote::quote! {
2089 #[doc = #live_doc]
2090 #[doc(hidden)]
2091 #[unsafe(no_mangle)]
2092 #[allow(non_snake_case)]
2093 pub unsafe extern "C-unwind" fn #live_fn_name(
2094 x: ::miniextendr_api::SEXP,
2095 raise: ::miniextendr_api::SEXP,
2096 ) -> ::miniextendr_api::SEXP {
2097 let __miniextendr_deferred_mark = ::miniextendr_api::deferred_condition::mark();
2098 let __miniextendr_value = ::miniextendr_api::unwind_protect::with_r_unwind_protect(
2099 || {
2100 use ::miniextendr_api::SEXP;
2101 let raise = ::miniextendr_api::externalptr::sidecar_require_live(raise);
2102 SEXP::scalar_logical(unsafe {
2103 ::miniextendr_api::externalptr::sidecar_r_live::<#name>(x, raise)
2104 })
2105 },
2106 ::core::option::Option::None,
2107 );
2108 unsafe {
2109 ::miniextendr_api::deferred_condition::finish(
2110 __miniextendr_deferred_mark,
2111 __miniextendr_value,
2112 ::core::option::Option::None,
2113 )
2114 }
2115 }
2116
2117 #[doc(hidden)]
2118 #live_registration
2119 });
2120 }
2121
2122 let r_wrappers = generate_class_integration_r_code(info.class_system, &name_str, &pub_slots);
2124 internal.push_str(&generate_field_syntax_helpers(
2127 &name_str,
2128 &pub_slots,
2129 &field_error.class,
2130 field_error.no_field_hint.as_deref(),
2131 restored.every_read,
2132 ));
2133
2134 let const_name_wrappers = Ident::new(
2135 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("R_WRAPPERS_RDATA_{0}",
name_symbol))
})format!("R_WRAPPERS_RDATA_{}", name_symbol),
2136 Span::call_site(),
2137 );
2138 let const_name_accessors = Ident::new(
2139 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("R_SIDECAR_ACCESSORS_{0}",
name_symbol))
})format!("R_SIDECAR_ACCESSORS_{}", name_symbol),
2140 Span::call_site(),
2141 );
2142 let source_location_doc = crate::source_location_doc(name.span());
2143 let source_line_lit = syn::LitInt::new(&name.span().start().line.to_string(), name.span());
2144
2145 let sidecar_prop_entries = if info.class_system == ClassSystem::S7 {
2148 let entries: Vec<_> = pub_slots
2149 .iter()
2150 .map(|slot| {
2151 let field_str = slot.r_name.as_str();
2154 let doc_str = slot
2155 .prop_doc
2156 .as_deref()
2157 .unwrap_or("(undocumented sidecar property)");
2158 let entry_ident = Ident::new(
2161 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_S7_SIDECAR_PROP_{0}_{1}",
name_symbol, crate::naming::ident_name(&slot.name)))
})format!(
2162 "__MX_S7_SIDECAR_PROP_{}_{}",
2163 name_symbol,
2164 crate::naming::ident_name(&slot.name)
2165 ),
2166 Span::call_site(),
2167 );
2168 {
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_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_S7_SIDECAR_PROPS");
_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, "SidecarPropEntry");
::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, "SidecarPropEntry");
::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(&name_str, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "field_name");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&field_str, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "prop_doc");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&doc_str, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2169 #[doc(hidden)]
2170 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_S7_SIDECAR_PROPS), linkme(crate = ::miniextendr_api::linkme))]
2171 #[allow(non_upper_case_globals)]
2172 static #entry_ident: ::miniextendr_api::registry::SidecarPropEntry =
2173 ::miniextendr_api::registry::SidecarPropEntry {
2174 rust_type: #name_str,
2175 field_name: #field_str,
2176 prop_doc: #doc_str,
2177 };
2178 }
2179 })
2180 .collect();
2181 {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut entries, i) = entries.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let entries =
match entries.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&entries, &mut _s);
}
}
_s
}quote::quote! { #(#entries)* }
2182 } else {
2183 ::quote::__private::TokenStream::new();quote::quote! {}
2184 };
2185
2186 let class_integration_wrappers = (!r_wrappers.is_empty()).then(|| {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "doc");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s,
"r\" Sidecar accessor R wrapper code 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_eq(&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, "concat");
::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,
"\"Generated from source file `\"");
::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, "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::parse(&mut _s, "\"`.\"");
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "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_R_WRAPPERS");
_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(&const_name_wrappers, &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, "RWrapperEntry");
::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, "RWrapperEntry");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "priority");
::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, "RWrapperPriority");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Sidecar");
::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_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "content");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&r_wrappers, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2187 #[doc = #source_location_doc]
2189 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
2190 #[doc(hidden)]
2191 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_R_WRAPPERS), linkme(crate = ::miniextendr_api::linkme))]
2192 #[allow(non_upper_case_globals)]
2193 static #const_name_wrappers: ::miniextendr_api::registry::RWrapperEntry =
2194 ::miniextendr_api::registry::RWrapperEntry {
2195 priority: ::miniextendr_api::registry::RWrapperPriority::Sidecar,
2196 source_file: ::core::file!(),
2197 source_line: #source_line_lit,
2198 content: #r_wrappers,
2199 };
2200 });
2201
2202 Ok({
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut c_functions, i) = c_functions.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let c_functions =
match c_functions.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&c_functions, &mut _s);
}
}
::quote::ToTokens::to_tokens(&class_integration_wrappers, &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 standalone sidecar accessors, exported and internal, via\"");
_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\" 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_SIDECAR_ACCESSORS");
_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(&const_name_accessors, &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, "SidecarAccessorsEntry");
::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, "SidecarAccessorsEntry");
::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(&name_str, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "exported");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&exported, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "internal");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&internal, &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_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&sidecar_prop_entries, &mut _s);
_s
}quote::quote! {
2203 #(#c_functions)*
2204
2205 #class_integration_wrappers
2206
2207 #[doc = #source_location_doc]
2210 #[doc(hidden)]
2211 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_SIDECAR_ACCESSORS), linkme(crate = ::miniextendr_api::linkme))]
2212 #[allow(non_upper_case_globals)]
2213 static #const_name_accessors: ::miniextendr_api::registry::SidecarAccessorsEntry =
2214 ::miniextendr_api::registry::SidecarAccessorsEntry {
2215 rust_type: #name_str,
2216 exported: #exported,
2217 internal: #internal,
2218 source_file: ::core::file!(),
2219 source_line: #source_line_lit,
2220 };
2221
2222 #sidecar_prop_entries
2223 })
2224}
2225
2226fn sidecar_slots(info: &SidecarInfo) -> impl Iterator<Item = (usize, &SidecarSlot)> {
2228 info.slots.iter().filter_map(|slot| match slot.kind {
2229 SlotKind::Sidecar(index) => Some((index, slot)),
2230 _ => None,
2231 })
2232}
2233
2234fn generate_typed_external(
2249 input: &DeriveInput,
2250 info: &SidecarInfo,
2251 restored: &RestoredOptions,
2252 field_error: &FieldErrorOptions,
2253 rebuild: Option<&syn::Path>,
2254 any_version: bool,
2255 display_name: Option<&str>,
2256) -> TokenStream {
2257 let name = &input.ident;
2258 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
2259
2260 let name_str = name.to_string();
2261 let name_lit = syn::LitStr::new(&name_str, name.span());
2262 let display_name = display_name.unwrap_or(&name_str);
2263 let display_lit = syn::LitStr::new(display_name, name.span());
2264 let name_cstr = syn::LitByteStr::new(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}\0", display_name))
})format!("{display_name}\0").as_bytes(), name.span());
2265 let restored_class = (!restored.class.is_empty()).then(|| {
2270 let classes = &restored.class;
2271 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "RESTORED_ERROR_CLASS");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut classes, i) = classes.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let classes =
match classes.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&classes, &mut _s);
}
}
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2272 const RESTORED_ERROR_CLASS: &'static [&'static str] = &[#(#classes),*];
2273 }
2274 });
2275 let restored_message = restored.message.as_ref().map(|message| {
2276 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "RESTORED_ERROR_MESSAGE");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&message, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2277 const RESTORED_ERROR_MESSAGE: ::core::option::Option<&'static str> =
2278 ::core::option::Option::Some(#message);
2279 }
2280 });
2281 let field_error_class = (!field_error.class.is_empty()).then(|| {
2285 let classes = &field_error.class;
2286 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "FIELD_ERROR_CLASS");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut classes, i) = classes.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let classes =
match classes.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&classes, &mut _s);
}
}
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2287 const FIELD_ERROR_CLASS: &'static [&'static str] = &[#(#classes),*];
2288 }
2289 });
2290 let field_error_message = field_error.message.as_ref().map(|message| {
2291 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "FIELD_ERROR_MESSAGE");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&message, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! {
2292 const FIELD_ERROR_MESSAGE: ::core::option::Option<&'static str> =
2293 ::core::option::Option::Some(#message);
2294 }
2295 });
2296 let rebuild = rebuild.map(|path| {
2303 let prefix = crate::miniextendr_fn::default_serde_error_prefix();
2304 let marker = crate::miniextendr_fn::init_marker_path();
2305 let call = {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span =
::quote::__private::get_span(syn::spanned::Spanned::span(path)).__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, "saved");
_s
});
_s
}quote::quote_spanned! {syn::spanned::Spanned::span(path)=> #path(saved) };
2306 let any_version = any_version.then(|| {
2307 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "REBUILDS_ANY_VERSION");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "bool");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "true");
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! { const REBUILDS_ANY_VERSION: bool = true; }
2308 });
2309 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "REBUILDS");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "bool");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "true");
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&any_version, &mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "__mx_rebuild");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "saved");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&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, "Saved");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'_");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Result");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCondition");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "match");
::quote::ToTokens::to_tokens(&call, &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, "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, "value");
_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, "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, "value");
_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, "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, "e");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "parts");
::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,
"__mx_result_err_parts");
::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::push_ident(&mut _s, "e");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&prefix, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&marker, &mut _s);
_s
});
::quote::__private::push_semi(&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_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "condition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCondition");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Error");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "parts");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "message");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "parts");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "class");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "parts");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "call");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "parts");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "call");
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
});
_s
});
_s
});
_s
}quote::quote! {
2310 const REBUILDS: bool = true;
2311 #any_version
2312
2313 fn __mx_rebuild(
2314 saved: &::miniextendr_api::externalptr::Saved<'_, Self>,
2315 ) -> ::core::result::Result<Self, ::miniextendr_api::condition::RCondition> {
2316 match #call {
2317 ::core::result::Result::Ok(value) => ::core::result::Result::Ok(value),
2318 ::core::result::Result::Err(e) => {
2319 let parts = ::miniextendr_api::__mx_result_err_parts!(e, #prefix, #marker);
2320 ::core::result::Result::Err(::miniextendr_api::condition::RCondition::Error {
2321 message: parts.message,
2322 class: parts.class,
2323 data: parts.data,
2324 call: parts.call,
2325 })
2326 }
2327 }
2328 }
2329 }
2330 });
2331 let sidecars: Vec<_> = sidecar_slots(info).collect();
2332 let r_slot_count = (!sidecars.is_empty()).then(|| {
2335 let count = sidecars.len();
2336 let names = sidecars.iter().map(|&(_, slot)| slot.r_name.as_str());
2337 let visits = sidecars.iter().map(|&(index, slot)| {
2338 let field = &slot.name;
2339 let r_name = slot.r_name.as_str();
2340 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "visit");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&index, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&r_name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote::quote! { visit(#index, #r_name, &self.#field); }
2341 });
2342 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "R_SLOT_COUNT");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "usize");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&count, &mut _s);
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "SIDECAR_NAMES");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut names, i) = names.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let names =
match names.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&names, &mut _s);
}
}
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "__mx_visit_sidecars");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "visit");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_ident(&mut _s, "dyn");
::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, "ops");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "FnMut");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "usize");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "dyn");
::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, "SidecarField");
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::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 visits, i) = visits.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let visits =
match visits.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&visits, &mut _s);
}
}
_s
});
_s
}quote::quote! {
2343 const R_SLOT_COUNT: usize = #count;
2344 const SIDECAR_NAMES: &'static [&'static str] = &[#(#names),*];
2345
2346 fn __mx_visit_sidecars(
2347 &self,
2348 visit: &mut dyn ::core::ops::FnMut(usize, &'static str, &dyn ::miniextendr_api::externalptr::SidecarField),
2349 ) {
2350 #(#visits)*
2351 }
2352 }
2353 });
2354
2355 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TypedExternal");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &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, "const");
::quote::__private::push_ident(&mut _s, "TYPE_NAME");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_ident(&mut _s, "str");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&display_lit, &mut _s);
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "TYPE_NAME_CSTR");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "u8");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&name_cstr, &mut _s);
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "TYPE_ID_CSTR");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "u8");
_s
});
::quote::__private::push_eq(&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, "concat");
::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::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "env");
::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, "\"CARGO_PKG_NAME\"");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _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, "env");
::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, "\"CARGO_PKG_VERSION\"");
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _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, "module_path");
::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::parse(&mut _s, "\"::\"");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&name_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\"\\0\"");
_s
});
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_bytes");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&r_slot_count, &mut _s);
::quote::ToTokens::to_tokens(&restored_class, &mut _s);
::quote::ToTokens::to_tokens(&restored_message, &mut _s);
::quote::ToTokens::to_tokens(&field_error_class, &mut _s);
::quote::ToTokens::to_tokens(&field_error_message, &mut _s);
::quote::ToTokens::to_tokens(&rebuild, &mut _s);
_s
});
_s
}quote::quote! {
2364 impl #impl_generics ::miniextendr_api::externalptr::TypedExternal for #name #ty_generics #where_clause {
2365 const TYPE_NAME: &'static str = #display_lit;
2366 const TYPE_NAME_CSTR: &'static [u8] = #name_cstr;
2367 const TYPE_ID_CSTR: &'static [u8] =
2368 ::core::concat!(
2369 ::core::env!("CARGO_PKG_NAME"), "@", ::core::env!("CARGO_PKG_VERSION"),
2370 "::", ::core::module_path!(), "::", #name_lit, "\0"
2371 ).as_bytes();
2372 #r_slot_count
2373 #restored_class
2374 #restored_message
2375 #field_error_class
2376 #field_error_message
2377 #rebuild
2378 }
2379 }
2380}
2381
2382pub(crate) fn generate_altrep_storage(
2386 input: &DeriveInput,
2387 class_name: &str,
2388) -> syn::Result<TokenStream> {
2389 if let syn::Data::Struct(data) = &input.data {
2390 for field in &data.fields {
2391 for attr in field.attrs.iter().filter(|a| a.path().is_ident("r_data")) {
2392 if sidecar_inner_type(&field.ty).is_none() {
2393 return Err(syn::Error::new_spanned(
2394 field,
2395 "ALTREP #[r_data] fields must be Sidecar<T>; R field accessors belong to ExternalPtr classes",
2396 ));
2397 }
2398 if #[allow(non_exhaustive_omitted_patterns)] match &attr.meta {
syn::Meta::List(_) => true,
_ => false,
}matches!(&attr.meta, syn::Meta::List(_)) {
2399 attr.parse_nested_meta(|meta| {
2400 if meta.path.is_ident("ref") || meta.path.is_ident("mut") {
2401 Ok(())
2402 } else {
2403 Err(meta.error("ALTREP sidecars support only `ref` and `mut` access; they have no R field wrappers"))
2404 }
2405 })?;
2406 }
2407 }
2408 }
2409 }
2410 let info = parse_sidecar_info(input, ClassSystem::Env)?;
2411 let storage = generate_typed_external(
2412 input,
2413 &info,
2414 &RestoredOptions::default(),
2415 &FieldErrorOptions::default(),
2416 None,
2417 false,
2418 Some(class_name),
2419 );
2420 let accessors = generate_sidecar_rust_accessors(input, &info, false);
2421 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&storage, &mut _s);
::quote::ToTokens::to_tokens(&accessors, &mut _s);
_s
}quote::quote! { #storage #accessors })
2422}
2423
2424fn generate_sidecar_rust_accessors(
2439 input: &DeriveInput,
2440 info: &SidecarInfo,
2441 rebuilds: bool,
2442) -> TokenStream {
2443 let methods: Vec<TokenStream> = sidecar_slots(info)
2444 .flat_map(|(index, slot)| {
2445 let inner = sidecar_inner_type(&slot.ty).expect("a Sidecar slot has an inner type");
2446 let field = &slot.name;
2447 let field_name = crate::naming::ident_name(field);
2448 let r_name = slot.r_name.as_str();
2451 let vis = &slot.vis;
2452 let allow = (!#[allow(non_exhaustive_omitted_patterns)] match vis {
Visibility::Public(_) => true,
_ => false,
}matches!(vis, Visibility::Public(_)))
2453 .then(|| {
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, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "dead_code");
_s
});
_s
});
_s
}quote::quote! { #[allow(dead_code)] });
2454 let mut methods = Vec::with_capacity(3);
2455 if rebuilds {
2456 let try_getter = match ::quote::__private::IdentFragmentAdapter(&field_name) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("try_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("try_{}", field_name);
2457 let doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("The value of the `{0}` sidecar field as the save `saved` kept it, in the slot of its R name `{1}`, for a rebuild hook; `None` when the version that saved the object had no slot of that name. On R\'s main thread.",
field_name, r_name))
})format!(
2458 "The value of the `{field_name}` sidecar field as the save `saved` kept \
2459 it, in the slot of its R name `{r_name}`, for a rebuild hook; `None` when \
2460 the version that saved the object had no slot of that name. On R's main \
2461 thread."
2462 );
2463 methods.push({
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(&doc, &mut _s);
_s
});
::quote::ToTokens::to_tokens(&allow, &mut _s);
::quote::ToTokens::to_tokens(&vis, &mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::ToTokens::to_tokens(&try_getter, &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, "saved");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&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, "Saved");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'_");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&inner, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__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_try_saved");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&inner, &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, "saved");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&index, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&r_name, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
}quote::quote! {
2464 #[doc = #doc]
2465 #allow
2466 #vis fn #try_getter(
2467 saved: &::miniextendr_api::externalptr::Saved<'_, Self>,
2468 ) -> ::core::option::Option<#inner> {
2469 ::miniextendr_api::externalptr::sidecar_try_saved::<Self, #inner>(
2470 saved, #index, #r_name,
2471 )
2472 }
2473 });
2474 }
2475 if slot.access.get {
2476 let doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("The value of the `{0}` sidecar field of the object `ptr` holds: the R value the external pointer keeps, converted to its Rust type (a copy for a converting type), after moving a pending value into the pointer. On R\'s main thread.",
field_name))
})format!(
2477 "The value of the `{field_name}` sidecar field of the object `ptr` holds: \
2478 the R value the external pointer keeps, converted to its Rust type (a copy \
2479 for a converting type), after moving a pending value into the pointer. On \
2480 R's main thread."
2481 );
2482 methods.push({
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(&doc, &mut _s);
_s
});
::quote::ToTokens::to_tokens(&allow, &mut _s);
::quote::ToTokens::to_tokens(&vis, &mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::ToTokens::to_tokens(&field, &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, "ptr");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "impl");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SidecarOwner");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::ToTokens::to_tokens(&inner, &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, "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_get");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&inner, &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, "ptr");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&index, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&r_name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_or(&mut _s);
::quote::__private::push_ident(&mut _s, "this");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_or(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "this");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
}quote::quote! {
2483 #[doc = #doc]
2484 #allow
2485 #vis fn #field(ptr: &impl ::miniextendr_api::externalptr::SidecarOwner<Self>) -> #inner {
2486 ::miniextendr_api::externalptr::sidecar_get::<Self, #inner>(
2487 ptr, #index, #r_name, |this: &Self| &this.#field,
2488 )
2489 }
2490 });
2491 }
2492 if slot.access.set {
2493 let setter = match ::quote::__private::IdentFragmentAdapter(&field_name) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("set_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("set_{}", field_name);
2494 let doc = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Stores `value` in the `{0}` sidecar field of the object `ptr` holds: in the external pointer\'s protection list, dropping a pending value. On R\'s main thread.",
field_name))
})format!(
2495 "Stores `value` in the `{field_name}` sidecar field of the object `ptr` \
2496 holds: in the external pointer's protection list, dropping a pending value. \
2497 On R's main thread."
2498 );
2499 methods.push({
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(&doc, &mut _s);
_s
});
::quote::ToTokens::to_tokens(&allow, &mut _s);
::quote::ToTokens::to_tokens(&vis, &mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::ToTokens::to_tokens(&setter, &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, "ptr");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_ident(&mut _s, "impl");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SidecarOwnerMut");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&inner, &mut _s);
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "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_set");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&inner, &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, "ptr");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&index, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&r_name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_or(&mut _s);
::quote::__private::push_ident(&mut _s, "this");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_or(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "this");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&field, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
}quote::quote! {
2500 #[doc = #doc]
2501 #allow
2502 #vis fn #setter(ptr: &mut impl ::miniextendr_api::externalptr::SidecarOwnerMut<Self>, value: #inner) {
2503 ::miniextendr_api::externalptr::sidecar_set::<Self, #inner>(
2504 ptr, #index, #r_name, |this: &Self| &this.#field, value,
2505 )
2506 }
2507 });
2508 }
2509 methods
2510 })
2511 .collect();
2512 if methods.is_empty() {
2513 return TokenStream::new();
2514 }
2515 let name = &input.ident;
2516 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
2517 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::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 methods, i) = methods.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let methods =
match methods.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&methods, &mut _s);
}
}
_s
});
_s
}quote::quote! {
2518 impl #impl_generics #name #ty_generics #where_clause {
2519 #(#methods)*
2520 }
2521 }
2522}
2523
2524fn generate_into_external_ptr(input: &DeriveInput) -> TokenStream {
2529 let name = &input.ident;
2530 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
2531
2532 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "IntoExternalPtr");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
::quote::__private::TokenStream::new());
_s
}quote::quote! {
2533 impl #impl_generics ::miniextendr_api::externalptr::IntoExternalPtr for #name #ty_generics #where_clause {}
2534 }
2535}
2536
2537fn generate_into_r_vec_element(input: &DeriveInput) -> TokenStream {
2551 let name = &input.ident;
2552 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
2553
2554 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "IntoRVecElement");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "inline");
_s
});
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "elements_into_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "values");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "vec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Vec");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_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_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"collect_into_r_list");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "values");
_s
});
_s
});
_s
});
_s
}quote::quote! {
2555 impl #impl_generics ::miniextendr_api::IntoRVecElement for #name #ty_generics #where_clause {
2556 #[inline]
2557 fn elements_into_sexp(values: ::std::vec::Vec<Self>) -> ::miniextendr_api::SEXP {
2558 ::miniextendr_api::externalptr::ExternalPtr::<Self>::collect_into_r_list(values)
2559 }
2560 }
2561 }
2562}
2563
2564pub fn derive_external_ptr(
2581 input: DeriveInput,
2582 emit_into_r_marker: bool,
2583) -> syn::Result<TokenStream> {
2584 let ExternalPtrAttrs {
2587 class_system,
2588 restored,
2589 field_error,
2590 rebuild,
2591 any_version,
2592 } = parse_externalptr_attrs(&input)?;
2593
2594 let sidecar_info = parse_sidecar_info(&input, class_system)?;
2596
2597 let typed_external = generate_typed_external(
2598 &input,
2599 &sidecar_info,
2600 &restored,
2601 &field_error,
2602 rebuild.as_ref(),
2603 any_version,
2604 None,
2605 );
2606 let sidecar_rust_accessors =
2607 generate_sidecar_rust_accessors(&input, &sidecar_info, rebuild.is_some());
2608 let (into_external_ptr, into_r_vec_element) = if emit_into_r_marker {
2609 (
2610 generate_into_external_ptr(&input),
2611 generate_into_r_vec_element(&input),
2612 )
2613 } else {
2614 (
2615 proc_macro2::TokenStream::new(),
2616 proc_macro2::TokenStream::new(),
2617 )
2618 };
2619 let sidecar_accessors =
2620 generate_sidecar_accessors(&input, &sidecar_info, &restored, &field_error)?;
2621 let erased_wrapper = generate_erased_wrapper(&input);
2622
2623 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&typed_external, &mut _s);
::quote::ToTokens::to_tokens(&sidecar_rust_accessors, &mut _s);
::quote::ToTokens::to_tokens(&into_external_ptr, &mut _s);
::quote::ToTokens::to_tokens(&into_r_vec_element, &mut _s);
::quote::ToTokens::to_tokens(&sidecar_accessors, &mut _s);
::quote::ToTokens::to_tokens(&erased_wrapper, &mut _s);
_s
}quote::quote! {
2624 #typed_external
2625 #sidecar_rust_accessors
2626 #into_external_ptr
2627 #into_r_vec_element
2628 #sidecar_accessors
2629 #erased_wrapper
2630 })
2631}
2632
2633fn generate_erased_wrapper(input: &DeriveInput) -> TokenStream {
2640 let type_ident = &input.ident;
2641
2642 if !input.generics.params.is_empty() {
2644 return ::quote::__private::TokenStream::new()quote::quote! {};
2645 }
2646
2647 let type_name = crate::naming::unraw(type_ident);
2649
2650 let base_vtable_name = match ::quote::__private::IdentFragmentAdapter(&type_name) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_BASE_VTABLE_{0}",
arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("__MX_BASE_VTABLE_{}", type_name);
2651 let concrete_tag_name = match ::quote::__private::IdentFragmentAdapter(&type_name) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__MX_TAG_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("__MX_TAG_{}", type_name);
2652 let wrap_fn_name = match ::quote::__private::IdentFragmentAdapter(&type_name) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__mx_wrap_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("__mx_wrap_{}", type_name);
2653 let source_loc_doc = crate::source_location_doc(type_ident.span());
2654 let tag_path = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("::{0}", type_ident))
})format!("::{}", type_ident);
2655
2656 {
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_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, "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, "const");
::quote::ToTokens::to_tokens(&concrete_tag_name, &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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_tag");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_tag_from_path");
::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, "concat");
::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::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "module_path");
::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::ToTokens::to_tokens(&tag_path, &mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "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, "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(&base_vtable_name, &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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_base_vtable");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_base_vtable");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "drop");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedObject");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "drop_raw");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "concrete_tag");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&concrete_tag_name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "query");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedObject");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "query");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "data_offset");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedObject");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "DATA_OFFSET");
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "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, "doc");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&source_loc_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, "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, "fn");
::quote::ToTokens::to_tokens(&wrap_fn_name, &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, "data");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::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, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mx_erased");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "abi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedObject");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "into_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "data");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&base_vtable_name, &mut _s);
_s
});
_s
});
_s
});
_s
}quote::quote! {
2657 #[doc(hidden)]
2658 #[allow(non_upper_case_globals)]
2659 const #concrete_tag_name: ::miniextendr_api::abi::mx_tag =
2660 ::miniextendr_api::abi::mx_tag_from_path(::core::concat!(::core::module_path!(), #tag_path));
2661
2662 #[doc(hidden)]
2663 #[allow(non_upper_case_globals)]
2664 static #base_vtable_name: ::miniextendr_api::abi::mx_base_vtable =
2665 ::miniextendr_api::abi::mx_base_vtable {
2666 drop: ::miniextendr_api::abi::ErasedObject::<#type_ident>::drop_raw,
2667 concrete_tag: #concrete_tag_name,
2668 query: ::miniextendr_api::abi::ErasedObject::<#type_ident>::query,
2669 data_offset: ::miniextendr_api::abi::ErasedObject::<#type_ident>::DATA_OFFSET,
2670 };
2671
2672 #[doc(hidden)]
2673 #[doc = #source_loc_doc]
2674 #[allow(non_snake_case)]
2675 fn #wrap_fn_name(data: #type_ident) -> *mut ::miniextendr_api::abi::mx_erased {
2676 unsafe {
2679 ::miniextendr_api::abi::ErasedObject::into_raw(data, &#base_vtable_name)
2680 }
2681 }
2682 }
2683}
2684
2685#[cfg(test)]
2686mod tests {
2687 use super::{ClassSystem, generate_class_integration_r_code, generate_r_wrapper_for_slot};
2688
2689 const ALL_CLASS_SYSTEMS: [ClassSystem; 6] = [
2690 ClassSystem::Env,
2691 ClassSystem::R6,
2692 ClassSystem::S3,
2693 ClassSystem::S4,
2694 ClassSystem::S7,
2695 ClassSystem::Vctrs,
2696 ];
2697
2698 #[test]
2703 fn sidecar_accessors_pass_no_call_slot() {
2704 let getter_c = "C__mx_rdata_get_T_f";
2705 let setter_c = "C__mx_rdata_set_T_f";
2706
2707 for cs in ALL_CLASS_SYSTEMS {
2708 let out =
2709 generate_r_wrapper_for_slot(cs, "T", "f", getter_c, Some(setter_c), true, true);
2710 assert!(
2714 out.contains(&format!(".Call({getter_c}, x, FALSE)")),
2715 "{cs:?} getter should call without .call:\n{out}"
2716 );
2717 assert!(
2718 out.contains(&format!(".Call({setter_c}, x, value, FALSE)")),
2719 "{cs:?} setter should call without .call:\n{out}"
2720 );
2721 assert!(
2723 !out.contains(".call ="),
2724 "{cs:?} sidecar wrapper must not pass a .call argument:\n{out}"
2725 );
2726 }
2727 }
2728
2729 #[test]
2734 fn sidecar_accessors_reraise_tagged_conditions() {
2735 let getter_c = "C__mx_rdata_get_T_f";
2736 let setter_c = "C__mx_rdata_set_T_f";
2737
2738 for cs in ALL_CLASS_SYSTEMS {
2739 let out =
2740 generate_r_wrapper_for_slot(cs, "T", "f", getter_c, Some(setter_c), true, true);
2741 assert_eq!(
2742 out.matches(".miniextendr_raise_condition(.val, sys.call())")
2743 .count(),
2744 2,
2745 "{cs:?} getter+setter should each carry the condition guard:\n{out}"
2746 );
2747 let out = generate_r_wrapper_for_slot(cs, "T", "f", getter_c, None, true, true);
2749 assert!(out.contains("T_get_f <- function(x)"), "{out}");
2750 assert!(!out.contains("T_set_f"), "{out}");
2751 assert_eq!(
2752 out.matches(".miniextendr_raise_condition(.val, sys.call())")
2753 .count(),
2754 1,
2755 "{cs:?} computed getter should carry the condition guard:\n{out}"
2756 );
2757 }
2758 }
2759
2760 #[test]
2765 fn sidecar_setter_raises_the_argument_error() {
2766 let body = |ty: syn::Type, kind: super::SlotKind| {
2767 let slot = super::SidecarSlot {
2768 name: syn::Ident::new("f", proc_macro2::Span::call_site()),
2769 r_name: String::from("f"),
2770 ty,
2771 vis: syn::parse_quote!(pub),
2772 is_public: true,
2773 kind,
2774 access: super::SidecarAccess::default(),
2775 prop_doc: None,
2776 setter_invisible: None,
2777 };
2778 super::generate_setter_body(
2779 &syn::Ident::new("T", proc_macro2::Span::call_site()),
2780 &slot,
2781 )
2782 .to_string()
2783 };
2784
2785 let s = body(syn::parse_quote!(i32), super::SlotKind::ScalarInt);
2786 assert!(s.contains("\"'f' must be a number\" , \"value\""), "{s}");
2787 assert!(s.contains("scalar_rejection_reason (value)"), "{s}");
2788 assert!(s.contains("Some (\"i32\")"), "{s}");
2789 assert!(s.contains("__mx_conversion_err_parts ! ("), "{s}");
2790 assert!(!s.contains("failed to convert"), "{s}");
2791
2792 let s = body(syn::parse_quote!(bool), super::SlotKind::ScalarLogical);
2793 assert!(s.contains("\"'f' must be TRUE or FALSE\""), "{s}");
2794
2795 let s = body(syn::parse_quote!(Vec<String>), super::SlotKind::Conversion);
2796 assert!(s.contains("\"'f' must be character\" , \"value\""), "{s}");
2797 assert!(s.contains("Some (\"Vec<String>\")"), "{s}");
2798 assert!(s.contains(", true)"), "{s}");
2799
2800 let s = body(syn::parse_quote!(MyType), super::SlotKind::Conversion);
2803 assert!(s.contains("__mx_conversion_expectation ! (e)"), "{s}");
2804 assert!(s.contains("conversion_prefix (\"f\" , false ,"), "{s}");
2805 assert!(
2806 s.contains(") , \"value\" , :: core :: option :: Option :: Some (\"MyType\")"),
2807 "{s}"
2808 );
2809 assert!(s.contains("Some (\"MyType\")"), "{s}");
2810 }
2811
2812 #[test]
2816 fn sidecar_class_integration_reraises_tagged_conditions() {
2817 let slot = super::SidecarSlot {
2818 name: syn::Ident::new("f", proc_macro2::Span::call_site()),
2819 r_name: String::from("f"),
2820 ty: syn::parse_quote!(i32),
2821 vis: syn::parse_quote!(pub),
2822 is_public: true,
2823 kind: super::SlotKind::ScalarInt,
2824 access: super::SidecarAccess::default(),
2825 prop_doc: None,
2826 setter_invisible: None,
2827 };
2828 let slots = [&slot];
2829
2830 for cs in [ClassSystem::R6, ClassSystem::S7] {
2831 let out = generate_class_integration_r_code(cs, "T", &slots);
2832 assert_eq!(
2833 out.matches(".miniextendr_raise_condition(.val, sys.call())")
2834 .count(),
2835 2,
2836 "{cs:?} integration getter+setter should each carry the condition guard:\n{out}"
2837 );
2838 assert!(
2839 !out.contains(".call ="),
2840 "{cs:?} integration code must not pass a .call argument:\n{out}"
2841 );
2842 let getter_c = crate::naming::sidecar_getter_c_name("T", "f");
2845 let setter_c = crate::naming::sidecar_setter_c_name("T", "f");
2846 assert!(
2847 out.contains(&format!(".Call({getter_c}, ")) && out.contains(", FALSE)"),
2848 "{out}"
2849 );
2850 assert!(
2851 out.contains(&format!(".Call({setter_c}, ")) && out.contains(", value, FALSE)"),
2852 "{out}"
2853 );
2854 }
2855 }
2856
2857 #[test]
2863 fn r_data_name_renames_the_r_field_only() {
2864 let input: syn::DeriveInput = syn::parse_str(
2865 "struct Engine { #[r_data] _r: RSidecar, #[r_data(name = \"keys\")] pub r_keys: Sidecar<Vec<i32>>, \
2866 #[r_data(name = \"n.rows\")] pub n_rows: i32 }",
2867 )
2868 .unwrap();
2869 let info = super::parse_sidecar_info(&input, ClassSystem::R6).unwrap();
2870 assert_eq!(info.slots[0].r_name, "keys");
2871 assert_eq!(info.slots[1].r_name, "n.rows");
2872 let pub_slots: Vec<_> = info.slots.iter().collect();
2873
2874 let helpers = super::generate_field_syntax_helpers("Engine", &pub_slots, &[], None, false);
2875 assert!(
2876 helpers.contains(".rdata_fields_Engine <- c(\"keys\", \"n.rows\")\n"),
2877 "{helpers}"
2878 );
2879 let getter = crate::naming::sidecar_getter_c_name("Engine", "r_keys");
2880 assert!(
2881 helpers.contains(&format!(" keys = .Call({getter}, x, TRUE)")),
2882 "{helpers}"
2883 );
2884 assert!(
2885 helpers.contains("its fields are `keys`, `n.rows`"),
2886 "{helpers}"
2887 );
2888
2889 let r6 = super::generate_class_integration_r_code(ClassSystem::R6, "Engine", &pub_slots);
2890 assert!(r6.contains("cls$set(\"active\", \"keys\","), "{r6}");
2891 assert!(
2892 r6.contains(&format!(".Call({getter}, private$.ptr, FALSE)")),
2893 "{r6}"
2894 );
2895 assert!(!r6.contains("\"r_keys\""), "{r6}");
2896 let s7 = super::generate_class_integration_r_code(ClassSystem::S7, "Engine", &pub_slots);
2897 assert!(s7.contains(" keys = S7::new_property("), "{s7}");
2898
2899 let out = super::derive_external_ptr(input, true).unwrap().to_string();
2900 assert!(out.contains("Engine_get_keys <- function(x)"), "{out}");
2901 assert!(
2902 out.contains("Engine_set_keys <- function(x, value)"),
2903 "{out}"
2904 );
2905 assert!(out.contains("Engine_get_n.rows <- function(x)"), "{out}");
2906 assert!(!out.contains("Engine_get_r_keys"), "{out}");
2907 assert!(out.contains(&getter), "{out}");
2908 assert!(
2909 out.contains("__MX_CALL_DEF_RDATA_GET_Engine_r_keys"),
2910 "{out}"
2911 );
2912 assert!(
2913 out.contains("__MX_CALL_DEF_RDATA_GET_Engine_n_rows"),
2914 "{out}"
2915 );
2916 assert!(out.contains("pub fn r_keys (ptr :"), "{out}");
2919 assert!(out.contains("pub fn set_r_keys (ptr :"), "{out}");
2920 assert!(
2921 out.contains("visit (0usize , \"keys\" , & self . r_keys)"),
2922 "{out}"
2923 );
2924 assert!(out.contains("'n.rows' must be a number"), "{out}");
2926 }
2927
2928 #[test]
2931 fn r_data_name_is_checked() {
2932 let refused = |source: &str| {
2933 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
2934 super::parse_sidecar_info(&input, ClassSystem::Env)
2935 .err()
2936 .map(|err| err.to_string())
2937 .unwrap_or_else(|| panic!("`{source}` must be refused"))
2938 };
2939 let message = refused("struct E { #[r_data(name = \"\")] pub count: i32 }");
2940 assert!(message.contains("can't be empty"), "{message}");
2941 let message = refused("struct E { #[r_data(name = \".ptr\")] pub count: i32 }");
2942 assert!(message.contains("`.ptr` is the element"), "{message}");
2943 let message = refused("struct E { #[r_data(name = \"n rows\")] pub count: i32 }");
2944 assert!(message.contains("not a syntactic R name"), "{message}");
2945 let message = refused("struct E { #[r_data(name = \"for\")] pub count: i32 }");
2946 assert!(message.contains("not a syntactic R name"), "{message}");
2947 let message = refused(
2948 "struct E { #[r_data] pub keys: i32, #[r_data(name = \"keys\")] pub r_keys: Sidecar<Vec<i32>> }",
2949 );
2950 assert!(
2951 message.contains("`keys` is already taken by the field `keys`"),
2952 "{message}"
2953 );
2954 let message =
2955 refused("struct E { #[r_data(name = \"r\")] _r: RSidecar, #[r_data] pub count: i32 }");
2956 assert!(message.contains("not the RSidecar selector"), "{message}");
2957 let message = refused("struct E { #[r_data(name = \"a\", name = \"b\")] pub count: i32 }");
2958 assert!(message.contains("duplicate `name`"), "{message}");
2959 }
2960
2961 #[test]
2967 fn computed_fields_get_a_getter_and_a_read_only_setter_arm() {
2968 let input: syn::DeriveInput = syn::parse_str(
2969 "struct Engine { #[r_data] _r: RSidecar, \
2970 #[r_data(get = \"Self::group_by\")] pub group_by: Computed, \
2971 #[r_data(name = \"keys\")] pub r_keys: Sidecar<Vec<i32>>, \
2972 #[r_data(get = \"n_rows_of\")] pub n_rows: Computed, \
2973 #[r_data] pub base: i32 }",
2974 )
2975 .unwrap();
2976 let info = super::parse_sidecar_info(&input, ClassSystem::S3).unwrap();
2977 let kinds: Vec<_> = info.slots.iter().map(|slot| slot.kind.clone()).collect();
2978 assert_eq!(
2979 kinds,
2980 [
2981 super::SlotKind::Computed(syn::parse_quote!(Engine::group_by)),
2982 super::SlotKind::Sidecar(0),
2983 super::SlotKind::Computed(syn::parse_quote!(n_rows_of)),
2984 super::SlotKind::ScalarInt,
2985 ]
2986 );
2987 let name = syn::Ident::new("Engine", proc_macro2::Span::call_site());
2988 let getter = super::generate_getter_body(&name, &info.slots[0]).to_string();
2989 assert!(
2990 getter.contains("sidecar_r_struct :: < Engine > (x)"),
2991 "{getter}"
2992 );
2993 assert!(
2994 getter.contains("IntoR :: into_sexp (Engine :: group_by (data))"),
2995 "{getter}"
2996 );
2997 assert!(
2998 super::generate_setter_body(&name, &info.slots[0]).is_empty(),
2999 "a computed field has no setter body"
3000 );
3001
3002 let pub_slots: Vec<_> = info.slots.iter().collect();
3003 let helpers = super::generate_field_syntax_helpers("Engine", &pub_slots, &[], None, false);
3004 assert!(
3005 helpers.contains(
3006 ".rdata_fields_Engine <- c(\"group_by\", \"keys\", \"n_rows\", \"base\")\n"
3007 ),
3008 "{helpers}"
3009 );
3010 let group_by_getter = crate::naming::sidecar_getter_c_name("Engine", "group_by");
3011 assert!(
3012 helpers.contains(&format!(" group_by = .Call({group_by_getter}, x, TRUE),")),
3013 "{helpers}"
3014 );
3015 assert!(
3016 helpers.contains(
3017 " group_by = stop(errorCondition(sprintf(\"`group_by` of `%s` is computed from the Rust \
3018 value and can't be assigned\", if (is.null(oldClass(x))) \"Engine\" else oldClass(x)[[1L]]), \
3019 class = c(.rdata_error_class_Engine, \"miniextendr_read_only_field\"), \
3020 call = .miniextendr_frame_call(parent.frame()))),"
3021 ),
3022 "{helpers}"
3023 );
3024 let keys_setter = crate::naming::sidecar_setter_c_name("Engine", "r_keys");
3025 assert!(
3026 helpers.contains(&format!(" keys = .Call({keys_setter}, x, value, TRUE),")),
3027 "{helpers}"
3028 );
3029
3030 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3031 assert!(out.contains("Engine_get_group_by <- function(x)"), "{out}");
3032 assert!(!out.contains("Engine_set_group_by"), "{out}");
3033 assert!(
3034 out.contains("__MX_CALL_DEF_RDATA_GET_Engine_group_by"),
3035 "{out}"
3036 );
3037 assert!(
3038 !out.contains("__MX_CALL_DEF_RDATA_SET_Engine_group_by"),
3039 "{out}"
3040 );
3041 assert!(
3042 !out.contains(&crate::naming::sidecar_setter_c_name("Engine", "group_by")),
3043 "{out}"
3044 );
3045 assert!(
3046 out.contains("Engine_set_keys <- function(x, value)"),
3047 "{out}"
3048 );
3049 assert!(
3052 out.contains("_require_live : :: miniextendr_api :: SEXP"),
3053 "{out}"
3054 );
3055 assert!(out.contains("sidecar_require_live (require_live)"), "{out}");
3056 }
3057
3058 #[test]
3061 fn computed_fields_are_checked() {
3062 let refused = |source: &str, system: ClassSystem| {
3063 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
3064 super::parse_sidecar_info(&input, system)
3065 .err()
3066 .map(|err| err.to_string())
3067 .unwrap_or_else(|| panic!("`{source}` must be refused"))
3068 };
3069 let message = refused(
3070 "struct E { #[r_data(get = \"Self::f\")] pub count: i32 }",
3071 ClassSystem::S3,
3072 );
3073 assert!(
3074 message.contains("`get` applies to a `Computed` field only"),
3075 "{message}"
3076 );
3077 let message = refused(
3078 "struct E { #[r_data] pub count: Computed }",
3079 ClassSystem::S3,
3080 );
3081 assert!(
3082 message.contains("needs `#[r_data(get = \"Self::f\")]`"),
3083 "{message}"
3084 );
3085 let message = refused(
3086 "struct E { #[r_data(ref, get = \"Self::f\")] pub count: Computed }",
3087 ClassSystem::S3,
3088 );
3089 assert!(
3090 message.contains("read through its `get` function"),
3091 "{message}"
3092 );
3093 let message = refused(
3094 "struct E { #[r_data(setter = \"visible\", get = \"Self::f\")] pub count: Computed }",
3095 ClassSystem::S3,
3096 );
3097 assert!(
3098 message.contains("not the RSidecar selector or a `Computed` field"),
3099 "{message}"
3100 );
3101 let message = refused(
3102 "struct E { #[r_data(get = \"Self::f\")] count: Computed }",
3103 ClassSystem::S3,
3104 );
3105 assert!(message.contains("must be `pub`"), "{message}");
3106 for (system, name) in [(ClassSystem::R6, "r6"), (ClassSystem::S7, "s7")] {
3107 let message = refused(
3108 "struct E { #[r_data(get = \"Self::f\")] pub count: Computed }",
3109 system,
3110 );
3111 assert!(
3112 message.contains(&format!("not supported under `#[externalptr({name})]`")),
3113 "{message}"
3114 );
3115 }
3116 let message = refused(
3117 "struct E { #[r_data(get = \"not a path\")] pub count: Computed }",
3118 ClassSystem::S3,
3119 );
3120 assert!(message.contains("`get` must be a path"), "{message}");
3121 }
3122
3123 #[test]
3127 fn restored_options_reach_the_typed_external_impl() {
3128 let attrs = |source: &str| {
3129 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
3130 super::parse_externalptr_attrs(&input).map(|attrs| (attrs.class_system, attrs.restored))
3131 };
3132 let (system, restored) = attrs(
3133 "#[externalptr(s3, restored(class = [\"pkg_saved\", \"pkg_error\"], message = \"saved; rebuild it\"))] struct E;",
3134 )
3135 .unwrap();
3136 assert_eq!(system, ClassSystem::S3);
3137 assert_eq!(restored.class, ["pkg_saved", "pkg_error"]);
3138 assert_eq!(restored.message.as_deref(), Some("saved; rebuild it"));
3139 let (system, restored) =
3140 attrs("#[externalptr(restored(class = \"pkg_saved\"))] #[externalptr(s4)] struct E;")
3141 .unwrap();
3142 assert_eq!(system, ClassSystem::S4);
3143 assert_eq!(restored.class, ["pkg_saved"]);
3144 assert_eq!(restored.message, None);
3145 let (_, restored) = attrs("#[externalptr(restored(message = \"m\"))] struct E;").unwrap();
3146 assert!(restored.class.is_empty());
3147 assert_eq!(restored.message.as_deref(), Some("m"));
3148 let (_, restored) = attrs("#[externalptr(env)] struct E;").unwrap();
3149 assert_eq!(restored, super::RestoredOptions::default());
3150
3151 let refused = |source: &str, expected: &str| {
3152 let message = attrs(source)
3153 .err()
3154 .map(|e| e.to_string())
3155 .unwrap_or_else(|| panic!("`{source}` must be refused"));
3156 assert!(message.contains(expected), "`{source}`: {message}");
3157 };
3158 refused(
3160 "#[externalptr(restored())] struct E;",
3161 "expected nested attribute",
3162 );
3163 refused(
3164 "#[externalptr(restored(class = []))] struct E;",
3165 "at least one",
3166 );
3167 refused(
3168 "#[externalptr(restored(class = \"\"))] struct E;",
3169 "can't be empty",
3170 );
3171 refused(
3172 "#[externalptr(restored(message = \"\"))] struct E;",
3173 "can't be empty",
3174 );
3175 refused(
3176 "#[externalptr(restored(class = \"a\", class = \"b\"))] struct E;",
3177 "given twice",
3178 );
3179 refused(
3180 "#[externalptr(restored(class = \"a\"), restored(class = \"b\"))] struct E;",
3181 "given twice",
3182 );
3183 refused(
3184 "#[externalptr(restored(klass = \"a\"))] struct E;",
3185 "unknown `restored` option",
3186 );
3187 refused(
3188 "#[externalptr(saved)] struct E;",
3189 "unknown `externalptr` option",
3190 );
3191
3192 let input: syn::DeriveInput = syn::parse_str(
3193 "#[externalptr(s3, restored(class = [\"pkg_saved\", \"pkg_error\"], message = \"saved; rebuild it\"))] struct E { n: i32 }",
3194 )
3195 .unwrap();
3196 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3197 assert!(
3198 out.contains(
3199 "const RESTORED_ERROR_CLASS : & 'static [& 'static str] = & [\"pkg_saved\" , \"pkg_error\"] ;"
3200 ),
3201 "{out}"
3202 );
3203 assert!(
3204 out.contains(
3205 "const RESTORED_ERROR_MESSAGE : :: core :: option :: Option < & 'static str > = :: core :: option :: Option :: Some (\"saved; rebuild it\") ;"
3206 ),
3207 "{out}"
3208 );
3209 let input: syn::DeriveInput = syn::parse_str("struct E { n: i32 }").unwrap();
3210 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3211 assert!(!out.contains("RESTORED_ERROR_"), "{out}");
3212 }
3213
3214 #[test]
3219 fn rebuild_any_version_option() {
3220 let attrs = |source: &str| {
3221 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
3222 super::parse_externalptr_attrs(&input)
3223 };
3224 let parsed =
3225 attrs("#[externalptr(rebuild = Self::from_saved, any_version)] struct E;").unwrap();
3226 assert!(parsed.rebuild.is_some());
3227 assert!(parsed.any_version);
3228 let parsed = attrs("#[externalptr(rebuild = Self::from_saved)] struct E;").unwrap();
3229 assert!(!parsed.any_version);
3230 for source in [
3231 "#[externalptr(any_version)] struct E;",
3232 "#[externalptr(r6, any_version)] struct E;",
3233 ] {
3234 let message = attrs(source)
3235 .err()
3236 .map(|e| e.to_string())
3237 .unwrap_or_default();
3238 assert!(
3239 message.contains("needs `rebuild = path`"),
3240 "`{source}`: {message}"
3241 );
3242 }
3243 let message = attrs("#[externalptr(rebuild = f, any_version, any_version)] struct E;")
3244 .err()
3245 .map(|e| e.to_string())
3246 .unwrap_or_default();
3247 assert!(
3248 message.contains("`any_version` is given twice"),
3249 "{message}"
3250 );
3251
3252 let input: syn::DeriveInput = syn::parse_str(
3253 "#[externalptr(rebuild = Self::from_saved, any_version)] struct E { #[r_data] keys: Sidecar<Vec<i32>>, #[r_data(name = \"n.rows\")] r_rows: Sidecar<i32> }",
3254 )
3255 .unwrap();
3256 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3257 assert!(
3258 out.contains("const REBUILDS_ANY_VERSION : bool = true ;"),
3259 "{out}"
3260 );
3261 assert!(
3265 out.contains(
3266 "const SIDECAR_NAMES : & 'static [& 'static str] = & [\"keys\" , \"n.rows\"] ;"
3267 ),
3268 "{out}"
3269 );
3270 assert!(
3271 out.contains("visit (1usize , \"n.rows\" , & self . r_rows) ;"),
3272 "{out}"
3273 );
3274 assert!(
3275 out.contains(
3276 "fn try_keys (saved : & :: miniextendr_api :: externalptr :: Saved < '_ , Self > ,)"
3277 ),
3278 "{out}"
3279 );
3280 assert!(out.contains("fn try_r_rows (saved"), "{out}");
3282 assert!(
3283 out.contains("sidecar_try_saved :: < Self , i32 > (saved , 1usize , \"n.rows\" ,)"),
3284 "{out}"
3285 );
3286 assert!(
3287 out.contains("sidecar_get :: < Self , i32 > (ptr , 1usize , \"n.rows\" ,"),
3288 "{out}"
3289 );
3290 assert!(
3291 out.contains("sidecar_set :: < Self , i32 > (ptr , 1usize , \"n.rows\" ,"),
3292 "{out}"
3293 );
3294 assert!(!out.contains("\"r_rows\""), "{out}");
3295
3296 let input: syn::DeriveInput =
3298 syn::parse_str("struct E { #[r_data] keys: Sidecar<Vec<i32>> }").unwrap();
3299 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3300 assert!(!out.contains("try_keys"), "{out}");
3301 assert!(!out.contains("REBUILDS"), "{out}");
3302 }
3303
3304 #[test]
3309 fn field_error_and_every_read_options() {
3310 let attrs = |source: &str| {
3311 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
3312 super::parse_externalptr_attrs(&input)
3313 };
3314 let parsed = attrs(
3315 "#[externalptr(s3, field_error(class = [\"pkg_config\", \"pkg_error\"]), restored(class = \"pkg_saved\", refuse = \"every_read\"))] struct E;",
3316 )
3317 .unwrap();
3318 assert_eq!(parsed.field_error.class, ["pkg_config", "pkg_error"]);
3319 assert_eq!(parsed.field_error.message, None);
3320 assert!(parsed.restored.every_read);
3321 assert_eq!(parsed.restored.class, ["pkg_saved"]);
3322 let parsed = attrs("#[externalptr(field_error(class = \"pkg_error\"))] struct E;").unwrap();
3323 assert_eq!(parsed.field_error.class, ["pkg_error"]);
3324 let parsed =
3326 attrs("#[externalptr(field_error(message = \"not a rec\"))] struct E;").unwrap();
3327 assert!(parsed.field_error.class.is_empty());
3328 assert_eq!(parsed.field_error.message.as_deref(), Some("not a rec"));
3329 assert!(!parsed.restored.every_read);
3330 let parsed =
3332 attrs("#[externalptr(field_error(no_field_hint = \"try `y$%s`\"))] struct E;").unwrap();
3333 assert_eq!(
3334 parsed.field_error.no_field_hint.as_deref(),
3335 Some("try `y$%s`")
3336 );
3337 assert_eq!(parsed.field_error.message, None);
3338
3339 let refused = |source: &str, expected: &str| {
3340 let message = attrs(source)
3341 .err()
3342 .map(|e| e.to_string())
3343 .unwrap_or_else(|| panic!("`{source}` must be refused"));
3344 assert!(message.contains(expected), "`{source}`: {message}");
3345 };
3346 refused(
3347 "#[externalptr(restored(refuse = \"names\"))] struct E;",
3348 "`refuse` takes \"every_read\"",
3349 );
3350 refused(
3351 "#[externalptr(restored(refuse = \"every_read\", refuse = \"every_read\"))] struct E;",
3352 "given twice",
3353 );
3354 refused(
3355 "#[externalptr(field_error(class = []))] struct E;",
3356 "at least one",
3357 );
3358 refused(
3359 "#[externalptr(field_error(text = \"m\"))] struct E;",
3360 "unknown `field_error` option",
3361 );
3362 refused(
3363 "#[externalptr(field_error(message = \"\"))] struct E;",
3364 "`message` is empty",
3365 );
3366 refused(
3367 "#[externalptr(field_error(message = \"a\", message = \"b\"))] struct E;",
3368 "given twice",
3369 );
3370 refused(
3371 "#[externalptr(field_error(no_field_hint = \"\"))] struct E;",
3372 "`no_field_hint` is empty",
3373 );
3374 refused(
3375 "#[externalptr(field_error(no_field_hint = \"a\", no_field_hint = \"b\"))] struct E;",
3376 "given twice",
3377 );
3378 refused(
3379 "#[externalptr(field_error(class = \"a\"), field_error(class = \"b\"))] struct E;",
3380 "given twice",
3381 );
3382
3383 let source = "#[externalptr(s3, field_error(class = [\"pkg_config\", \"pkg_error\"]), restored(refuse = \"every_read\"))] \
3384 struct Engine { #[r_data] r: RSidecar, #[r_data] pub keys: Sidecar<Vec<i32>> }";
3385 let out = super::derive_external_ptr(syn::parse_str(source).unwrap(), true)
3386 .unwrap()
3387 .to_string();
3388 assert!(
3389 out.contains(
3390 "const FIELD_ERROR_CLASS : & 'static [& 'static str] = & [\"pkg_config\" , \"pkg_error\"] ;"
3391 ),
3392 "{out}"
3393 );
3394 let live = crate::naming::sidecar_live_c_name("Engine");
3395 assert!(out.contains(&format!("fn {live}")), "{out}");
3396 assert!(out.contains("sidecar_r_live :: < Engine >"), "{out}");
3397 assert!(
3398 out.contains(".rdata_error_class_Engine <- c(\\\"pkg_config\\\", \\\"pkg_error\\\")"),
3399 "{out}"
3400 );
3401 assert!(
3402 out.contains(&format!(
3403 ".rdata_live_Engine <- function(x, raise) .Call({live}, x, raise)"
3404 )),
3405 "{out}"
3406 );
3407 assert!(out.contains(".rdata_every_read_Engine <- TRUE"), "{out}");
3408
3409 let out = super::derive_external_ptr(
3410 syn::parse_str(
3411 "struct Engine { #[r_data] r: RSidecar, #[r_data] pub keys: Sidecar<Vec<i32>> }",
3412 )
3413 .unwrap(),
3414 true,
3415 )
3416 .unwrap()
3417 .to_string();
3418 assert!(!out.contains("FIELD_ERROR_CLASS"), "{out}");
3419 assert!(!out.contains("mx_rdata_live_"), "{out}");
3420 assert!(out.contains(".rdata_error_class_Engine <- NULL"), "{out}");
3421 assert!(out.contains(".rdata_every_read_Engine <- FALSE"), "{out}");
3422 assert!(
3423 out.contains(".rdata_live_Engine <- function(x, raise) TRUE"),
3424 "{out}"
3425 );
3426 }
3427
3428 #[test]
3431 fn standalone_accessors_come_exported_and_internal() {
3432 for exported in [true, false] {
3433 let out = generate_r_wrapper_for_slot(
3434 ClassSystem::S3,
3435 "T",
3436 "f",
3437 "get_f",
3438 Some("set_f"),
3439 true,
3440 exported,
3441 );
3442 assert!(out.contains("T_get_f <- function(x)"), "{out}");
3443 assert!(out.contains("T_set_f <- function(x, value)"), "{out}");
3444 assert_eq!(out.contains("@export"), exported, "{out}");
3445 assert_eq!(out.contains("@rdname T"), exported, "{out}");
3446 assert_eq!(
3447 out.matches("#' @noRd").count(),
3448 if exported { 0 } else { 2 },
3449 "{out}"
3450 );
3451 }
3452 let out = super::derive_external_ptr(
3453 syn::parse_str("struct T { #[r_data] r: RSidecar, #[r_data] pub f: i32 }").unwrap(),
3454 true,
3455 )
3456 .unwrap()
3457 .to_string();
3458 assert!(out.contains("MX_SIDECAR_ACCESSORS"), "{out}");
3459 assert!(out.contains("R_SIDECAR_ACCESSORS_T"), "{out}");
3460 }
3461
3462 #[test]
3463 fn field_setter_visibility_reaches_standalone_and_integrated_wrappers() {
3464 for (attribute, explicit) in [
3465 ("", None),
3466 ("setter = \"visible\"", Some(false)),
3467 ("setter = \"invisible\"", Some(true)),
3468 ] {
3469 let input: syn::DeriveInput = syn::parse_str(&format!(
3470 "struct Example {{ #[r_data({attribute})] pub value: i32 }}"
3471 ))
3472 .unwrap();
3473 for system in ALL_CLASS_SYSTEMS {
3474 let info = super::parse_sidecar_info(&input, system).unwrap();
3475 let slot = &info.slots[0];
3476 assert_eq!(slot.setter_invisible, explicit);
3477 let standalone = generate_r_wrapper_for_slot(
3478 system,
3479 "Example",
3480 "value",
3481 "get_value",
3482 Some("set_value"),
3483 slot.setter_invisible.unwrap_or(true),
3484 true,
3485 );
3486 assert_eq!(
3487 standalone.contains("invisible(x)"),
3488 explicit.unwrap_or(true)
3489 );
3490 assert!(standalone.contains(if explicit == Some(false) {
3491 "pointer (visibly)"
3492 } else {
3493 "pointer (invisibly)"
3494 }));
3495 let integrated = generate_class_integration_r_code(system, "Example", &[slot]);
3496 match system {
3497 ClassSystem::R6 => assert_eq!(
3498 integrated.contains("invisible(self)"),
3499 explicit.unwrap_or(true)
3500 ),
3501 ClassSystem::S7 => assert_eq!(
3502 integrated.contains("invisible(self)"),
3503 explicit.unwrap_or(false)
3504 ),
3505 _ => assert!(integrated.is_empty()),
3506 }
3507 }
3508 }
3509 }
3510
3511 #[test]
3512 fn setter_visibility_and_property_docs_can_share_or_split_attributes() {
3513 for attrs in [
3514 "#[r_data(prop_doc = \"A counter\", setter = \"visible\")]",
3515 "#[r_data] #[r_data(setter = \"visible\", prop_doc = \"A counter\")]",
3516 ] {
3517 let input: syn::DeriveInput =
3518 syn::parse_str(&format!("struct Example {{ {attrs} pub value: i32 }}")).unwrap();
3519 let info = super::parse_sidecar_info(&input, ClassSystem::S7).unwrap();
3520 assert_eq!(info.slots[0].prop_doc.as_deref(), Some("A counter"));
3521 assert_eq!(info.slots[0].setter_invisible, Some(false));
3522 }
3523 }
3524
3525 #[test]
3531 fn sidecar_fields_number_their_own_positions() {
3532 let input: syn::DeriveInput = syn::parse_str(
3533 "struct Engine { #[r_data] _r: RSidecar, #[r_data] pub a: i32, \
3534 #[r_data] pub keys: Sidecar<Vec<i32>>, #[r_data] pub c: String, \
3535 #[r_data] steps: Sidecar<Option<List>> }",
3536 )
3537 .unwrap();
3538 let info = super::parse_sidecar_info(&input, ClassSystem::Env).unwrap();
3539 let kinds: Vec<_> = info.slots.iter().map(|slot| slot.kind.clone()).collect();
3540 assert_eq!(
3541 kinds,
3542 [
3543 super::SlotKind::ScalarInt,
3544 super::SlotKind::Sidecar(0),
3545 super::SlotKind::Conversion,
3546 super::SlotKind::Sidecar(1),
3547 ]
3548 );
3549 assert_eq!(
3551 info.slots[1].access,
3552 super::SidecarAccess {
3553 get: true,
3554 set: true
3555 }
3556 );
3557
3558 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3559 assert!(
3560 out.contains("const R_SLOT_COUNT : usize = 2usize ;"),
3561 "{out}"
3562 );
3563 assert!(
3564 out.contains("visit (0usize , \"keys\" , & self . keys) ; visit (1usize , \"steps\" , & self . steps) ;"),
3565 "{out}"
3566 );
3567 assert!(
3570 out.contains(
3571 "pub fn keys (ptr : & impl :: miniextendr_api :: externalptr :: SidecarOwner < Self >) -> Vec < i32 > { :: miniextendr_api :: externalptr :: sidecar_get :: < Self , Vec < i32 > > (ptr , 0usize , \"keys\" , | this : & Self | & this . keys ,) }"
3572 ),
3573 "{out}"
3574 );
3575 assert!(
3576 out.contains(
3577 "pub fn set_keys (ptr : & mut impl :: miniextendr_api :: externalptr :: SidecarOwnerMut < Self > , value : Vec < i32 >) { :: miniextendr_api :: externalptr :: sidecar_set :: < Self , Vec < i32 > > (ptr , 0usize , \"keys\" , | this : & Self | & this . keys , value ,) }"
3578 ),
3579 "{out}"
3580 );
3581 assert!(!out.contains("fn keys (& self)"), "{out}");
3582 assert!(
3585 out.contains(
3586 "# [allow (dead_code)] fn steps (ptr : & impl :: miniextendr_api :: externalptr :: SidecarOwner < Self >) -> Option < List >"
3587 ),
3588 "{out}"
3589 );
3590 assert!(
3591 out.contains(
3592 "# [allow (dead_code)] fn set_steps (ptr : & mut impl :: miniextendr_api :: externalptr :: SidecarOwnerMut < Self > , value : Option < List >)"
3593 ),
3594 "{out}"
3595 );
3596 assert!(out.contains("(ptr , 1usize , \"steps\" ,"), "{out}");
3597 assert!(!out.contains("get_steps"), "{out}");
3598
3599 let keys = &info.slots[1];
3601 let name = syn::Ident::new("Engine", proc_macro2::Span::call_site());
3602 let getter = super::generate_getter_body(&name, keys).to_string();
3603 assert!(
3606 getter.contains(
3607 "sidecar_r_get :: < Engine > (x , 0usize , :: miniextendr_api :: externalptr :: sidecar_require_live (require_live) ,)"
3608 ),
3609 "{getter}"
3610 );
3611 assert!(!getter.contains("R_ExternalPtrAddr"), "{getter}");
3612 let setter = super::generate_setter_body(&name, keys).to_string();
3613 assert!(
3614 setter.contains("sidecar_r_check :: < Engine > (x , require_live)"),
3615 "{setter}"
3616 );
3617 assert!(
3619 setter.contains("< Vec < i32 > as TryFromSexp > :: try_from_sexp (value)"),
3620 "{setter}"
3621 );
3622 assert!(setter.contains("\"'keys' must be integer\""), "{setter}");
3623 assert!(setter.contains("Some (\"Vec<i32>\")"), "{setter}");
3624 assert!(
3625 setter.contains("sidecar_r_set :: < Engine > (x , 0usize , value , require_live ,)"),
3626 "{setter}"
3627 );
3628 }
3629
3630 #[test]
3632 fn sidecar_access_options_select_the_accessors() {
3633 let input: syn::DeriveInput = syn::parse_str(
3634 "struct Engine { #[r_data(ref)] pub keys: Sidecar<Vec<i32>>, \
3635 #[r_data(mut)] pub(crate) note: Sidecar<String> }",
3636 )
3637 .unwrap();
3638 let info = super::parse_sidecar_info(&input, ClassSystem::Env).unwrap();
3639 assert_eq!(
3640 info.slots[0].access,
3641 super::SidecarAccess {
3642 get: true,
3643 set: false
3644 }
3645 );
3646 assert_eq!(
3647 info.slots[1].access,
3648 super::SidecarAccess {
3649 get: false,
3650 set: true
3651 }
3652 );
3653 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3654 assert!(
3655 out.contains(
3656 "pub fn keys (ptr : & impl :: miniextendr_api :: externalptr :: SidecarOwner < Self >) -> Vec < i32 >"
3657 ),
3658 "{out}"
3659 );
3660 assert!(!out.contains("fn set_keys"), "{out}");
3661 assert!(
3662 out.contains(
3663 "# [allow (dead_code)] pub (crate) fn set_note (ptr : & mut impl :: miniextendr_api :: externalptr :: SidecarOwnerMut < Self > , value : String)"
3664 ),
3665 "{out}"
3666 );
3667 assert!(!out.contains("fn note ("), "{out}");
3668 let input: syn::DeriveInput =
3671 syn::parse_str("struct Engine { #[r_data(mut, ref)] pub keys: Sidecar<Vec<i32>> }")
3672 .unwrap();
3673 let info = super::parse_sidecar_info(&input, ClassSystem::Env).unwrap();
3674 assert_eq!(
3675 info.slots[0].access,
3676 super::SidecarAccess {
3677 get: true,
3678 set: true
3679 }
3680 );
3681 }
3682
3683 #[test]
3686 fn sidecar_access_options_are_checked() {
3687 let refused = |source: &str| {
3688 let input: syn::DeriveInput = syn::parse_str(source).unwrap();
3689 super::parse_sidecar_info(&input, ClassSystem::Env)
3690 .err()
3691 .map(|err| err.to_string())
3692 .unwrap_or_else(|| panic!("`{source}` must be refused"))
3693 };
3694 let message = refused("struct E { #[r_data(ref)] pub count: i32 }");
3695 assert!(
3696 message.contains("apply to `Sidecar<T>` fields only"),
3697 "{message}"
3698 );
3699 let message = refused("struct E { pub keys: Sidecar<Vec<i32>> }");
3700 assert!(message.contains("needs `#[r_data]`"), "{message}");
3701 let message = refused("struct E { #[r_data(ref, ref)] pub keys: Sidecar<Vec<i32>> }");
3702 assert!(message.contains("duplicate `ref`"), "{message}");
3703 let message = refused("struct E { #[r_data] pub keys: Sidecar }");
3704 assert!(message.contains("takes one type argument"), "{message}");
3705 }
3706
3707 #[test]
3713 fn field_syntax_helpers_switch_over_the_accessors() {
3714 let slot = |name: &str| super::SidecarSlot {
3715 name: syn::parse_str(name).unwrap(),
3716 r_name: crate::naming::ident_name(&syn::parse_str::<syn::Ident>(name).unwrap()),
3717 ty: syn::parse_quote!(i32),
3718 vis: syn::parse_quote!(pub),
3719 is_public: true,
3720 kind: super::SlotKind::ScalarInt,
3721 access: super::SidecarAccess::default(),
3722 prop_doc: None,
3723 setter_invisible: None,
3724 };
3725 let (keys, reserved) = (slot("keys"), slot("r#for"));
3726 let out =
3727 super::generate_field_syntax_helpers("Engine", &[&keys, &reserved], &[], None, false);
3728 assert!(
3729 out.contains(".rdata_fields_Engine <- c(\"keys\", \"for\")\n"),
3730 "{out}"
3731 );
3732 let getter = crate::naming::sidecar_getter_c_name("Engine", "keys");
3733 let setter = crate::naming::sidecar_setter_c_name("Engine", "for");
3734 assert!(
3735 out.contains(&format!(
3736 ".rdata_get_Engine <- function(x, name) switch(name,\n keys = .Call({getter}, x, TRUE),"
3737 )),
3738 "{out}"
3739 );
3740 assert!(
3741 out.contains(&format!(" `for` = .Call({setter}, x, value, TRUE))\n")),
3742 "{out}"
3743 );
3744 assert!(
3745 out.contains(
3746 "function(name, env, cls) stop(errorCondition(\n sprintf(\"`%s` is not a field of `%s`; its fields are `keys`, `for`\", name, cls),"
3747 ),
3748 "{out}"
3749 );
3750 assert!(
3751 out.contains("class = c(.rdata_error_class_Engine, \"miniextendr_no_field\"), call = .miniextendr_frame_call(env)"),
3752 "{out}"
3753 );
3754
3755 let out = super::generate_field_syntax_helpers(
3759 "Engine",
3760 &[&keys],
3761 &[],
3762 Some("See `t$%s` or \"u\\%s\" (50% off)."),
3763 false,
3764 );
3765 assert!(
3766 out.contains(
3767 " paste0(sprintf(\"`%s` is not a field of `%s`; its fields are `keys`\", name, cls), \". \", \
3768 \"See `t$\", name, \"` or \\\"u\\\\\", name, \"\\\" (50% off).\"),\n"
3769 ),
3770 "{out}"
3771 );
3772 }
3773
3774 #[test]
3777 fn field_syntax_helpers_follow_the_r_accessors() {
3778 for attr in ["", "#[externalptr(r6)]", "#[externalptr(s3)]"] {
3779 let input: syn::DeriveInput = syn::parse_str(&format!(
3780 "{attr} struct Engine {{ #[r_data] _r: RSidecar, #[r_data] pub count: i32 }}"
3781 ))
3782 .unwrap();
3783 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3784 assert!(out.contains(".rdata_fields_Engine"), "{attr}: {out}");
3785 }
3786 let input: syn::DeriveInput =
3787 syn::parse_str("struct Engine { #[r_data] pub count: i32 }").unwrap();
3788 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3789 assert!(!out.contains(".rdata_"), "{out}");
3790 }
3791
3792 #[test]
3793 fn no_sidecar_fields_emit_no_count_or_hook() {
3794 let input: syn::DeriveInput =
3795 syn::parse_str("struct Plain { #[r_data] _r: RSidecar, #[r_data] pub a: i32 }")
3796 .unwrap();
3797 let out = super::derive_external_ptr(input, true).unwrap().to_string();
3798 assert!(!out.contains("R_SLOT_COUNT"), "{out}");
3799 assert!(!out.contains("__mx_visit_sidecars"), "{out}");
3800 assert!(!out.contains("sidecar_get"), "{out}");
3801 }
3802
3803 #[test]
3804 fn r_views_in_plain_fields_are_refused_recursively() {
3805 for ty in [
3806 "List",
3807 "ListMut",
3808 "NamedList",
3809 "DataFrame",
3810 "StrVec<'static>",
3811 "RCow<'static, i32>",
3812 "RArray<i32, 2>",
3813 "RVector<f64>",
3814 "RMatrix<i32>",
3815 "RArray3D<f64>",
3816 "Factor<'static>",
3817 "FactorMut<'static>",
3818 "::miniextendr_api::list::List",
3819 "Option<List>",
3820 "Vec<Option<DataFrame>>",
3821 "HashMap<String, Vec<List>>",
3822 "Result<Vec<i32>, SEXP>",
3823 "Box<[List]>",
3824 "[Option<List>; 2]",
3825 "(i32, Vec<NamedList>)",
3826 "&'static List",
3827 "&'static str",
3828 "Option<&'static i32>",
3829 "Box<&'static [f64]>",
3830 "Arc<Mutex<Option<List>>>",
3831 "(List)",
3832 ] {
3833 let input =
3834 syn::parse_str(&format!("struct Bad {{ #[r_data] pub value: {ty} }}")).unwrap();
3835 let err = super::derive_external_ptr(input, true).unwrap_err();
3836 assert!(err.to_string().contains("is not rooted"), "{ty}: {err}");
3837 assert!(err.to_string().contains("Sidecar<"), "{ty}: {err}");
3838 }
3839 }
3840
3841 #[test]
3842 fn owned_fields_and_sidecars_keep_their_existing_classification() {
3843 for ty in [
3844 "String",
3845 "Vec<Option<i32>>",
3846 "HashMap<String, Vec<f64>>",
3847 "Preserved",
3848 "BuiltList",
3849 "BuiltDataFrame",
3850 "ProtectedStrVec",
3851 "Option<BuiltList>",
3852 "Cow<'static, str>",
3853 "PhantomData<List>",
3854 ] {
3855 let ty = syn::parse_str(ty).unwrap();
3856 assert!(!super::contains_unrooted_r_view(&ty), "{ty:?}");
3857 }
3858 for ty in [
3859 "Sidecar<List>",
3860 "Sidecar<Option<List>>",
3861 "Sidecar<DataFrame>",
3862 ] {
3863 let ty = syn::parse_str(ty).unwrap();
3864 let kind = super::slot_kind_for_type(&ty, 2, None, &syn::parse_quote!(Host)).unwrap();
3865 assert!(matches!(kind, super::SlotKind::Sidecar(2)));
3866 }
3867 }
3868
3869 #[test]
3871 fn bare_sexp_sidecar_field_is_refused() {
3872 let input: syn::DeriveInput =
3873 syn::parse_str("struct Engine { #[r_data] _r: RSidecar, #[r_data] pub keys: SEXP }")
3874 .unwrap();
3875 let Err(err) = super::parse_sidecar_info(&input, ClassSystem::Env) else {
3876 panic!("a SEXP sidecar field must be refused");
3877 };
3878 let message = err.to_string();
3879 assert!(message.contains("is not rooted"), "{message}");
3880 assert!(
3881 message.contains("Declare the field as `Sidecar<SEXP>`"),
3882 "{message}"
3883 );
3884 }
3885}