1use proc_macro2::TokenStream;
116use quote::quote;
117
118fn is_external_ptr_type(ty: &syn::Type) -> bool {
120 if let syn::Type::Path(type_path) = ty {
121 type_path
122 .path
123 .segments
124 .last()
125 .map(|seg| seg.ident == "ExternalPtr")
126 .unwrap_or(false)
127 } else {
128 false
129 }
130}
131
132fn old_handle_receiver(sig: &syn::Signature) -> syn::Result<()> {
136 let Some(syn::FnArg::Receiver(receiver)) = sig.inputs.first() else {
137 return Ok(());
138 };
139 let syn::Type::Reference(reference) = receiver.ty.as_ref() else {
140 return Ok(());
141 };
142 if receiver.colon_token.is_none() || !is_external_ptr_type(&reference.elem) {
143 return Ok(());
144 }
145 let (view, binding) = if reference.mutability.is_some() {
146 ("ExternalPtrMut", "mut self")
147 } else {
148 ("ExternalPtrRef", "self")
149 };
150 Err(syn::Error::new_spanned(
151 &receiver.ty,
152 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a method takes its object as `{0}: {1}<\'_, Self>`: the wrapper borrows the value for the call, and the view carries the R object for the sidecar accessors (`Self::field(&self)`); use `&self` / `&mut self` when the body needs only the value, or `self: ExternalPtr<Self>` for the unborrowed handle",
binding, view))
})format!(
153 "a method takes its object as `{binding}: {view}<'_, Self>`: the wrapper borrows the \
154 value for the call, and the view carries the R object for the sidecar accessors \
155 (`Self::field(&self)`); use `&self` / `&mut self` when the body needs only the \
156 value, or `self: ExternalPtr<Self>` for the unborrowed handle"
157 ),
158 ))
159}
160
161fn rewrite_external_ptr_receivers(mut item_impl: syn::ItemImpl) -> syn::ItemImpl {
171 for item in &mut item_impl.items {
172 let syn::ImplItem::Fn(method) = item else {
173 continue;
174 };
175 if crate::trait_receiver::owner_receiver(&method.sig).is_some() {
176 crate::trait_receiver::rewrite(&mut method.sig, Some(&mut method.block));
177 continue;
178 }
179 let Some(syn::FnArg::Receiver(receiver)) = method.sig.inputs.first() else {
180 continue;
181 };
182 if receiver.colon_token.is_none() || !is_external_ptr_type(receiver.ty.as_ref()) {
183 continue;
184 }
185
186 let receiver_ident =
188 proc_macro2::Ident::new("__miniextendr_self", proc_macro2::Span::mixed_site());
189 let binding_mutability = receiver.mutability;
190 let inner_ty = &receiver.ty;
191 let new_param: syn::FnArg = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&binding_mutability, &mut _s);
::quote::ToTokens::to_tokens(&receiver_ident, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
_s
})syn::parse_quote! {
192 #binding_mutability #receiver_ident: #inner_ty
193 };
194
195 let inputs: Vec<syn::FnArg> = method.sig.inputs.iter().cloned().collect();
197 let mut new_inputs: Vec<syn::FnArg> = Vec::with_capacity(inputs.len());
198 new_inputs.push(new_param);
199 new_inputs.extend(inputs.into_iter().skip(1));
200 method.sig.inputs = new_inputs.into_iter().collect();
201
202 crate::receiver_body::rewrite(&mut method.block, &receiver_ident);
203 }
204 item_impl
205}
206
207fn strip_miniextendr_attrs_from_impl(mut item_impl: syn::ItemImpl) -> syn::ItemImpl {
213 item_impl.attrs = crate::roxygen::strip_roxygen_from_attrs(&item_impl.attrs);
214 item_impl
215 .attrs
216 .retain(|attr| !attr.path().is_ident("miniextendr"));
217 for item in &mut item_impl.items {
218 match item {
219 syn::ImplItem::Fn(fn_item) => {
220 fn_item.attrs = crate::roxygen::strip_roxygen_from_attrs(&fn_item.attrs);
221 fn_item
222 .attrs
223 .retain(|attr| !attr.path().is_ident("miniextendr"));
224 }
225 syn::ImplItem::Const(const_item) => {
226 const_item.attrs = crate::roxygen::strip_roxygen_from_attrs(&const_item.attrs);
227 const_item
228 .attrs
229 .retain(|attr| !attr.path().is_ident("miniextendr"));
230 }
231 syn::ImplItem::Type(type_item) => {
232 type_item.attrs = crate::roxygen::strip_roxygen_from_attrs(&type_item.attrs);
233 type_item
234 .attrs
235 .retain(|attr| !attr.path().is_ident("miniextendr"));
236 }
237 syn::ImplItem::Macro(macro_item) => {
238 macro_item.attrs = crate::roxygen::strip_roxygen_from_attrs(¯o_item.attrs);
239 macro_item
240 .attrs
241 .retain(|attr| !attr.path().is_ident("miniextendr"));
242 }
243 _ => {}
244 }
245 }
246 item_impl
247}
248
249#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ClassSystem {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ClassSystem::Env => "Env",
ClassSystem::R6 => "R6",
ClassSystem::S7 => "S7",
ClassSystem::S3 => "S3",
ClassSystem::S4 => "S4",
ClassSystem::Vctrs => "Vctrs",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ClassSystem { }
#[automatically_derived]
impl ::core::clone::Clone for ClassSystem {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ClassSystem { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ClassSystem { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ClassSystem {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ClassSystem { }Eq)]
251pub enum ClassSystem {
252 Env,
254 R6,
256 S7,
258 S3,
260 S4,
262 Vctrs,
264}
265
266impl ClassSystem {
267 pub fn to_ident(self) -> syn::Ident {
269 let name = match self {
270 ClassSystem::Env => "env",
271 ClassSystem::R6 => "r6",
272 ClassSystem::S7 => "s7",
273 ClassSystem::S3 => "s3",
274 ClassSystem::S4 => "s4",
275 ClassSystem::Vctrs => "vctrs",
276 };
277 syn::Ident::new(name, proc_macro2::Span::call_site())
278 }
279
280 pub fn from_ident(ident: &syn::Ident) -> Option<Self> {
282 match ident.to_string().as_str() {
283 "env" => Some(ClassSystem::Env),
284 "r6" => Some(ClassSystem::R6),
285 "s7" => Some(ClassSystem::S7),
286 "s3" => Some(ClassSystem::S3),
287 "s4" => Some(ClassSystem::S4),
288 "vctrs" => Some(ClassSystem::Vctrs),
289 _ => None,
290 }
291 }
292}
293
294impl std::str::FromStr for ClassSystem {
298 type Err = String;
299
300 fn from_str(s: &str) -> Result<Self, Self::Err> {
301 match s.to_lowercase().as_str() {
302 "env" => Ok(ClassSystem::Env),
303 "r6" => Ok(ClassSystem::R6),
304 "s7" => Ok(ClassSystem::S7),
305 "s3" => Ok(ClassSystem::S3),
306 "s4" => Ok(ClassSystem::S4),
307 "vctrs" => Ok(ClassSystem::Vctrs),
308 _ => Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown class system: {0}", s))
})format!("unknown class system: {}", s)),
309 }
310 }
311}
312
313#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RDataAccessors {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
RDataAccessors::Off => "Off",
RDataAccessors::GetSet => "GetSet",
RDataAccessors::GetOnly => "GetOnly",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RDataAccessors { }
#[automatically_derived]
impl ::core::clone::Clone for RDataAccessors {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for RDataAccessors { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for RDataAccessors { }
#[automatically_derived]
impl ::core::cmp::PartialEq for RDataAccessors {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RDataAccessors { }Eq, #[automatically_derived]
impl ::core::default::Default for RDataAccessors {
#[inline]
fn default() -> Self { Self::Off }
}Default)]
320pub enum RDataAccessors {
321 #[default]
323 Off,
324 GetSet,
326 GetOnly,
331}
332
333impl RDataAccessors {
334 pub fn enabled(self) -> bool {
336 self != RDataAccessors::Off
337 }
338
339 pub fn setters(self) -> bool {
341 self == RDataAccessors::GetSet
342 }
343}
344
345#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FieldLookup {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
FieldLookup::Strict => "Strict",
FieldLookup::List => "List",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FieldLookup { }
#[automatically_derived]
impl ::core::clone::Clone for FieldLookup {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for FieldLookup { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for FieldLookup { }
#[automatically_derived]
impl ::core::cmp::PartialEq for FieldLookup {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FieldLookup { }Eq, #[automatically_derived]
impl ::core::default::Default for FieldLookup {
#[inline]
fn default() -> Self { Self::Strict }
}Default)]
349pub enum FieldLookup {
350 #[default]
354 Strict,
355 List,
359}
360
361#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FieldFallback {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "FieldFallback",
"get", &self.get, "names", &&self.names)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for FieldFallback {
#[inline]
fn clone(&self) -> Self {
FieldFallback {
get: ::core::clone::Clone::clone(&self.get),
names: ::core::clone::Clone::clone(&self.names),
}
}
}Clone)]
389pub struct FieldFallback {
390 pub get: syn::LitStr,
392 pub names: Option<syn::LitStr>,
394}
395
396fn parse_fallback_value(
400 content: syn::parse::ParseStream,
401 key: &syn::Ident,
402) -> syn::Result<syn::LitStr> {
403 let example = if key == "fallback" {
404 "Self::column"
405 } else {
406 "Self::column_names"
407 };
408 if !content.peek(::syn::token::Eqsyn::Token![=]) {
409 return Err(syn::Error::new(
410 key.span(),
411 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` takes a path to a function in a string: `{0} = \"{1}\"`",
key, example))
})format!("`{key}` takes a path to a function in a string: `{key} = \"{example}\"`"),
412 ));
413 }
414 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
415 if !content.peek(syn::LitStr) {
416 return Err(content.error(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` takes a path to a function in a string: `{0} = \"{1}\"`",
key, example))
})format!(
417 "`{key}` takes a path to a function in a string: `{key} = \"{example}\"`"
418 )));
419 }
420 let value: syn::LitStr = content.parse()?;
421 if let Err(err) = value.parse::<syn::Path>() {
422 return Err(syn::Error::new_spanned(
423 &value,
424 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` must be a path to a function, e.g. `{1}`: {2}",
key, example, err))
})format!("`{key}` must be a path to a function, e.g. `{example}`: {err}"),
425 ));
426 }
427 Ok(value)
428}
429
430fn no_field_fallback_error(key: &syn::Ident, system: &str) -> syn::Error {
434 let why = match system {
435 "r6" => "an R6 object's `$` reads its environment, whose active bindings are fixed",
436 "s7" => "S7 properties are a fixed set, read with `@`",
437 _ => "a vctr is an R vector with no external pointer",
438 };
439 syn::Error::new(
440 key.span(),
441 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` applies to the `$` / `[[` readers of `s3(r_data_accessors)`, `s4(r_data_accessors)` and `env(r_data_accessors)`; {1}",
key, why))
})format!(
442 "`{key}` applies to the `$` / `[[` readers of `s3(r_data_accessors)`, \
443 `s4(r_data_accessors)` and `env(r_data_accessors)`; {why}"
444 ),
445 )
446}
447
448fn parse_r_data_accessors_value(
452 content: syn::parse::ParseStream,
453 key: &syn::Ident,
454 system: ClassSystem,
455) -> syn::Result<RDataAccessors> {
456 if !content.peek(::syn::token::Eqsyn::Token![=]) {
457 return Ok(RDataAccessors::GetSet);
458 }
459 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
460 let value: syn::LitStr = content.parse()?;
461 if !#[allow(non_exhaustive_omitted_patterns)] match system {
ClassSystem::S3 | ClassSystem::S4 | ClassSystem::Env => true,
_ => false,
}matches!(system, ClassSystem::S3 | ClassSystem::S4 | ClassSystem::Env) {
462 return Err(syn::Error::new(
463 key.span(),
464 "the getters-only form `r_data_accessors = \"get\"` applies to `s3`, `s4` and \
465 `env` classes; R6 active bindings and S7 properties take the bare \
466 `r_data_accessors`",
467 ));
468 }
469 if value.value() != "get" {
470 return Err(syn::Error::new(
471 value.span(),
472 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown `r_data_accessors` value \"{0}\"; expected `r_data_accessors` (getters and setters) or `r_data_accessors = \"get\"` (getters only)",
value.value()))
})format!(
473 "unknown `r_data_accessors` value \"{}\"; expected `r_data_accessors` (getters \
474 and setters) or `r_data_accessors = \"get\"` (getters only)",
475 value.value()
476 ),
477 ));
478 }
479 Ok(RDataAccessors::GetOnly)
480}
481
482#[derive(#[automatically_derived]
impl ::core::fmt::Debug for VctrsKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
VctrsKind::Vctr => "Vctr",
VctrsKind::Rcrd => "Rcrd",
VctrsKind::ListOf => "ListOf",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for VctrsKind { }
#[automatically_derived]
impl ::core::clone::Clone for VctrsKind {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for VctrsKind { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for VctrsKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for VctrsKind {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for VctrsKind { }Eq, #[automatically_derived]
impl ::core::default::Default for VctrsKind {
#[inline]
fn default() -> Self { Self::Vctr }
}Default)]
484pub enum VctrsKind {
485 #[default]
487 Vctr,
488 Rcrd,
490 ListOf,
492}
493
494impl std::str::FromStr for VctrsKind {
498 type Err = String;
499
500 fn from_str(s: &str) -> Result<Self, Self::Err> {
501 match s.to_lowercase().as_str() {
502 "vctr" => Ok(VctrsKind::Vctr),
503 "rcrd" | "record" => Ok(VctrsKind::Rcrd),
504 "list_of" | "listof" => Ok(VctrsKind::ListOf),
505 _ => Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown vctrs kind: {0} (expected vctr, rcrd, or list_of)",
s))
})format!(
506 "unknown vctrs kind: {} (expected vctr, rcrd, or list_of)",
507 s
508 )),
509 }
510 }
511}
512
513#[derive(#[automatically_derived]
impl ::core::fmt::Debug for VctrsAttrs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f, "VctrsAttrs",
"kind", &self.kind, "base", &self.base, "inherit_base_type",
&self.inherit_base_type, "ptype", &self.ptype, "abbr",
&&self.abbr)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for VctrsAttrs {
#[inline]
fn clone(&self) -> Self {
VctrsAttrs {
kind: ::core::clone::Clone::clone(&self.kind),
base: ::core::clone::Clone::clone(&self.base),
inherit_base_type: ::core::clone::Clone::clone(&self.inherit_base_type),
ptype: ::core::clone::Clone::clone(&self.ptype),
abbr: ::core::clone::Clone::clone(&self.abbr),
}
}
}Clone, #[automatically_derived]
impl ::core::default::Default for VctrsAttrs {
#[inline]
fn default() -> Self {
VctrsAttrs {
kind: ::core::default::Default::default(),
base: ::core::default::Default::default(),
inherit_base_type: ::core::default::Default::default(),
ptype: ::core::default::Default::default(),
abbr: ::core::default::Default::default(),
}
}
}Default)]
515pub struct VctrsAttrs {
516 pub kind: VctrsKind,
518 pub base: Option<String>,
520 pub inherit_base_type: Option<bool>,
522 pub ptype: Option<String>,
524 pub abbr: Option<String>,
526}
527
528#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ReceiverKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ReceiverKind::None => "None",
ReceiverKind::Ref => "Ref",
ReceiverKind::RefMut => "RefMut",
ReceiverKind::Value => "Value",
ReceiverKind::ExternalPtrRef => "ExternalPtrRef",
ReceiverKind::ExternalPtrMut => "ExternalPtrMut",
ReceiverKind::ExternalPtrValue => "ExternalPtrValue",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ReceiverKind { }
#[automatically_derived]
impl ::core::clone::Clone for ReceiverKind {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ReceiverKind { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ReceiverKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ReceiverKind {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ReceiverKind { }Eq)]
530pub enum ReceiverKind {
531 None,
533 Ref,
535 RefMut,
537 Value,
542 ExternalPtrRef,
544 ExternalPtrMut,
546 ExternalPtrValue,
548}
549
550impl ReceiverKind {
551 pub fn is_instance(&self) -> bool {
554 #[allow(non_exhaustive_omitted_patterns)] match self {
ReceiverKind::Ref | ReceiverKind::RefMut | ReceiverKind::Value |
ReceiverKind::ExternalPtrRef | ReceiverKind::ExternalPtrMut |
ReceiverKind::ExternalPtrValue => true,
_ => false,
}matches!(
555 self,
556 ReceiverKind::Ref
557 | ReceiverKind::RefMut
558 | ReceiverKind::Value
559 | ReceiverKind::ExternalPtrRef
560 | ReceiverKind::ExternalPtrMut
561 | ReceiverKind::ExternalPtrValue
562 )
563 }
564
565 pub fn is_mut(&self) -> bool {
567 #[allow(non_exhaustive_omitted_patterns)] match self {
ReceiverKind::RefMut | ReceiverKind::ExternalPtrMut => true,
_ => false,
}matches!(self, ReceiverKind::RefMut | ReceiverKind::ExternalPtrMut)
568 }
569}
570
571#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ParsedMethod {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["visibility_marker", "return_wrap", "ident", "env", "sig",
"param_markers", "vis", "doc_tags", "method_attrs",
"param_defaults", "has_dots", "rng_guard"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.visibility_marker, &self.return_wrap, &self.ident,
&self.env, &self.sig, &self.param_markers, &self.vis,
&self.doc_tags, &self.method_attrs, &self.param_defaults,
&self.has_dots, &&self.rng_guard];
::core::fmt::Formatter::debug_struct_fields_finish(f, "ParsedMethod",
names, values)
}
}Debug)]
583pub struct ParsedMethod {
584 pub visibility_marker: Option<bool>,
589 pub return_wrap: Option<crate::return_wrap::ReturnWrap>,
591 pub ident: syn::Ident,
593 pub env: ReceiverKind,
595 pub sig: syn::Signature,
601 pub param_markers: Vec<(String, Vec<crate::type_inspect::ParamMarker>)>,
605 pub vis: syn::Visibility,
608 pub doc_tags: Vec<String>,
610 pub method_attrs: MethodAttrs,
615 pub param_defaults: std::collections::HashMap<String, String>,
619 pub has_dots: bool,
622 pub rng_guard: Option<usize>,
626}
627
628#[derive(#[automatically_derived]
impl ::core::fmt::Debug for R6MethodAttrs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["active", "active_span", "setter", "prop", "private",
"private_span", "finalize", "finalize_span", "deep_clone",
"deep_clone_span"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.active, &self.active_span, &self.setter, &self.prop,
&self.private, &self.private_span, &self.finalize,
&self.finalize_span, &self.deep_clone,
&&self.deep_clone_span];
::core::fmt::Formatter::debug_struct_fields_finish(f, "R6MethodAttrs",
names, values)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for R6MethodAttrs {
#[inline]
fn default() -> Self {
R6MethodAttrs {
active: ::core::default::Default::default(),
active_span: ::core::default::Default::default(),
setter: ::core::default::Default::default(),
prop: ::core::default::Default::default(),
private: ::core::default::Default::default(),
private_span: ::core::default::Default::default(),
finalize: ::core::default::Default::default(),
finalize_span: ::core::default::Default::default(),
deep_clone: ::core::default::Default::default(),
deep_clone_span: ::core::default::Default::default(),
}
}
}Default)]
635pub struct R6MethodAttrs {
636 pub active: bool,
638 pub active_span: Option<proc_macro2::Span>,
641 pub setter: bool,
643 pub prop: Option<String>,
645 pub private: bool,
648 pub private_span: Option<proc_macro2::Span>,
651 pub finalize: bool,
654 pub finalize_span: Option<proc_macro2::Span>,
656 pub deep_clone: bool,
659 pub deep_clone_span: Option<proc_macro2::Span>,
661}
662
663#[derive(#[automatically_derived]
impl ::core::fmt::Debug for S7MethodAttrs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["getter", "setter", "prop", "default", "validate", "required",
"frozen", "deprecated", "no_dots", "dispatch", "fallback",
"convert_from", "convert_to", "no_shortcut"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.getter, &self.setter, &self.prop, &self.default,
&self.validate, &self.required, &self.frozen,
&self.deprecated, &self.no_dots, &self.dispatch,
&self.fallback, &self.convert_from, &self.convert_to,
&&self.no_shortcut];
::core::fmt::Formatter::debug_struct_fields_finish(f, "S7MethodAttrs",
names, values)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for S7MethodAttrs {
#[inline]
fn default() -> Self {
S7MethodAttrs {
getter: ::core::default::Default::default(),
setter: ::core::default::Default::default(),
prop: ::core::default::Default::default(),
default: ::core::default::Default::default(),
validate: ::core::default::Default::default(),
required: ::core::default::Default::default(),
frozen: ::core::default::Default::default(),
deprecated: ::core::default::Default::default(),
no_dots: ::core::default::Default::default(),
dispatch: ::core::default::Default::default(),
fallback: ::core::default::Default::default(),
convert_from: ::core::default::Default::default(),
convert_to: ::core::default::Default::default(),
no_shortcut: ::core::default::Default::default(),
}
}
}Default)]
686pub struct S7MethodAttrs {
687 pub getter: bool,
688 pub setter: bool,
689 pub prop: Option<String>,
690 pub default: Option<String>,
691 pub validate: bool,
692 pub required: bool,
693 pub frozen: bool,
694 pub deprecated: Option<String>,
695 pub no_dots: bool,
696 pub dispatch: Option<String>,
697 pub fallback: bool,
698 pub convert_from: Option<String>,
699 pub convert_to: Option<String>,
700 pub no_shortcut: bool,
704}
705
706#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MethodAttrs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["ignore", "constructor", "force_invisible", "r6", "as_coercion",
"as_coercion_span", "generic", "receiver",
"no_dispatch_dots", "class", "worker", "unsafe_main_thread",
"check_interrupt", "coerce", "preconditions", "rng",
"dots_spec", "dots_policy", "unwrap_in_r", "serde_error",
"serialize", "wrap", "defaults", "defaults_span",
"per_param", "match_arg_span", "s7", "lifecycle",
"vctrs_protocol", "r_name", "postfix", "r_entry",
"r_post_checks", "r_on_exit", "internal", "noexport"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.ignore, &self.constructor, &self.force_invisible,
&self.r6, &self.as_coercion, &self.as_coercion_span,
&self.generic, &self.receiver, &self.no_dispatch_dots,
&self.class, &self.worker, &self.unsafe_main_thread,
&self.check_interrupt, &self.coerce, &self.preconditions,
&self.rng, &self.dots_spec, &self.dots_policy,
&self.unwrap_in_r, &self.serde_error, &self.serialize,
&self.wrap, &self.defaults, &self.defaults_span,
&self.per_param, &self.match_arg_span, &self.s7,
&self.lifecycle, &self.vctrs_protocol, &self.r_name,
&self.postfix, &self.r_entry, &self.r_post_checks,
&self.r_on_exit, &self.internal, &&self.noexport];
::core::fmt::Formatter::debug_struct_fields_finish(f, "MethodAttrs",
names, values)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for MethodAttrs {
#[inline]
fn default() -> Self {
MethodAttrs {
ignore: ::core::default::Default::default(),
constructor: ::core::default::Default::default(),
force_invisible: ::core::default::Default::default(),
r6: ::core::default::Default::default(),
as_coercion: ::core::default::Default::default(),
as_coercion_span: ::core::default::Default::default(),
generic: ::core::default::Default::default(),
receiver: ::core::default::Default::default(),
no_dispatch_dots: ::core::default::Default::default(),
class: ::core::default::Default::default(),
worker: ::core::default::Default::default(),
unsafe_main_thread: ::core::default::Default::default(),
check_interrupt: ::core::default::Default::default(),
coerce: ::core::default::Default::default(),
preconditions: ::core::default::Default::default(),
rng: ::core::default::Default::default(),
dots_spec: ::core::default::Default::default(),
dots_policy: ::core::default::Default::default(),
unwrap_in_r: ::core::default::Default::default(),
serde_error: ::core::default::Default::default(),
serialize: ::core::default::Default::default(),
wrap: ::core::default::Default::default(),
defaults: ::core::default::Default::default(),
defaults_span: ::core::default::Default::default(),
per_param: ::core::default::Default::default(),
match_arg_span: ::core::default::Default::default(),
s7: ::core::default::Default::default(),
lifecycle: ::core::default::Default::default(),
vctrs_protocol: ::core::default::Default::default(),
r_name: ::core::default::Default::default(),
postfix: ::core::default::Default::default(),
r_entry: ::core::default::Default::default(),
r_post_checks: ::core::default::Default::default(),
r_on_exit: ::core::default::Default::default(),
internal: ::core::default::Default::default(),
noexport: ::core::default::Default::default(),
}
}
}Default)]
708pub struct MethodAttrs {
709 pub ignore: bool,
711 pub constructor: bool,
713 pub force_invisible: Option<bool>,
718 pub r6: R6MethodAttrs,
722 pub as_coercion: Option<String>,
735 pub as_coercion_span: Option<proc_macro2::Span>,
737 pub generic: Option<String>,
757 pub receiver: Option<String>,
759 pub no_dispatch_dots: bool,
761 pub class: Option<String>,
775 pub worker: bool,
777 pub unsafe_main_thread: bool,
779 pub check_interrupt: bool,
781 pub coerce: bool,
783 pub preconditions: Option<bool>,
791 pub rng: bool,
793 pub dots_spec: Option<proc_macro2::TokenStream>,
798 pub dots_policy: Option<crate::dots_policy::DotsPolicy>,
803 pub unwrap_in_r: bool,
805 pub serde_error: Option<crate::miniextendr_fn::SerdeErrorSpec>,
808 pub serialize: bool,
810 pub wrap: Option<ClassSystem>,
812 pub defaults: std::collections::HashMap<String, String>,
814 pub defaults_span: Option<proc_macro2::Span>,
816 pub per_param: std::collections::HashMap<String, crate::miniextendr_fn::ParamAttrs>,
831 pub match_arg_span: Option<proc_macro2::Span>,
833 pub s7: S7MethodAttrs,
836 pub lifecycle: Option<crate::lifecycle::LifecycleSpec>,
852 pub vctrs_protocol: Option<String>,
861 pub r_name: Option<String>,
867 pub postfix: Option<String>,
871 pub r_entry: Option<String>,
873 pub r_post_checks: Option<String>,
875 pub r_on_exit: Option<crate::miniextendr_fn::ROnExit>,
880 pub internal: bool,
887 pub noexport: bool,
893}
894
895#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ParsedImpl {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["type_ident", "class_system", "class_name", "doc_tags",
"methods", "original_impl", "cfg_attrs", "vctrs_attrs",
"r6_inherit", "r6_portable", "r6_cloneable",
"r6_lock_objects", "r6_lock_class", "s7_parent",
"s7_abstract", "r_data_accessors", "field_lookup",
"field_fallback", "strict", "preconditions", "internal",
"noexport", "constructor_demoted", "param_warnings",
"class_param_names"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.type_ident, &self.class_system, &self.class_name,
&self.doc_tags, &self.methods, &self.original_impl,
&self.cfg_attrs, &self.vctrs_attrs, &self.r6_inherit,
&self.r6_portable, &self.r6_cloneable,
&self.r6_lock_objects, &self.r6_lock_class, &self.s7_parent,
&self.s7_abstract, &self.r_data_accessors,
&self.field_lookup, &self.field_fallback, &self.strict,
&self.preconditions, &self.internal, &self.noexport,
&self.constructor_demoted, &self.param_warnings,
&&self.class_param_names];
::core::fmt::Formatter::debug_struct_fields_finish(f, "ParsedImpl",
names, values)
}
}Debug)]
902pub struct ParsedImpl {
903 pub type_ident: syn::Ident,
905 pub class_system: ClassSystem,
907 pub class_name: Option<String>,
909 pub doc_tags: Vec<String>,
912 pub methods: Vec<ParsedMethod>,
914 pub original_impl: syn::ItemImpl,
917 pub cfg_attrs: Vec<syn::Attribute>,
920 pub vctrs_attrs: VctrsAttrs,
922 pub r6_inherit: Option<String>,
925 pub r6_portable: Option<bool>,
928 pub r6_cloneable: Option<bool>,
931 pub r6_lock_objects: Option<bool>,
934 pub r6_lock_class: Option<bool>,
937 pub s7_parent: Option<String>,
940 pub s7_abstract: bool,
943 pub r_data_accessors: RDataAccessors,
949 pub field_lookup: FieldLookup,
952 pub field_fallback: Option<FieldFallback>,
956 pub strict: bool,
958 pub preconditions: Option<bool>,
961 pub internal: bool,
963 pub noexport: bool,
965 pub constructor_demoted: bool,
970 pub param_warnings: proc_macro2::TokenStream,
973 pub class_param_names: std::collections::HashSet<String>,
981}
982
983#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ImplAttrs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["class_system", "class_name", "vctrs_attrs", "r6_inherit",
"r6_portable", "r6_cloneable", "r6_lock_objects",
"r6_lock_class", "s7_parent", "s7_abstract",
"r_data_accessors", "field_lookup", "field_fallback",
"strict", "preconditions", "internal", "noexport",
"blanket"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.class_system, &self.class_name, &self.vctrs_attrs,
&self.r6_inherit, &self.r6_portable, &self.r6_cloneable,
&self.r6_lock_objects, &self.r6_lock_class, &self.s7_parent,
&self.s7_abstract, &self.r_data_accessors,
&self.field_lookup, &self.field_fallback, &self.strict,
&self.preconditions, &self.internal, &self.noexport,
&&self.blanket];
::core::fmt::Formatter::debug_struct_fields_finish(f, "ImplAttrs",
names, values)
}
}Debug)]
991pub struct ImplAttrs {
992 pub class_system: ClassSystem,
995 pub class_name: Option<String>,
997 pub vctrs_attrs: VctrsAttrs,
999 pub r6_inherit: Option<String>,
1004 pub r6_portable: Option<bool>,
1006 pub r6_cloneable: Option<bool>,
1008 pub r6_lock_objects: Option<bool>,
1010 pub r6_lock_class: Option<bool>,
1012 pub s7_parent: Option<String>,
1017 pub s7_abstract: bool,
1019 pub r_data_accessors: RDataAccessors,
1027 pub field_lookup: FieldLookup,
1029 pub field_fallback: Option<FieldFallback>,
1032 pub strict: bool,
1037 pub preconditions: Option<bool>,
1051 pub internal: bool,
1054 pub noexport: bool,
1056 pub blanket: bool,
1060}
1061
1062const CLASS_SETTING_TAGS: [&str; 2] = ["noRd", "keywords internal"];
1066
1067const IMPL_OPTIONS_HELP: &str = "env, env(...), r6, r6(...), s3, s3(...), s4, s4(...), s7, \
1070 s7(...), vctrs, vctrs(...) (class system), class = \"...\" (R class name), \
1071 blanket, strict, no_strict, preconditions, no_preconditions, internal, noexport";
1072
1073impl syn::parse::Parse for ImplAttrs {
1074 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
1076 let mut class_system = if falsecfg!(feature = "r6-default") {
1077 ClassSystem::R6
1078 } else if falsecfg!(feature = "s7-default") {
1079 ClassSystem::S7
1080 } else {
1081 ClassSystem::Env
1082 };
1083 let mut class_system_span: Option<(&str, proc_macro2::Span)> = None;
1084 let mut class_name = None;
1085 let mut vctrs_attrs = VctrsAttrs::default();
1086 let mut r6_inherit = None;
1087 let mut r6_portable = None;
1088 let mut r6_cloneable = None;
1089 let mut r6_lock_objects = None;
1090 let mut r6_lock_class = None;
1091 let mut s7_parent = None;
1092 let mut s7_abstract = false;
1093 let mut r_data_accessors = RDataAccessors::Off;
1094 let mut field_lookup: Option<(FieldLookup, proc_macro2::Span)> = None;
1095 let mut fallback: Option<(syn::LitStr, proc_macro2::Span)> = None;
1096 let mut fallback_names: Option<(syn::LitStr, proc_macro2::Span)> = None;
1097 let mut strict: Option<bool> = None;
1098 let mut preconditions: Option<bool> = None;
1099 let mut internal = false;
1100 let mut noexport = false;
1101 let mut blanket = false;
1102
1103 while !input.is_empty() {
1114 let ident: syn::Ident = input.parse()?;
1115 let ident_str = ident.to_string();
1116
1117 if input.peek(::syn::token::Eqsyn::Token![=]) {
1119 let _: ::syn::token::Eqsyn::Token![=] = input.parse()?;
1120 match ident_str.as_str() {
1121 "class" => {
1122 let value: syn::LitStr = input.parse()?;
1123 class_name = Some(value.value());
1124 }
1125 _ => {
1126 return Err(syn::Error::new(
1127 ident.span(),
1128 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown impl block option `{0}`; expected one of: {1}",
ident_str, IMPL_OPTIONS_HELP))
})format!(
1129 "unknown impl block option `{ident_str}`; expected one of: \
1130 {IMPL_OPTIONS_HELP}"
1131 ),
1132 ));
1133 }
1134 }
1135 } else if ident_str == "vctrs" {
1136 if let Some((prev_name, _prev_span)) = class_system_span {
1138 return Err(syn::Error::new(
1139 ident.span(),
1140 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple class systems specified (`{0}` and `{1}`); use only one of: env, r6, s3, s4, s7, vctrs",
prev_name, ident_str))
})format!(
1141 "multiple class systems specified (`{}` and `{}`); use only one of: env, r6, s3, s4, s7, vctrs",
1142 prev_name, ident_str
1143 ),
1144 ));
1145 }
1146 class_system_span = Some(("vctrs", ident.span()));
1147 class_system = ClassSystem::Vctrs;
1148
1149 if input.peek(syn::token::Paren) {
1151 let content;
1152 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::parenthesized!(content in input);
1153
1154 while !content.is_empty() {
1155 let key: syn::Ident = content.parse()?;
1156 if key == "r_data_accessors" {
1157 return Err(syn::Error::new(
1158 key.span(),
1159 "vctrs classes have no `r_data_accessors`: a vctr is an R \
1160 vector with no external pointer, and vctrs keeps `$` on a \
1161 record for its own fields. Use the standalone \
1162 `Type_get_<field>()` / `Type_set_<field>()`",
1163 ));
1164 }
1165 if key == "fallback" || key == "fallback_names" {
1166 return Err(no_field_fallback_error(&key, "vctrs"));
1167 }
1168 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1169 let key_str = key.to_string();
1170
1171 match key_str.as_str() {
1172 "kind" => {
1173 let value: syn::LitStr = content.parse()?;
1174 vctrs_attrs.kind = value
1175 .value()
1176 .parse()
1177 .map_err(|e| syn::Error::new(value.span(), e))?;
1178 }
1179 "base" => {
1180 let value: syn::LitStr = content.parse()?;
1181 vctrs_attrs.base = Some(value.value());
1182 }
1183 "inherit_base_type" => {
1184 let value: syn::LitBool = content.parse()?;
1185 vctrs_attrs.inherit_base_type = Some(value.value());
1186 }
1187 "ptype" => {
1188 let value: syn::LitStr = content.parse()?;
1189 vctrs_attrs.ptype = Some(value.value());
1190 }
1191 "abbr" => {
1192 let value: syn::LitStr = content.parse()?;
1193 vctrs_attrs.abbr = Some(value.value());
1194 }
1195 _ => {
1196 return Err(syn::Error::new(
1197 key.span(),
1198 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown vctrs option: {0} (expected kind, base, inherit_base_type, ptype, abbr)",
key_str))
})format!(
1199 "unknown vctrs option: {} (expected kind, base, inherit_base_type, ptype, abbr)",
1200 key_str
1201 ),
1202 ));
1203 }
1204 }
1205
1206 if content.peek(::syn::token::Commasyn::Token![,]) {
1208 let _: ::syn::token::Commasyn::Token![,] = content.parse()?;
1209 }
1210 }
1211 }
1212 } else if ident_str == "r6" {
1213 if let Some((prev_name, _prev_span)) = class_system_span {
1216 return Err(syn::Error::new(
1217 ident.span(),
1218 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple class systems specified (`{0}` and `{1}`); use only one of: env, r6, s3, s4, s7, vctrs",
prev_name, ident_str))
})format!(
1219 "multiple class systems specified (`{}` and `{}`); use only one of: env, r6, s3, s4, s7, vctrs",
1220 prev_name, ident_str
1221 ),
1222 ));
1223 }
1224 class_system_span = Some(("r6", ident.span()));
1225 class_system = ClassSystem::R6;
1226
1227 if input.peek(syn::token::Paren) {
1228 let content;
1229 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::parenthesized!(content in input);
1230
1231 while !content.is_empty() {
1232 let key: syn::Ident = content.parse()?;
1233 let key_str = key.to_string();
1234
1235 match key_str.as_str() {
1236 "inherit" => {
1237 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1238 let value: syn::LitStr = content.parse()?;
1239 r6_inherit = Some(value.value());
1240 }
1241 "portable" => {
1242 if content.peek(::syn::token::Eqsyn::Token![=]) {
1243 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1244 let value: syn::LitBool = content.parse()?;
1245 r6_portable = Some(value.value());
1246 } else {
1247 r6_portable = Some(true);
1248 }
1249 }
1250 "cloneable" => {
1251 if content.peek(::syn::token::Eqsyn::Token![=]) {
1252 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1253 let value: syn::LitBool = content.parse()?;
1254 r6_cloneable = Some(value.value());
1255 } else {
1256 r6_cloneable = Some(true);
1257 }
1258 }
1259 "lock_objects" => {
1260 if content.peek(::syn::token::Eqsyn::Token![=]) {
1261 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1262 let value: syn::LitBool = content.parse()?;
1263 r6_lock_objects = Some(value.value());
1264 } else {
1265 r6_lock_objects = Some(true);
1266 }
1267 }
1268 "lock_class" => {
1269 if content.peek(::syn::token::Eqsyn::Token![=]) {
1270 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1271 let value: syn::LitBool = content.parse()?;
1272 r6_lock_class = Some(value.value());
1273 } else {
1274 r6_lock_class = Some(true);
1275 }
1276 }
1277 "r_data_accessors" => {
1278 r_data_accessors =
1279 parse_r_data_accessors_value(&content, &key, ClassSystem::R6)?;
1280 }
1281 "fallback" | "fallback_names" => {
1282 return Err(no_field_fallback_error(&key, "r6"));
1283 }
1284 _ => {
1285 return Err(syn::Error::new(
1286 key.span(),
1287 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown r6 option: {0} (expected inherit, portable, cloneable, lock_objects, lock_class, r_data_accessors)",
key_str))
})format!(
1288 "unknown r6 option: {} (expected inherit, portable, cloneable, lock_objects, lock_class, r_data_accessors)",
1289 key_str
1290 ),
1291 ));
1292 }
1293 }
1294
1295 if content.peek(::syn::token::Commasyn::Token![,]) {
1297 let _: ::syn::token::Commasyn::Token![,] = content.parse()?;
1298 }
1299 }
1300 }
1301 } else if ident_str == "s7" {
1302 if let Some((prev_name, _prev_span)) = class_system_span {
1305 return Err(syn::Error::new(
1306 ident.span(),
1307 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple class systems specified (`{0}` and `{1}`); use only one of: env, r6, s3, s4, s7, vctrs",
prev_name, ident_str))
})format!(
1308 "multiple class systems specified (`{}` and `{}`); use only one of: env, r6, s3, s4, s7, vctrs",
1309 prev_name, ident_str
1310 ),
1311 ));
1312 }
1313 class_system_span = Some(("s7", ident.span()));
1314 class_system = ClassSystem::S7;
1315
1316 if input.peek(syn::token::Paren) {
1317 let content;
1318 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::parenthesized!(content in input);
1319
1320 while !content.is_empty() {
1321 use syn::ext::IdentExt;
1323 let key = syn::Ident::parse_any(&content)?;
1324 let key_str = key.to_string();
1325
1326 match key_str.as_str() {
1327 "parent" => {
1328 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1329 let value: syn::LitStr = content.parse()?;
1330 s7_parent = Some(value.value());
1331 }
1332 "abstract" => {
1333 if content.peek(::syn::token::Eqsyn::Token![=]) {
1334 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1335 let value: syn::LitBool = content.parse()?;
1336 s7_abstract = value.value();
1337 } else {
1338 s7_abstract = true;
1339 }
1340 }
1341 "r_data_accessors" => {
1342 r_data_accessors =
1343 parse_r_data_accessors_value(&content, &key, ClassSystem::S7)?;
1344 }
1345 "fallback" | "fallback_names" => {
1346 return Err(no_field_fallback_error(&key, "s7"));
1347 }
1348 _ => {
1349 return Err(syn::Error::new(
1350 key.span(),
1351 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown s7 option: {0} (expected parent, abstract, r_data_accessors)",
key_str))
})format!(
1352 "unknown s7 option: {} (expected parent, abstract, r_data_accessors)",
1353 key_str
1354 ),
1355 ));
1356 }
1357 }
1358
1359 if content.peek(::syn::token::Commasyn::Token![,]) {
1361 let _: ::syn::token::Commasyn::Token![,] = content.parse()?;
1362 }
1363 }
1364 }
1365 } else if ident_str == "blanket" {
1366 blanket = true;
1367 } else if ident_str == "strict" {
1368 strict = Some(true);
1369 } else if ident_str == "no_strict" {
1370 strict = Some(false);
1371 } else if ident_str == "preconditions" {
1372 preconditions = Some(true);
1373 } else if ident_str == "no_preconditions" {
1374 preconditions = Some(false);
1375 } else if ident_str == "internal" {
1376 internal = true;
1377 } else if ident_str == "noexport" {
1378 noexport = true;
1379 } else {
1380 let parsed_system: ClassSystem = ident_str.parse().map_err(|_| {
1382 syn::Error::new(
1383 ident.span(),
1384 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown impl block option `{0}`; expected one of: {1}",
ident_str, IMPL_OPTIONS_HELP))
})format!(
1385 "unknown impl block option `{ident_str}`; expected one of: \
1386 {IMPL_OPTIONS_HELP}"
1387 ),
1388 )
1389 })?;
1390 if let Some((prev_name, _prev_span)) = class_system_span {
1391 return Err(syn::Error::new(
1392 ident.span(),
1393 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple class systems specified (`{0}` and `{1}`); use only one of: env, r6, s3, s4, s7, vctrs",
prev_name, ident_str))
})format!(
1394 "multiple class systems specified (`{}` and `{}`); use only one of: env, r6, s3, s4, s7, vctrs",
1395 prev_name, ident_str
1396 ),
1397 ));
1398 }
1399 class_system_span = Some((
1400 match parsed_system {
1401 ClassSystem::Env => "env",
1402 ClassSystem::R6 => "r6",
1403 ClassSystem::S3 => "s3",
1404 ClassSystem::S4 => "s4",
1405 ClassSystem::S7 => "s7",
1406 ClassSystem::Vctrs => "vctrs",
1407 },
1408 ident.span(),
1409 ));
1410 class_system = parsed_system;
1411
1412 if input.peek(syn::token::Paren) {
1414 let content;
1415 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};syn::parenthesized!(content in input);
1416 while !content.is_empty() {
1417 let key: syn::Ident = content.parse()?;
1418 if key == "lookup" && parsed_system == ClassSystem::S3 {
1419 if field_lookup.is_some() {
1420 return Err(syn::Error::new(key.span(), "`lookup` is given twice"));
1421 }
1422 let _: ::syn::token::Eqsyn::Token![=] = content.parse()?;
1423 let value: syn::LitStr = content.parse()?;
1424 let lookup = match value.value().as_str() {
1425 "strict" => FieldLookup::Strict,
1426 "list" => FieldLookup::List,
1427 other => {
1428 return Err(syn::Error::new(
1429 value.span(),
1430 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown `lookup` value \"{0}\"; expected \"strict\" (exact names and whole-number positions, the default) or \"list\" (an unknown name or `NA` reads `NULL`)",
other))
})format!(
1431 "unknown `lookup` value \"{other}\"; expected \
1432 \"strict\" (exact names and whole-number \
1433 positions, the default) or \"list\" (an unknown \
1434 name or `NA` reads `NULL`)"
1435 ),
1436 ));
1437 }
1438 };
1439 field_lookup = Some((lookup, key.span()));
1440 } else if key == "r_data_accessors" {
1441 r_data_accessors =
1442 parse_r_data_accessors_value(&content, &key, parsed_system)?;
1443 } else if key == "fallback" || key == "fallback_names" {
1444 let slot = if key == "fallback" {
1445 &mut fallback
1446 } else {
1447 &mut fallback_names
1448 };
1449 if slot.is_some() {
1450 return Err(syn::Error::new(
1451 key.span(),
1452 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is given twice", key))
})format!("`{key}` is given twice"),
1453 ));
1454 }
1455 *slot = Some((parse_fallback_value(&content, &key)?, key.span()));
1456 } else {
1457 let lookup = if parsed_system == ClassSystem::S3 {
1458 ", lookup = \"list\""
1459 } else {
1460 ""
1461 };
1462 return Err(syn::Error::new(
1463 key.span(),
1464 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown {0} option: {1} (expected r_data_accessors, or r_data_accessors = \"get\" for getters only{2}, fallback = \"Self::f\", fallback_names = \"Self::g\")",
ident_str, key, lookup))
})format!(
1465 "unknown {ident_str} option: {key} (expected \
1466 r_data_accessors, or r_data_accessors = \"get\" for \
1467 getters only{lookup}, fallback = \"Self::f\", \
1468 fallback_names = \"Self::g\")"
1469 ),
1470 ));
1471 }
1472 if content.peek(::syn::token::Commasyn::Token![,]) {
1473 let _: ::syn::token::Commasyn::Token![,] = content.parse()?;
1474 }
1475 }
1476 if let Some((_, span)) = field_lookup
1477 && !r_data_accessors.enabled()
1478 {
1479 return Err(syn::Error::new(
1480 span,
1481 "`lookup` sets how the readers of `s3(r_data_accessors)` look a \
1482 field up; add `r_data_accessors` (or `r_data_accessors = \"get\"`)",
1483 ));
1484 }
1485 if let Some((_, span)) = &fallback
1486 && !r_data_accessors.enabled()
1487 {
1488 return Err(syn::Error::new(
1489 *span,
1490 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`fallback` answers the names no field has for the `$` / `[[` readers of `{0}(r_data_accessors)`; add `r_data_accessors` (or `r_data_accessors = \"get\"`)",
ident_str))
})format!(
1491 "`fallback` answers the names no field has for the `$` / `[[` \
1492 readers of `{ident_str}(r_data_accessors)`; add \
1493 `r_data_accessors` (or `r_data_accessors = \"get\"`)"
1494 ),
1495 ));
1496 }
1497 if let Some((_, span)) = &fallback_names
1498 && fallback.is_none()
1499 {
1500 return Err(syn::Error::new(
1501 *span,
1502 "`fallback_names` lists the names `fallback` answers, for \
1503 `.DollarNames()`; add `fallback = \"Self::f\"`",
1504 ));
1505 }
1506 }
1507 }
1508
1509 if input.peek(::syn::token::Commasyn::Token![,]) {
1511 let _: ::syn::token::Commasyn::Token![,] = input.parse()?;
1512 }
1513 }
1514
1515 Ok(ImplAttrs {
1516 class_system,
1517 class_name,
1518 vctrs_attrs,
1519 r6_inherit,
1520 r6_portable,
1521 r6_cloneable,
1522 r6_lock_objects,
1523 r6_lock_class,
1524 s7_parent,
1525 s7_abstract,
1526 r_data_accessors,
1527 field_lookup: field_lookup.map(|(lookup, _)| lookup).unwrap_or_default(),
1528 field_fallback: fallback.map(|(get, _)| FieldFallback {
1529 get,
1530 names: fallback_names.map(|(names, _)| names),
1531 }),
1532 strict: strict.unwrap_or(falsecfg!(feature = "strict-default")),
1533 preconditions,
1534 internal,
1535 noexport,
1536 blanket,
1537 })
1538 }
1539}
1540
1541impl ParsedMethod {
1542 fn validate_method_attrs(
1545 attrs: &MethodAttrs,
1546 class_system: ClassSystem,
1547 span: proc_macro2::Span,
1548 ) -> syn::Result<()> {
1549 if (attrs.receiver.is_some() || attrs.no_dispatch_dots)
1550 && (!#[allow(non_exhaustive_omitted_patterns)] match class_system {
ClassSystem::S3 | ClassSystem::S4 => true,
_ => false,
}matches!(class_system, ClassSystem::S3 | ClassSystem::S4)
1551 || attrs.generic.is_none())
1552 {
1553 return Err(syn::Error::new(
1554 span,
1555 "`receiver` and `no_dots` require an explicit S3/S4 `generic = \"...\"`",
1556 ));
1557 }
1558
1559 if class_system != ClassSystem::R6 {
1561 if attrs.r6.active {
1562 return Err(syn::Error::new(
1563 attrs.r6.active_span.unwrap_or(span),
1564 "`active` is only valid for R6 class systems",
1565 ));
1566 }
1567 if attrs.r6.private {
1568 return Err(syn::Error::new(
1569 attrs.r6.private_span.unwrap_or(span),
1570 "`private` is only valid for R6 class systems",
1571 ));
1572 }
1573 if attrs.r6.finalize {
1574 return Err(syn::Error::new(
1575 attrs.r6.finalize_span.unwrap_or(span),
1576 "`finalize` is only valid for R6 class systems",
1577 ));
1578 }
1579 if attrs.r6.deep_clone {
1580 return Err(syn::Error::new(
1581 attrs.r6.deep_clone_span.unwrap_or(span),
1582 "`deep_clone` is only valid for R6 class systems",
1583 ));
1584 }
1585 }
1586
1587 if attrs.s7.convert_from.is_some() && attrs.s7.convert_to.is_some() {
1591 return Err(syn::Error::new(
1592 span,
1593 "cannot specify both `convert_from` and `convert_to` on the same method; \
1594 convert_from is for static methods, convert_to is for instance methods",
1595 ));
1596 }
1597
1598 if attrs.postfix.is_some() && attrs.r_name.is_some() {
1601 return Err(syn::Error::new(
1602 span,
1603 "`postfix` and `r_name` both set the R method name; use one of them.",
1604 ));
1605 }
1606 if attrs.postfix.is_some() && attrs.generic.is_some() {
1607 return Err(syn::Error::new(
1608 span,
1609 "`postfix` and `generic` cannot be used on the same method. \
1610 Generic dispatch names the R method after the generic.",
1611 ));
1612 }
1613
1614 if attrs.serialize && (attrs.unwrap_in_r || attrs.serde_error.is_some()) {
1615 return Err(syn::Error::new(
1616 proc_macro2::Span::call_site(),
1617 "`serialize` cannot be combined with `unwrap_in_r` or `serde_error`: it serializes the complete return value, including any Result variant",
1618 ));
1619 }
1620
1621 if attrs.serde_error.is_some() && attrs.unwrap_in_r {
1623 return Err(syn::Error::new(
1624 span,
1625 "`serde_error` cannot be used with `unwrap_in_r`: `unwrap_in_r` returns the \
1626 `Result` to R as a value, so there is no raised condition to class.",
1627 ));
1628 }
1629
1630 if attrs.r_name.is_some() && attrs.generic.is_some() {
1632 return Err(syn::Error::new(
1633 span,
1634 "`r_name` and `generic` cannot be used on the same method. \
1635 Use `r_name` for a simple rename, or `generic`/`class` for S3/S4/S7 generic dispatch.",
1636 ));
1637 }
1638
1639 Ok(())
1643 }
1644
1645 fn parse_method_attrs(attrs: &[syn::Attribute]) -> syn::Result<MethodAttrs> {
1653 use syn::spanned::Spanned;
1654 let mut method_attrs = MethodAttrs::default();
1655 let mut worker: Option<bool> = None;
1657 let mut unsafe_main_thread: Option<bool> = None;
1658 let mut coerce: Option<bool> = None;
1659
1660 for attr in attrs {
1661 if !attr.path().is_ident("miniextendr") {
1663 continue;
1664 }
1665
1666 attr.parse_nested_meta(|meta| {
1668 let is_class_meta = meta.path.is_ident("env")
1670 || meta.path.is_ident("r6")
1671 || meta.path.is_ident("s7")
1672 || meta.path.is_ident("s3")
1673 || meta.path.is_ident("s4");
1674
1675 if is_class_meta {
1676 meta.parse_nested_meta(|inner| {
1678 if inner.path.is_ident("ignore") {
1679 method_attrs.ignore = true;
1680 } else if inner.path.is_ident("invisible") {
1681 method_attrs.force_invisible = Some(true);
1682 } else if inner.path.is_ident("visible") {
1683 method_attrs.force_invisible = Some(false);
1684 } else if inner.path.is_ident("constructor") {
1685 method_attrs.constructor = true;
1686 } else if inner.path.is_ident("finalize") {
1687 method_attrs.r6.finalize = true;
1688 method_attrs.r6.finalize_span = Some(inner.path.span());
1689 } else if inner.path.is_ident("private") {
1690 method_attrs.r6.private = true;
1691 method_attrs.r6.private_span = Some(inner.path.span());
1692 } else if inner.path.is_ident("active") {
1693 method_attrs.r6.active = true;
1694 method_attrs.r6.active_span = Some(inner.path.span());
1695 } else if inner.path.is_ident("setter") {
1696 method_attrs.r6.setter = true;
1698 method_attrs.s7.setter = true;
1699 } else if inner.path.is_ident("worker") {
1700 worker = Some(true);
1701 crate::deprecation::worker_option(inner.path.span());
1702 } else if inner.path.is_ident("no_worker") {
1703 worker = Some(false);
1704 } else if inner.path.is_ident("main_thread") {
1705 unsafe_main_thread = Some(true);
1706 } else if inner.path.is_ident("no_main_thread") {
1707 unsafe_main_thread = Some(false);
1708 } else if inner.path.is_ident("check_interrupt") {
1709 method_attrs.check_interrupt = true;
1710 } else if inner.path.is_ident("coerce") {
1711 coerce = Some(true);
1712 } else if inner.path.is_ident("no_coerce") {
1713 coerce = Some(false);
1714 } else if inner.path.is_ident("rng") {
1715 if inner.input.peek(syn::token::Paren) {
1716 return crate::miniextendr_fn::refuse_rng_seed_on_method(
1717 &inner,
1718 "an impl method",
1719 );
1720 }
1721 method_attrs.rng = true;
1722 } else if inner.path.is_ident("unwrap_in_r") {
1723 method_attrs.unwrap_in_r = true;
1724 } else if inner.path.is_ident("wrap") {
1725 let value: syn::LitStr = inner.value()?.parse()?;
1726 method_attrs.wrap = Some(crate::return_wrap::parse_system(&value)?);
1727 } else if inner.path.is_ident("serialize") {
1728 method_attrs.serialize = true;
1729 } else if inner.path.is_ident("serde_error") {
1730 method_attrs.serde_error =
1731 Some(crate::miniextendr_fn::parse_serde_error_nested(&inner)?);
1732 } else if inner.path.is_ident("generic") {
1733 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1734 let value: syn::LitStr = inner.input.parse()?;
1735 method_attrs.generic = Some(crate::naming::parse_generic(&value)?);
1736 } else if inner.path.is_ident("receiver") {
1737 let value: syn::LitStr = inner.value()?.parse()?;
1738 let name = crate::naming::parse_r_receiver(&value)?;
1739 if method_attrs.receiver.replace(name).is_some() {
1740 return Err(inner.error("receiver may be specified only once"));
1741 }
1742 } else if inner.path.is_ident("class") {
1743 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1744 let value: syn::LitStr = inner.input.parse()?;
1745 method_attrs.class = Some(value.value());
1746 } else if inner.path.is_ident("getter") {
1747 method_attrs.s7.getter = true;
1748 } else if inner.path.is_ident("validate") {
1749 method_attrs.s7.validate = true;
1750 } else if inner.path.is_ident("prop") {
1751 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1752 let value: syn::LitStr = inner.input.parse()?;
1753 let prop_value = value.value();
1754 method_attrs.s7.prop = Some(prop_value.clone());
1756 method_attrs.r6.prop = Some(prop_value);
1757 } else if inner.path.is_ident("default") {
1758 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1759 let value: syn::LitStr = inner.input.parse()?;
1760 method_attrs.s7.default = Some(value.value());
1761 } else if inner.path.is_ident("required") {
1762 method_attrs.s7.required = true;
1763 } else if inner.path.is_ident("frozen") {
1764 method_attrs.s7.frozen = true;
1765 } else if inner.path.is_ident("deprecated") {
1766 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1767 let value: syn::LitStr = inner.input.parse()?;
1768 method_attrs.s7.deprecated = Some(value.value());
1769 } else if inner.path.is_ident("no_dots") {
1770 if meta.path.is_ident("s3") || meta.path.is_ident("s4") {
1771 method_attrs.no_dispatch_dots = true;
1772 } else {
1773 method_attrs.s7.no_dots = true;
1774 }
1775 } else if inner.path.is_ident("dispatch") {
1776 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1777 let value: syn::LitStr = inner.input.parse()?;
1778 method_attrs.s7.dispatch = Some(value.value());
1779 } else if inner.path.is_ident("fallback") {
1780 method_attrs.s7.fallback = true;
1781 } else if inner.path.is_ident("no_shortcut") {
1782 method_attrs.s7.no_shortcut = true;
1783 } else if inner.path.is_ident("convert_from") {
1784 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1785 let value: syn::LitStr = inner.input.parse()?;
1786 method_attrs.s7.convert_from = Some(value.value());
1787 } else if inner.path.is_ident("convert_to") {
1788 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1789 let value: syn::LitStr = inner.input.parse()?;
1790 method_attrs.s7.convert_to = Some(value.value());
1791 } else if inner.path.is_ident("deep_clone") {
1792 method_attrs.r6.deep_clone = true;
1793 method_attrs.r6.deep_clone_span = Some(inner.path.span());
1794 } else if inner.path.is_ident("r_name") {
1795 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1796 let value: syn::LitStr = inner.input.parse()?;
1797 let val = value.value();
1798 if val.is_empty() {
1799 return Err(syn::Error::new_spanned(value, "r_name must not be empty"));
1800 }
1801 method_attrs.r_name = Some(val);
1802 } else if inner.path.is_ident("postfix") {
1803 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1804 let value: syn::LitStr = inner.input.parse()?;
1805 let val = value.value();
1806 crate::miniextendr_fn::validate_postfix(&val, &value)?;
1807 method_attrs.postfix = Some(val);
1808 } else if inner.path.is_ident("call") {
1809 return Err(inner.error(
1810 "`call = caller` is only supported on standalone `#[miniextendr]` \
1811 functions (the internal-entry-point pattern); class methods keep \
1812 their own call attribution",
1813 ));
1814 } else if inner.path.is_ident("r_entry") {
1815 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1816 let value: syn::LitStr = inner.input.parse()?;
1817 method_attrs.r_entry = Some(value.value());
1818 } else if inner.path.is_ident("r_post_checks") {
1819 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1820 let value: syn::LitStr = inner.input.parse()?;
1821 method_attrs.r_post_checks = Some(value.value());
1822 } else if inner.path.is_ident("r_on_exit") {
1823 if inner.input.peek(::syn::token::Eqsyn::Token![=]) {
1824 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1826 let value: syn::LitStr = inner.input.parse()?;
1827 method_attrs.r_on_exit = Some(crate::miniextendr_fn::ROnExit {
1828 expr: value.value(),
1829 add: true,
1830 after: true,
1831 });
1832 } else {
1833 let mut expr = None;
1835 let mut add = true;
1836 let mut after = true;
1837 inner.parse_nested_meta(|meta| {
1838 if meta.path.is_ident("expr") {
1839 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1840 let value: syn::LitStr = meta.input.parse()?;
1841 expr = Some(value.value());
1842 } else if meta.path.is_ident("add") {
1843 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1844 let value: syn::LitBool = meta.input.parse()?;
1845 add = value.value;
1846 } else if meta.path.is_ident("after") {
1847 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
1848 let value: syn::LitBool = meta.input.parse()?;
1849 after = value.value;
1850 } else {
1851 return Err(meta.error(
1852 "unknown r_on_exit option; expected `expr`, `add`, or `after`",
1853 ));
1854 }
1855 Ok(())
1856 })?;
1857 let expr = expr.ok_or_else(|| {
1858 inner.error("r_on_exit(...) requires `expr = \"...\"` specifying the R expression")
1859 })?;
1860 method_attrs.r_on_exit = Some(crate::miniextendr_fn::ROnExit { expr, add, after });
1861 }
1862 } else {
1863 return Err(inner.error(
1864 "unknown method option; expected one of: ignore, constructor, finalize, private, active, worker, no_worker, main_thread, no_main_thread, check_interrupt, coerce, no_coerce, rng, unwrap_in_r, serialize, serde_error, generic, class, getter, setter, validate, prop, default, required, frozen, deprecated, no_dots, dispatch, fallback, no_shortcut, convert_from, convert_to, deep_clone, r_on_exit, r_name, postfix, invisible, visible"
1865 ));
1866 }
1867 Ok(())
1868 })?;
1869 } else if meta.path.is_ident("defaults") {
1870 method_attrs.defaults_span = Some(meta.path.span());
1872 meta.parse_nested_meta(|inner| {
1874 let param_name = inner
1876 .path
1877 .get_ident()
1878 .ok_or_else(|| inner.error("expected parameter name"))?
1879 .to_string();
1880 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1882 let value: syn::LitStr = inner.input.parse()?;
1883 method_attrs.defaults.insert(param_name, value.value());
1884 Ok(())
1885 })?;
1886 } else if meta.path.is_ident("preconditions")
1887 || meta.path.is_ident("no_preconditions")
1888 {
1889 let keep = meta.path.is_ident("preconditions");
1893 if meta.input.peek(syn::token::Paren) {
1894 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1895 crate::miniextendr_fn::parse_method_preconditions(
1896 &meta,
1897 &mut method_attrs.per_param,
1898 keep,
1899 )?;
1900 } else {
1901 method_attrs.preconditions = Some(keep);
1902 }
1903 } else if meta.path.is_ident("no_na") {
1904 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1906 crate::miniextendr_fn::parse_method_no_na(&meta, &mut method_attrs.per_param)?;
1907 } else if let Some(check) = crate::miniextendr_fn::ClassCheck::of(&meta.path) {
1908 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1912 crate::miniextendr_fn::parse_method_class_check(
1913 &meta,
1914 &mut method_attrs.per_param,
1915 check,
1916 )?;
1917 } else if meta.path.is_ident("match_arg") {
1918 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1920 meta.parse_nested_meta(|inner| {
1921 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1922 method_attrs
1923 .per_param
1924 .entry(name)
1925 .or_default()
1926 .match_arg = true;
1927 Ok(())
1928 })?;
1929 } else if meta.path.is_ident("match_arg_several_ok") {
1930 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1933 meta.parse_nested_meta(|inner| {
1934 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1935 let entry = method_attrs.per_param.entry(name).or_default();
1936 entry.match_arg = true;
1937 entry.several_ok = true;
1938 Ok(())
1939 })?;
1940 } else if meta.path.is_ident("no_default") {
1941 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1944 crate::miniextendr_fn::parse_method_no_default(
1945 &meta,
1946 &mut method_attrs.per_param,
1947 )?;
1948 } else if meta.path.is_ident("formal") {
1949 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1952 crate::miniextendr_fn::parse_method_formal(&meta, &mut method_attrs.per_param)?;
1953 } else if meta.path.is_ident("choices") {
1954 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1956 meta.parse_nested_meta(|inner| {
1957 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1958 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1959 let value: syn::LitStr = inner.input.parse()?;
1960 let choices = crate::r_wrapper_builder::split_choice_list(&value.value());
1961 method_attrs.per_param.entry(name).or_default().choices = Some(choices);
1962 Ok(())
1963 })?;
1964 } else if meta.path.is_ident("choices_several_ok") {
1965 method_attrs.match_arg_span.get_or_insert(meta.path.span());
1967 meta.parse_nested_meta(|inner| {
1968 let name = crate::miniextendr_fn::method_check_param(&inner)?;
1969 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
1970 let value: syn::LitStr = inner.input.parse()?;
1971 let choices = crate::r_wrapper_builder::split_choice_list(&value.value());
1972 let entry = method_attrs.per_param.entry(name).or_default();
1973 entry.choices = Some(choices);
1974 entry.several_ok = true;
1975 Ok(())
1976 })?;
1977 } else if meta.path.is_ident("unsafe") {
1978 meta.parse_nested_meta(|inner| {
1980 if inner.path.is_ident("main_thread") {
1981 unsafe_main_thread = Some(true);
1982 } else {
1983 return Err(inner.error(
1984 "unknown `unsafe(...)` option; only `main_thread` is supported",
1985 ));
1986 }
1987 Ok(())
1988 })?;
1989 } else if meta.path.is_ident("check_interrupt") {
1990 method_attrs.check_interrupt = true;
1991 } else if meta.path.is_ident("coerce") {
1992 coerce = Some(true);
1993 } else if meta.path.is_ident("no_coerce") {
1994 coerce = Some(false);
1995 } else if meta.path.is_ident("rng") {
1996 if meta.input.peek(syn::token::Paren) {
1997 return crate::miniextendr_fn::refuse_rng_seed_on_method(
1998 &meta,
1999 "an impl method",
2000 );
2001 }
2002 method_attrs.rng = true;
2003 } else if meta.path.is_ident("unwrap_in_r") {
2004 method_attrs.unwrap_in_r = true;
2005 } else if meta.path.is_ident("wrap") {
2006 let value: syn::LitStr = meta.value()?.parse()?;
2007 method_attrs.wrap = Some(crate::return_wrap::parse_system(&value)?);
2008 } else if meta.path.is_ident("serialize") {
2009 method_attrs.serialize = true;
2010 } else if meta.path.is_ident("serde_error") {
2011 method_attrs.serde_error =
2012 Some(crate::miniextendr_fn::parse_serde_error_nested(&meta)?);
2013 } else if meta.path.is_ident("as") {
2014 method_attrs.as_coercion_span = Some(meta.path.span());
2016 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2017 let value: syn::LitStr = meta.input.parse()?;
2018 let coercion_type = value.value();
2019
2020 const SUPPORTED_AS_TYPES: &[&str] = &[
2022 "data.frame",
2023 "list",
2024 "character",
2025 "numeric",
2026 "double",
2027 "integer",
2028 "logical",
2029 "matrix",
2030 "vector",
2031 "factor",
2032 "Date",
2033 "POSIXct",
2034 "complex",
2035 "raw",
2036 "environment",
2037 "function",
2038 "tibble",
2039 "data.table",
2040 "array",
2041 "ts",
2042 ];
2043
2044 if !SUPPORTED_AS_TYPES.contains(&coercion_type.as_str()) {
2045 return Err(syn::Error::new(
2046 value.span(),
2047 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unsupported `as` type: \"{0}\". Supported types: {1}",
coercion_type, SUPPORTED_AS_TYPES.join(", ")))
})format!(
2048 "unsupported `as` type: \"{}\". Supported types: {}",
2049 coercion_type,
2050 SUPPORTED_AS_TYPES.join(", ")
2051 ),
2052 ));
2053 }
2054
2055 method_attrs.as_coercion = Some(coercion_type);
2056 } else if meta.path.is_ident("lifecycle") {
2057 if meta.input.peek(::syn::token::Eqsyn::Token![=]) {
2059 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2061 let value: syn::LitStr = meta.input.parse()?;
2062 let stage = crate::lifecycle::LifecycleStage::from_str(&value.value())
2063 .ok_or_else(|| {
2064 syn::Error::new(
2065 value.span(),
2066 "invalid lifecycle stage; expected one of: experimental, stable, superseded, soft-deprecated, deprecated, defunct",
2067 )
2068 })?;
2069 method_attrs.lifecycle = Some(crate::lifecycle::LifecycleSpec::new(stage));
2070 } else {
2071 let mut spec = crate::lifecycle::LifecycleSpec::default();
2073 meta.parse_nested_meta(|inner| {
2074 let key = inner.path.get_ident()
2075 .ok_or_else(|| inner.error("expected identifier"))?
2076 .to_string();
2077 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
2078 let value: syn::LitStr = inner.input.parse()?;
2079 match key.as_str() {
2080 "stage" => {
2081 spec.stage = crate::lifecycle::LifecycleStage::from_str(&value.value())
2082 .ok_or_else(|| syn::Error::new(value.span(), "invalid lifecycle stage"))?;
2083 }
2084 "when" => spec.when = Some(value.value()),
2085 "what" => spec.what = Some(value.value()),
2086 "with" => spec.with = Some(value.value()),
2087 "details" => spec.details = Some(value.value()),
2088 "id" => spec.id = Some(value.value()),
2089 _ => return Err(inner.error(
2090 "unknown lifecycle option; expected: stage, when, what, with, details, id"
2091 )),
2092 }
2093 Ok(())
2094 })?;
2095 method_attrs.lifecycle = Some(spec);
2096 }
2097 } else if meta.path.is_ident("vctrs") {
2098 meta.parse_nested_meta(|inner| {
2100 let raw_name = inner.path.get_ident()
2101 .ok_or_else(|| inner.error("expected protocol name"))?
2102 .to_string();
2103
2104 const PROTOCOL_ALIASES: &[(&str, &str)] = &[
2106 ("print_data", "obj_print_data"),
2107 ("print_header", "obj_print_header"),
2108 ("print_footer", "obj_print_footer"),
2109 ("proxy", "vec_proxy"),
2110 ("proxy_equal", "vec_proxy_equal"),
2111 ("proxy_compare", "vec_proxy_compare"),
2112 ("proxy_order", "vec_proxy_order"),
2113 ("restore", "vec_restore"),
2114 ];
2115 let protocol = PROTOCOL_ALIASES
2116 .iter()
2117 .find(|(alias, _)| *alias == raw_name)
2118 .map(|(_, full)| full.to_string())
2119 .unwrap_or_else(|| raw_name.to_string());
2120
2121 const VALID_PROTOCOLS: &[&str] = &[
2122 "format", "vec_proxy", "vec_proxy_equal", "vec_proxy_compare",
2123 "vec_proxy_order", "vec_restore", "obj_print_data",
2124 "obj_print_header", "obj_print_footer",
2125 ];
2126 if !VALID_PROTOCOLS.contains(&protocol.as_str()) {
2127 return Err(inner.error(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown vctrs protocol: {0}; expected one of: {1}",
raw_name, VALID_PROTOCOLS.join(", ")))
})format!(
2128 "unknown vctrs protocol: {}; expected one of: {}",
2129 raw_name,
2130 VALID_PROTOCOLS.join(", ")
2131 )));
2132 }
2133 method_attrs.vctrs_protocol = Some(protocol);
2134 Ok(())
2135 })?;
2136 } else if meta.path.is_ident("r_name") {
2137 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2138 let value: syn::LitStr = meta.input.parse()?;
2139 let val = value.value();
2140 if val.is_empty() {
2141 return Err(syn::Error::new_spanned(value, "r_name must not be empty"));
2142 }
2143 method_attrs.r_name = Some(val);
2144 } else if meta.path.is_ident("postfix") {
2145 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2146 let value: syn::LitStr = meta.input.parse()?;
2147 let val = value.value();
2148 crate::miniextendr_fn::validate_postfix(&val, &value)?;
2149 method_attrs.postfix = Some(val);
2150 } else if meta.path.is_ident("call") {
2151 return Err(meta.error(
2152 "`call = caller` is only supported on standalone `#[miniextendr]` \
2153 functions (the internal-entry-point pattern); class methods keep \
2154 their own call attribution",
2155 ));
2156 } else if meta.path.is_ident("r_entry") {
2157 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2158 let value: syn::LitStr = meta.input.parse()?;
2159 method_attrs.r_entry = Some(value.value());
2160 } else if meta.path.is_ident("r_post_checks") {
2161 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2162 let value: syn::LitStr = meta.input.parse()?;
2163 method_attrs.r_post_checks = Some(value.value());
2164 } else if meta.path.is_ident("r_on_exit") {
2165 if meta.input.peek(::syn::token::Eqsyn::Token![=]) {
2166 let _: ::syn::token::Eqsyn::Token![=] = meta.input.parse()?;
2168 let value: syn::LitStr = meta.input.parse()?;
2169 method_attrs.r_on_exit = Some(crate::miniextendr_fn::ROnExit {
2170 expr: value.value(),
2171 add: true,
2172 after: true,
2173 });
2174 } else {
2175 let mut expr = None;
2177 let mut add = true;
2178 let mut after = true;
2179 meta.parse_nested_meta(|inner| {
2180 if inner.path.is_ident("expr") {
2181 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
2182 let value: syn::LitStr = inner.input.parse()?;
2183 expr = Some(value.value());
2184 } else if inner.path.is_ident("add") {
2185 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
2186 let value: syn::LitBool = inner.input.parse()?;
2187 add = value.value;
2188 } else if inner.path.is_ident("after") {
2189 let _: ::syn::token::Eqsyn::Token![=] = inner.input.parse()?;
2190 let value: syn::LitBool = inner.input.parse()?;
2191 after = value.value;
2192 } else {
2193 return Err(inner.error(
2194 "unknown r_on_exit option; expected `expr`, `add`, or `after`",
2195 ));
2196 }
2197 Ok(())
2198 })?;
2199 let expr = expr.ok_or_else(|| {
2200 meta.error("r_on_exit(...) requires `expr = \"...\"` specifying the R expression")
2201 })?;
2202 method_attrs.r_on_exit = Some(crate::miniextendr_fn::ROnExit { expr, add, after });
2203 }
2204 } else if meta.path.is_ident("noexport") {
2205 method_attrs.noexport = true;
2206 } else if meta.path.is_ident("internal") {
2207 method_attrs.internal = true;
2208 } else if meta.path.is_ident("invisible") {
2209 method_attrs.force_invisible = Some(true);
2210 } else if meta.path.is_ident("visible") {
2211 method_attrs.force_invisible = Some(false);
2212 } else if meta.path.is_ident("dots") {
2213 let value: syn::Expr = meta.value()?.parse()?;
2219 match crate::dots_policy::parse_dots_attr(&value)? {
2220 crate::dots_policy::DotsAttr::TypedList(spec) => {
2221 method_attrs.dots_spec = Some(spec);
2222 }
2223 crate::dots_policy::DotsAttr::Policy(policy) => {
2224 method_attrs.dots_policy = Some(policy);
2225 }
2226 }
2227 } else {
2228 return Err(meta.error(
2229 "unknown attribute; expected one of: env, r6, s3, s4, s7, vctrs, defaults, unsafe, check_interrupt, coerce, no_coerce, preconditions, no_preconditions, rng, unwrap_in_r, serialize, serde_error, as, lifecycle, r_name, postfix, r_entry, r_post_checks, r_on_exit, noexport, internal, invisible, visible, match_arg, match_arg_several_ok, choices, choices_several_ok, no_default, inherits, not_inherits, no_na, formal, dots = typed_list!(...) | empty | forward(allow = [...]) | data"
2230 ));
2231 }
2232 Ok(())
2233 })?;
2234 }
2235
2236 method_attrs.worker = worker.unwrap_or(falsecfg!(feature = "worker-default"));
2238 method_attrs.unsafe_main_thread = unsafe_main_thread.unwrap_or(false);
2241 method_attrs.coerce = coerce.unwrap_or(falsecfg!(feature = "coerce-default"));
2242
2243 if (method_attrs.internal || method_attrs.noexport) && !method_attrs.r6.active {
2255 return Err(syn::Error::new(
2256 proc_macro2::Span::call_site(),
2257 "method-level `internal` / `noexport` are currently only supported on R6 \
2258 active bindings (use `#[miniextendr(r6(active), noexport)]`). For other \
2259 method positions, set `internal` / `noexport` at the impl-block level \
2260 (`#[miniextendr(s7, internal)] impl Foo { ... }`) instead.",
2261 ));
2262 }
2263
2264 Ok(method_attrs)
2265 }
2266
2267 fn detect_env(sig: &syn::Signature) -> ReceiverKind {
2275 match crate::trait_receiver::owner_receiver(sig) {
2276 Some(crate::trait_receiver::OwnerReceiver::Shared) => {
2277 return ReceiverKind::ExternalPtrRef;
2278 }
2279 Some(crate::trait_receiver::OwnerReceiver::Mutable) => {
2280 return ReceiverKind::ExternalPtrMut;
2281 }
2282 None => {}
2283 }
2284 match sig.inputs.first() {
2285 Some(syn::FnArg::Receiver(r)) => {
2286 if r.reference.is_some() {
2288 if r.mutability.is_some() {
2289 ReceiverKind::RefMut
2290 } else {
2291 ReceiverKind::Ref
2292 }
2293 } else if r.colon_token.is_some() {
2294 if let syn::Type::Reference(type_ref) = r.ty.as_ref() {
2297 if type_ref.mutability.is_some() {
2298 ReceiverKind::RefMut
2299 } else {
2300 ReceiverKind::Ref
2301 }
2302 } else if is_external_ptr_type(r.ty.as_ref()) {
2303 ReceiverKind::ExternalPtrValue
2305 } else {
2306 ReceiverKind::Value
2308 }
2309 } else {
2310 ReceiverKind::Value
2311 }
2312 }
2313 _ => ReceiverKind::None,
2314 }
2315 }
2316
2317 fn sig_without_env(sig: &syn::Signature) -> syn::Signature {
2323 let mut sig = sig.clone();
2324 if let Some(syn::FnArg::Receiver(_)) = sig.inputs.first() {
2325 sig.inputs = sig.inputs.into_iter().skip(1).collect();
2326 }
2327 sig
2328 }
2329
2330 pub fn from_impl_item(
2336 item: &mut syn::ImplItemFn,
2337 class_page: crate::roxygen::RdPage,
2338 ) -> syn::Result<Self> {
2339 use syn::spanned::Spanned;
2340 old_handle_receiver(&item.sig)?;
2341 let env = Self::detect_env(&item.sig);
2342 let mut method_attrs = Self::parse_method_attrs(&item.attrs)?;
2343
2344 crate::miniextendr_fn::rewrite_variadic_dots(&mut item.sig)?;
2347 let dots_ident = crate::miniextendr_fn::find_dots_param(&item.sig.inputs)?;
2348 let has_dots = dots_ident.is_some();
2349
2350 let param_markers = crate::miniextendr_fn::collect_param_markers(&item.sig.inputs)?;
2355 for arg in &item.sig.inputs {
2356 let syn::FnArg::Typed(pt) = arg else {
2357 continue;
2358 };
2359 let syn::Pat::Ident(pat_ident) = pt.pat.as_ref() else {
2360 continue;
2361 };
2362 let name = crate::naming::ident_name(&pat_ident.ident);
2363 let Some((_, markers)) = param_markers.iter().find(|(n, _)| *n == name) else {
2364 continue;
2365 };
2366 let entry = method_attrs.per_param.entry(name.clone()).or_default();
2367 entry.preconditions = crate::miniextendr_fn::merge_param_policy(
2368 markers,
2369 entry.preconditions,
2370 &name,
2371 true,
2372 &pt.ty,
2373 )?;
2374 }
2375 let mut peeled_sig = item.sig.clone();
2376 peeled_sig.inputs = crate::miniextendr_fn::peeled_inputs(&item.sig.inputs, ¶m_markers)?;
2377
2378 if let Some(spec) = &method_attrs.dots_spec {
2384 let dots_ident = dots_ident.as_ref().ok_or_else(|| {
2385 syn::Error::new(
2386 item.sig.ident.span(),
2387 "dots = typed_list!(...) requires the method to take a dots parameter \
2388 (`...` or a `&Dots` parameter)",
2389 )
2390 })?;
2391 if let Some(err) =
2392 crate::miniextendr_fn::typed_list_on_lazy_dots(&item.sig.inputs, None)
2393 {
2394 return Err(err);
2395 }
2396 let stmt = crate::build_dots_validation_stmt(dots_ident, spec);
2397 item.block.stmts.insert(0, stmt);
2398 }
2399
2400 if env != ReceiverKind::None && method_attrs.defaults.contains_key("self") {
2402 return Err(syn::Error::new(
2403 method_attrs
2404 .defaults_span
2405 .unwrap_or_else(|| item.sig.ident.span()),
2406 "cannot specify default for self parameter in defaults(...)",
2407 ));
2408 }
2409
2410 let param_names: std::collections::HashSet<String> = item
2412 .sig
2413 .inputs
2414 .iter()
2415 .filter_map(|input| {
2416 if let syn::FnArg::Typed(pat_type) = input
2417 && let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref()
2418 {
2419 Some(crate::naming::ident_name(&pat_ident.ident))
2420 } else {
2421 None
2422 }
2423 })
2424 .collect();
2425
2426 let mut invalid_params: Vec<String> = method_attrs
2427 .defaults
2428 .keys()
2429 .filter(|key| *key != "self" && !param_names.contains(*key))
2430 .cloned()
2431 .collect();
2432 invalid_params.sort();
2433
2434 if !invalid_params.is_empty() {
2435 return Err(syn::Error::new(
2436 method_attrs
2437 .defaults_span
2438 .unwrap_or_else(|| item.sig.ident.span()),
2439 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("defaults(...) references non-existent parameter(s): {0}",
invalid_params.join(", ")))
})format!(
2440 "defaults(...) references non-existent parameter(s): {}",
2441 invalid_params.join(", ")
2442 ),
2443 ));
2444 }
2445
2446 for input in &peeled_sig.inputs {
2448 let syn::FnArg::Typed(pat_type) = input else {
2449 continue;
2450 };
2451 let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() else {
2452 continue;
2453 };
2454 let param_name = crate::naming::ident_name(&pat_ident.ident);
2455
2456 crate::miniextendr_fn::validate_param_type(pat_type.ty.as_ref(), pat_type.ty.span())?;
2458
2459 if crate::miniextendr_fn::is_dots_type(pat_type.ty.as_ref())
2461 && method_attrs.defaults.contains_key(¶m_name)
2462 {
2463 return Err(syn::Error::new(
2464 method_attrs
2465 .defaults_span
2466 .unwrap_or_else(|| pat_ident.ident.span()),
2467 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("variadic (...) parameter `{0}` cannot have a default value",
param_name))
})format!(
2468 "variadic (...) parameter `{}` cannot have a default value",
2469 param_name
2470 ),
2471 ));
2472 }
2473 }
2474
2475 if method_attrs.lifecycle.is_none() {
2477 method_attrs.lifecycle = item
2478 .attrs
2479 .iter()
2480 .find_map(crate::lifecycle::parse_rust_deprecated);
2481 }
2482
2483 let mut doc_tags =
2485 crate::roxygen::roxygen_tags_from_attrs_for_r6_method(&item.attrs, class_page);
2486
2487 if let Some(ref spec) = method_attrs.lifecycle {
2489 crate::lifecycle::inject_lifecycle_badge(&mut doc_tags, spec);
2490 }
2491
2492 let param_defaults = method_attrs.defaults.clone();
2494
2495 crate::miniextendr_fn::finalize_method_param_attrs(
2505 &mut method_attrs.per_param,
2506 &peeled_sig.inputs,
2507 ¶m_markers,
2508 ¶m_defaults,
2509 method_attrs
2510 .match_arg_span
2511 .unwrap_or_else(|| item.sig.ident.span()),
2512 )?;
2513
2514 crate::miniextendr_fn::check_rng_guard_params(
2517 &peeled_sig.inputs,
2518 method_attrs.rng,
2519 |name| method_attrs.per_param.contains_key(name) || param_defaults.contains_key(name),
2520 )?;
2521
2522 if env == ReceiverKind::Value {
2527 if let Some(syn::FnArg::Receiver(r)) = item.sig.inputs.first()
2528 && r.colon_token.is_some()
2529 && !#[allow(non_exhaustive_omitted_patterns)] match r.ty.as_ref() {
syn::Type::Path(tp) if
tp.path.segments.last().is_some_and(|seg| seg.ident == "Self") &&
tp.path.segments.len() == 1 => true,
_ => false,
}matches!(r.ty.as_ref(), syn::Type::Path(tp)
2530 if tp.path.segments.last().is_some_and(|seg| seg.ident == "Self")
2531 && tp.path.segments.len() == 1)
2532 {
2533 return Err(syn::Error::new_spanned(
2534 &r.ty,
2535 "unsupported receiver type: the R handle stores the value itself, so a \
2536 method can take `self`, `self: Self`, `&self`, `&mut self`, \
2537 `self: ExternalPtrRef<'_, Self>`, `self: ExternalPtrMut<'_, Self>` or \
2538 `self: ExternalPtr<Self>` — not a smart pointer around `Self`",
2539 ));
2540 }
2541 if method_attrs.constructor {
2542 return Err(syn::Error::new(
2543 item.sig.fn_token.span,
2544 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("method `{0}` takes `self` and is marked `constructor`; a constructor has no receiver (`fn new(...) -> Self`). A consuming builder step needs no marker: `fn {1}(self, ...) -> Self` writes its result back into the same R object.",
item.sig.ident, item.sig.ident))
})format!(
2545 "method `{}` takes `self` and is marked `constructor`; a constructor has no \
2546 receiver (`fn new(...) -> Self`). A consuming builder step needs no marker: \
2547 `fn {}(self, ...) -> Self` writes its result back into the same R object.",
2548 item.sig.ident, item.sig.ident
2549 ),
2550 ));
2551 }
2552 }
2553
2554 let mut sig = Self::sig_without_env(&peeled_sig);
2557 let rng_guard = sig.inputs.iter().position(|arg| {
2561 #[allow(non_exhaustive_omitted_patterns)] match arg {
syn::FnArg::Typed(pt) if crate::type_inspect::is_rng_guard_param(&pt.ty)
=> true,
_ => false,
}matches!(arg, syn::FnArg::Typed(pt) if crate::type_inspect::is_rng_guard_param(&pt.ty))
2562 });
2563 if rng_guard.is_some() {
2564 sig.inputs = std::mem::take(&mut sig.inputs)
2565 .into_iter()
2566 .filter(|arg| {
2567 !#[allow(non_exhaustive_omitted_patterns)] match arg {
syn::FnArg::Typed(pt) if crate::type_inspect::is_rng_guard_param(&pt.ty)
=> true,
_ => false,
}matches!(arg, syn::FnArg::Typed(pt)
2568 if crate::type_inspect::is_rng_guard_param(&pt.ty))
2569 })
2570 .collect();
2571 }
2572 let visibility_marker = match &item.sig.output {
2573 syn::ReturnType::Type(_, ty) => {
2574 if let Some(err) = crate::type_inspect::visibility_marker_error(ty, "return") {
2575 return Err(err);
2576 }
2577 let (marker, peeled) =
2578 crate::type_inspect::peel_return_visibility(&item.sig.output);
2579 sig.output = peeled;
2580 marker
2581 }
2582 syn::ReturnType::Default => None,
2583 };
2584 if let (Some(marker), Some(attr)) = (visibility_marker, method_attrs.force_invisible)
2585 && marker != attr
2586 {
2587 return Err(syn::Error::new_spanned(
2588 &item.sig.output,
2589 "the return type's visibility marker and the `invisible` / `visible` method option disagree; keep one of them (or make them agree)",
2590 ));
2591 }
2592
2593 let (return_wrap, output) = crate::return_wrap::resolve(&sig.output, method_attrs.wrap)?;
2594 if return_wrap.is_some() && (method_attrs.serialize || method_attrs.unwrap_in_r) {
2595 return Err(syn::Error::new_spanned(
2596 &item.sig.output,
2597 "explicit class wrapping cannot be combined with serialize or unwrap_in_r",
2598 ));
2599 }
2600 sig.output = crate::type_inspect::serialize_return_type(&output, method_attrs.serialize);
2601 Ok(ParsedMethod {
2602 visibility_marker,
2603 return_wrap,
2604 ident: item.sig.ident.clone(),
2605 env,
2606 sig,
2607 param_markers,
2608 vis: item.vis.clone(),
2609 doc_tags,
2610 method_attrs,
2611 param_defaults,
2612 has_dots,
2613 rng_guard,
2614 })
2615 }
2616
2617 pub fn should_include(&self) -> bool {
2619 !self.method_attrs.ignore
2621 }
2622
2623 pub fn is_private(&self) -> bool {
2626 if self.method_attrs.r6.private {
2628 return true;
2629 }
2630 !#[allow(non_exhaustive_omitted_patterns)] match self.vis {
syn::Visibility::Public(_) => true,
_ => false,
}matches!(self.vis, syn::Visibility::Public(_))
2632 }
2633
2634 pub fn is_constructor(&self) -> bool {
2637 self.method_attrs.constructor
2638 || (self.env == ReceiverKind::None && self.ident == "new" && self.returns_self())
2639 }
2640
2641 pub fn is_finalizer(&self) -> bool {
2648 self.method_attrs.r6.finalize
2649 }
2650
2651 pub fn is_active(&self) -> bool {
2654 self.method_attrs.r6.active
2655 }
2656
2657 pub fn r_method_name(&self) -> String {
2662 if let Some(r_name) = &self.method_attrs.r_name {
2663 return r_name.clone();
2664 }
2665 match &self.method_attrs.postfix {
2666 Some(postfix) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}",
crate::naming::ident_name(&self.ident), postfix))
})format!("{}{postfix}", crate::naming::ident_name(&self.ident)),
2667 None => crate::naming::ident_name(&self.ident),
2668 }
2669 }
2670
2671 pub fn c_wrapper_ident(&self, type_ident: &syn::Ident) -> syn::Ident {
2677 crate::naming::impl_method_c_wrapper_ident(type_ident, &self.ident)
2678 }
2679
2680 pub fn formals(&self) -> crate::r_wrapper_builder::Formals {
2683 crate::r_wrapper_builder::Formals::from_param_attrs(&self.method_attrs.per_param)
2684 }
2685
2686 pub fn lifecycle_prelude(&self, what: &str) -> Option<String> {
2693 self.method_attrs
2694 .lifecycle
2695 .as_ref()
2696 .and_then(|spec| spec.r_prelude(what))
2697 }
2698
2699 pub fn returns_self(&self) -> bool {
2701 #[allow(non_exhaustive_omitted_patterns)] match &self.sig.output {
syn::ReturnType::Type(_, ty) if
#[allow(non_exhaustive_omitted_patterns)] match ty.as_ref() {
syn::Type::Path(p) if
p.path.segments.last().map(|s|
s.ident == "Self").unwrap_or(false) => true,
_ => false,
} => true,
_ => false,
}matches!(&self.sig.output, syn::ReturnType::Type(_, ty)
2702 if matches!(ty.as_ref(), syn::Type::Path(p)
2703 if p.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false)))
2704 }
2705
2706 pub fn returns_result_self(&self) -> bool {
2713 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
2714 return false;
2715 };
2716 let syn::Type::Path(p) = ty.as_ref() else {
2717 return false;
2718 };
2719 let Some(seg) = p.path.segments.last() else {
2720 return false;
2721 };
2722 if seg.ident != "Result" {
2723 return false;
2724 }
2725 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
2726 return false;
2727 };
2728 let Some(syn::GenericArgument::Type(ok_ty)) = ab.args.first() else {
2729 return false;
2730 };
2731 #[allow(non_exhaustive_omitted_patterns)] match ok_ty {
syn::Type::Path(ip) if
ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false) =>
true,
_ => false,
}matches!(ok_ty, syn::Type::Path(ip)
2732 if ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false))
2733 }
2734
2735 pub fn returns_option_self(&self) -> bool {
2743 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
2744 return false;
2745 };
2746 let syn::Type::Path(p) = ty.as_ref() else {
2747 return false;
2748 };
2749 let Some(seg) = p.path.segments.last() else {
2750 return false;
2751 };
2752 if seg.ident != "Option" {
2753 return false;
2754 }
2755 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
2756 return false;
2757 };
2758 let Some(syn::GenericArgument::Type(some_ty)) = ab.args.first() else {
2759 return false;
2760 };
2761 #[allow(non_exhaustive_omitted_patterns)] match some_ty {
syn::Type::Path(ip) if
ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false) =>
true,
_ => false,
}matches!(some_ty, syn::Type::Path(ip)
2762 if ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false))
2763 }
2764
2765 pub fn returns_other_class(&self) -> Option<syn::Ident> {
2801 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
2802 return None;
2803 };
2804 let syn::Type::Path(p) = ty.as_ref() else {
2805 return None;
2806 };
2807 let seg = p.path.segments.last()?;
2808
2809 match &seg.arguments {
2810 syn::PathArguments::None => Self::class_ident_from_ident(&seg.ident),
2811 syn::PathArguments::AngleBracketed(_) if seg.ident == "Option" => {
2812 Self::inner_class_ident(crate::first_type_argument(seg)?)
2813 }
2814 syn::PathArguments::AngleBracketed(_) if seg.ident == "Result" => {
2815 let err_is_unit = crate::second_type_argument(seg)
2819 .is_some_and(|ty| #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Tuple(t) if t.elems.is_empty() => true,
_ => false,
}matches!(ty, syn::Type::Tuple(t) if t.elems.is_empty()));
2820 if err_is_unit {
2821 return None;
2822 }
2823 Self::inner_class_ident(crate::first_type_argument(seg)?)
2824 }
2825 syn::PathArguments::AngleBracketed(_) if seg.ident == "ExternalPtr" => {
2829 Self::inner_class_ident(ty.as_ref())
2830 }
2831 _ => None,
2832 }
2833 }
2834
2835 pub fn returns_other_class_list(&self) -> Option<syn::Ident> {
2877 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
2878 return None;
2879 };
2880 let syn::Type::Path(p) = ty.as_ref() else {
2881 return None;
2882 };
2883 let seg = p.path.segments.last()?;
2884
2885 match &seg.arguments {
2886 syn::PathArguments::AngleBracketed(_) if seg.ident == "Vec" => {
2887 Self::vec_inner_class_ident(ty)
2888 }
2889 syn::PathArguments::AngleBracketed(_) if seg.ident == "Option" => {
2890 Self::vec_inner_class_ident(crate::first_type_argument(seg)?)
2891 }
2892 syn::PathArguments::AngleBracketed(_) if seg.ident == "Result" => {
2893 let err_is_unit = crate::second_type_argument(seg)
2896 .is_some_and(|ty| #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Tuple(t) if t.elems.is_empty() => true,
_ => false,
}matches!(ty, syn::Type::Tuple(t) if t.elems.is_empty()));
2897 if err_is_unit {
2898 return None;
2899 }
2900 Self::vec_inner_class_ident(crate::first_type_argument(seg)?)
2901 }
2902 _ => None,
2903 }
2904 }
2905
2906 pub(crate) fn vec_inner_class_ident(ty: &syn::Type) -> Option<syn::Ident> {
2911 let syn::Type::Path(p) = ty else {
2912 return None;
2913 };
2914 let seg = p.path.segments.last()?;
2915 if seg.ident != "Vec" {
2916 return None;
2917 }
2918 Self::inner_class_ident(crate::first_type_argument(seg)?)
2919 }
2920
2921 fn class_ident_from_ident(ident: &syn::Ident) -> Option<syn::Ident> {
2925 let name = ident.to_string();
2926 if name == "Self"
2927 || is_builtin_return_type_name(&name)
2928 || is_known_return_container_name(&name)
2929 {
2930 return None;
2931 }
2932
2933 name.chars()
2934 .next()
2935 .is_some_and(|c| c.is_ascii_uppercase())
2936 .then(|| ident.clone())
2937 }
2938
2939 pub(crate) fn inner_class_ident(ty: &syn::Type) -> Option<syn::Ident> {
2951 let syn::Type::Path(p) = crate::type_inspect::peel_external_ptr(ty) else {
2952 return None;
2953 };
2954 let seg = p.path.segments.last()?;
2955 match &seg.arguments {
2956 syn::PathArguments::None => Self::class_ident_from_ident(&seg.ident),
2957 _ => None,
2958 }
2959 }
2960
2961 pub fn returns_self_list(&self) -> bool {
2981 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
2982 return false;
2983 };
2984 let syn::Type::Path(p) = ty.as_ref() else {
2985 return false;
2986 };
2987 let Some(seg) = p.path.segments.last() else {
2988 return false;
2989 };
2990
2991 match &seg.arguments {
2992 syn::PathArguments::AngleBracketed(_) if seg.ident == "Vec" => Self::is_vec_of_self(ty),
2993 syn::PathArguments::AngleBracketed(_) if seg.ident == "Option" => {
2994 crate::first_type_argument(seg).is_some_and(Self::is_vec_of_self)
2995 }
2996 syn::PathArguments::AngleBracketed(_) if seg.ident == "Result" => {
2997 let err_is_unit = crate::second_type_argument(seg)
3001 .is_some_and(|ty| #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Tuple(t) if t.elems.is_empty() => true,
_ => false,
}matches!(ty, syn::Type::Tuple(t) if t.elems.is_empty()));
3002 !err_is_unit && crate::first_type_argument(seg).is_some_and(Self::is_vec_of_self)
3003 }
3004 _ => false,
3005 }
3006 }
3007
3008 fn is_vec_of_self(ty: &syn::Type) -> bool {
3013 let syn::Type::Path(p) = ty else {
3014 return false;
3015 };
3016 let Some(seg) = p.path.segments.last() else {
3017 return false;
3018 };
3019 if seg.ident != "Vec" {
3020 return false;
3021 }
3022 #[allow(non_exhaustive_omitted_patterns)] match crate::first_type_argument(seg)
{
Some(syn::Type::Path(ip)) if
ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false) =>
true,
_ => false,
}matches!(crate::first_type_argument(seg), Some(syn::Type::Path(ip))
3023 if ip.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false))
3024 }
3025
3026 pub fn returns_self_ref(&self) -> bool {
3037 #[allow(non_exhaustive_omitted_patterns)] match &self.sig.output {
syn::ReturnType::Type(_, ty) if Self::is_self_ref_type(ty) => true,
_ => false,
}matches!(&self.sig.output, syn::ReturnType::Type(_, ty) if Self::is_self_ref_type(ty))
3038 }
3039
3040 fn is_self_ref_type(ty: &syn::Type) -> bool {
3042 #[allow(non_exhaustive_omitted_patterns)] match ty {
syn::Type::Reference(r) if
#[allow(non_exhaustive_omitted_patterns)] match r.elem.as_ref() {
syn::Type::Path(p) if
p.path.segments.last().map(|s|
s.ident == "Self").unwrap_or(false) => true,
_ => false,
} => true,
_ => false,
}matches!(ty, syn::Type::Reference(r)
3043 if matches!(r.elem.as_ref(), syn::Type::Path(p)
3044 if p.path.segments.last().map(|s| s.ident == "Self").unwrap_or(false)))
3045 }
3046
3047 fn wrapped_output_arg(&self, wrapper: &str) -> Option<&syn::Type> {
3050 let syn::ReturnType::Type(_, ty) = &self.sig.output else {
3051 return None;
3052 };
3053 let syn::Type::Path(p) = ty.as_ref() else {
3054 return None;
3055 };
3056 let seg = p.path.segments.last()?;
3057 if seg.ident != wrapper {
3058 return None;
3059 }
3060 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
3061 return None;
3062 };
3063 match ab.args.first()? {
3064 syn::GenericArgument::Type(t) => Some(t),
3065 _ => None,
3066 }
3067 }
3068
3069 pub fn returns_result_self_ref(&self) -> bool {
3074 self.wrapped_output_arg("Result")
3075 .is_some_and(Self::is_self_ref_type)
3076 }
3077
3078 pub fn returns_option_self_ref(&self) -> bool {
3082 self.wrapped_output_arg("Option")
3083 .is_some_and(Self::is_self_ref_type)
3084 }
3085
3086 pub fn returns_option(&self) -> bool {
3089 self.wrapped_output_arg("Option").is_some()
3090 }
3091
3092 pub fn returns_unit(&self) -> bool {
3094 match &self.sig.output {
3095 syn::ReturnType::Default => true,
3096 syn::ReturnType::Type(_, ty) => {
3097 #[allow(non_exhaustive_omitted_patterns)] match ty.as_ref() {
syn::Type::Tuple(t) if t.elems.is_empty() => true,
_ => false,
}matches!(ty.as_ref(), syn::Type::Tuple(t) if t.elems.is_empty())
3098 }
3099 }
3100 }
3101
3102 pub fn is_invisible(&self) -> bool {
3107 self.visibility_marker
3108 .or(self.method_attrs.force_invisible)
3109 .unwrap_or(false)
3110 }
3111}
3112
3113fn is_builtin_return_type_name(name: &str) -> bool {
3114 #[allow(non_exhaustive_omitted_patterns)] match name {
"i8" | "i16" | "i32" | "i64" | "i128" | "u8" | "u16" | "u32" | "u64" |
"u128" | "f32" | "f64" | "bool" | "char" | "str" | "String" | "usize"
| "isize" | "RLogical" | "Rboolean" | "Rcomplex" => true,
_ => false,
}matches!(
3115 name,
3116 "i8" | "i16"
3117 | "i32"
3118 | "i64"
3119 | "i128"
3120 | "u8"
3121 | "u16"
3122 | "u32"
3123 | "u64"
3124 | "u128"
3125 | "f32"
3126 | "f64"
3127 | "bool"
3128 | "char"
3129 | "str"
3130 | "String"
3131 | "usize"
3132 | "isize"
3133 | "RLogical"
3134 | "Rboolean"
3135 | "Rcomplex"
3136 )
3137}
3138
3139fn is_known_return_container_name(name: &str) -> bool {
3140 #[allow(non_exhaustive_omitted_patterns)] match name {
"Vec" | "Option" | "Result" | "Box" | "HashMap" | "BTreeMap" => true,
_ => false,
}matches!(
3141 name,
3142 "Vec" | "Option" | "Result" | "Box" | "HashMap" | "BTreeMap"
3143 )
3144}
3145
3146impl ParsedImpl {
3147 pub fn parse(attrs: ImplAttrs, item_impl: syn::ItemImpl) -> syn::Result<Self> {
3152 let type_ident =
3154 match item_impl.self_ty.as_ref() {
3155 syn::Type::Path(p) => p.path.segments.last().map(|s| s.ident.clone()).ok_or_else(
3156 || {
3157 syn::Error::new_spanned(
3158 &item_impl.self_ty,
3159 "#[miniextendr] impl blocks require a named type (e.g., `impl MyType`)",
3160 )
3161 },
3162 )?,
3163 _ => {
3164 return Err(syn::Error::new_spanned(
3165 &item_impl.self_ty,
3166 "#[miniextendr] impl blocks require a named struct type. \
3167 Found a non-path type. Use `impl MyStruct { ... }` with a concrete struct.",
3168 ));
3169 }
3170 };
3171
3172 {
3179 let params = &item_impl.generics.params;
3180 let has_type_or_const = params
3181 .iter()
3182 .any(|p| #[allow(non_exhaustive_omitted_patterns)] match p {
syn::GenericParam::Type(_) | syn::GenericParam::Const(_) => true,
_ => false,
}matches!(p, syn::GenericParam::Type(_) | syn::GenericParam::Const(_)));
3183
3184 if has_type_or_const {
3185 return Err(syn::Error::new_spanned(
3186 &item_impl.generics,
3187 "generic impl blocks are not supported by #[miniextendr]. \
3188 R's .Call interface requires monomorphic C symbols, so generic type \
3189 parameters cannot be used. Remove the generic parameters and use a \
3190 concrete type instead. \
3191 Explicit lifetime parameters are allowed (lifetimes are erased at codegen).",
3192 ));
3193 }
3194 }
3195
3196 for attr in &item_impl.attrs {
3198 if attr.path().is_ident("export_name") {
3199 return Err(syn::Error::new_spanned(
3200 attr,
3201 "#[export_name] is not supported with #[miniextendr]; \
3202 the macro generates its own C symbol names",
3203 ));
3204 }
3205 }
3206
3207 let class_page = crate::roxygen::RdPage::suppressed_if(
3213 crate::roxygen::attrs_have_roxygen_tag(&item_impl.attrs, "noRd")
3214 || (attrs.noexport
3215 && !attrs.internal
3216 && !crate::roxygen::attrs_have_roxygen_tag(
3217 &item_impl.attrs,
3218 "keywords internal",
3219 )),
3220 );
3221
3222 let mut original_impl = item_impl.clone();
3225 let mut methods = Vec::new();
3226 for item in &mut original_impl.items {
3227 if let syn::ImplItem::Fn(fn_item) = item {
3228 let mut method = ParsedMethod::from_impl_item(fn_item, class_page)?;
3229 crate::s7_conversion::configure(
3230 &mut method,
3231 fn_item,
3232 attrs.class_system,
3233 &type_ident,
3234 )?;
3235 ParsedMethod::validate_method_attrs(
3237 &method.method_attrs,
3238 attrs.class_system,
3239 fn_item.sig.ident.span(),
3240 )?;
3241 if method.method_attrs.serde_error.is_some()
3242 && !crate::return_type_analysis::output_is_result(&fn_item.sig.output)
3243 {
3244 return Err(syn::Error::new(
3245 fn_item.sig.ident.span(),
3246 "`#[miniextendr(serde_error(..))]` requires a `Result<T, E>` return type: it \
3247 classes the condition raised from the `Err` arm",
3248 ));
3249 }
3250 methods.push(method);
3251 }
3252 }
3253
3254 if attrs.class_system == ClassSystem::Vctrs {
3270 for method in &methods {
3271 let is_ctor = (method.method_attrs.constructor
3273 || (method.env == ReceiverKind::None && method.ident == "new"))
3274 && method.env != ReceiverKind::Ref
3275 && method.env != ReceiverKind::RefMut;
3276 if is_ctor && vctrs_ctor_returns_self_or_type(&method.sig.output, &type_ident) {
3277 return Err(syn::Error::new_spanned(
3278 &method.sig.output,
3279 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[MXL120] vctrs constructor `{0}` must not return `Self` or `{1}`.\n\nThe generated R wrapper passes the constructor result to `vctrs::new_vctr()` (or `new_rcrd`/`new_list_of`), which requires a plain vector payload — not an ExternalPtr (`EXTPTRSXP`).\n\nFix: return the vector payload directly instead of `Self`.\nFor example, return `Vec<f64>` (for vctr), a `std::collections::HashMap` / named-list struct (for rcrd), or a `Vec<Vec<T>>` (for list_of).",
method.ident, type_ident))
})format!(
3280 "[MXL120] vctrs constructor `{}` must not return `Self` or `{}`.\n\
3281 \n\
3282 The generated R wrapper passes the constructor result to \
3283 `vctrs::new_vctr()` (or `new_rcrd`/`new_list_of`), which requires a \
3284 plain vector payload — not an ExternalPtr (`EXTPTRSXP`).\n\
3285 \n\
3286 Fix: return the vector payload directly instead of `Self`.\n\
3287 For example, return `Vec<f64>` (for vctr), a `std::collections::HashMap` \
3288 / named-list struct (for rcrd), or a `Vec<Vec<T>>` (for list_of).",
3289 method.ident, type_ident
3290 ),
3291 ));
3292 }
3293
3294 if method.env.is_instance() {
3296 let receiver_spelling = match method.env {
3297 ReceiverKind::Ref => "&self",
3298 ReceiverKind::RefMut => "&mut self",
3299 ReceiverKind::Value => "self",
3300 ReceiverKind::ExternalPtrRef => "self: ExternalPtrRef<'_, Self>",
3301 ReceiverKind::ExternalPtrMut => "self: ExternalPtrMut<'_, Self>",
3302 ReceiverKind::ExternalPtrValue => "self: ExternalPtr<Self>",
3303 ReceiverKind::None => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
3304 };
3305 return Err(syn::Error::new_spanned(
3306 &method.ident,
3307 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[MXL120] vctrs impl method `{0}` uses a `{1}` receiver, which is not supported on `#[miniextendr(vctrs(...))]` impls.\n\nA vctrs object is an S3-classed base vector (REALSXP, INTSXP, etc.). There is no Rust `Self` stored inside the R SEXP — the vector payload IS the R object. The C wrapper cannot reconstruct `Self` from a base vector, so calling an instance method would panic at runtime.\n\nFix: convert this method to a static method whose parameters receive the vector data directly. For example:\n\n// Before (broken):\n// pub fn value(&self) -> f64 {{ ... }}\n\n// After (correct):\n// pub fn value(amounts: Vec<f64>) -> Vec<f64> {{ ... }}",
method.ident, receiver_spelling))
})format!(
3308 "[MXL120] vctrs impl method `{}` uses a `{}` receiver, which is not \
3309 supported on `#[miniextendr(vctrs(...))]` impls.\n\
3310 \n\
3311 A vctrs object is an S3-classed base vector (REALSXP, INTSXP, etc.). \
3312 There is no Rust `Self` stored inside the R SEXP — the vector payload \
3313 IS the R object. The C wrapper cannot reconstruct `Self` from a base \
3314 vector, so calling an instance method would panic at runtime.\n\
3315 \n\
3316 Fix: convert this method to a static method whose parameters receive \
3317 the vector data directly. For example:\n\
3318 \n\
3319 // Before (broken):\n\
3320 // pub fn value(&self) -> f64 {{ ... }}\n\
3321 \n\
3322 // After (correct):\n\
3323 // pub fn value(amounts: Vec<f64>) -> Vec<f64> {{ ... }}",
3324 method.ident, receiver_spelling
3325 ),
3326 ));
3327 }
3328 }
3329 }
3330
3331 let cfg_attrs: Vec<_> = item_impl
3333 .attrs
3334 .iter()
3335 .filter(|attr| attr.path().is_ident("cfg"))
3336 .cloned()
3337 .collect();
3338 let raw_doc_tags = crate::roxygen::roxygen_tags_from_attrs(&item_impl.attrs, class_page);
3339 let (doc_tags, param_warnings) = if attrs.class_system == ClassSystem::R6 {
3344 crate::roxygen::strip_method_tags_r6(
3345 &raw_doc_tags,
3346 &type_ident.to_string(),
3347 item_impl.impl_token.span,
3348 )
3349 } else {
3350 crate::roxygen::strip_method_tags(
3351 &raw_doc_tags,
3352 &type_ident.to_string(),
3353 item_impl.impl_token.span,
3354 )
3355 };
3356 let class_param_names = crate::roxygen::extract_param_names(&doc_tags);
3359
3360 let parsed = ParsedImpl {
3361 type_ident,
3362 class_system: attrs.class_system,
3363 class_name: attrs.class_name,
3364 doc_tags,
3365 methods,
3366 original_impl: rewrite_external_ptr_receivers(strip_miniextendr_attrs_from_impl(
3369 original_impl,
3370 )),
3371 cfg_attrs,
3372 vctrs_attrs: attrs.vctrs_attrs,
3373 r6_inherit: attrs.r6_inherit,
3374 r6_portable: attrs.r6_portable,
3375 r6_cloneable: attrs.r6_cloneable,
3376 r6_lock_objects: attrs.r6_lock_objects,
3377 r6_lock_class: attrs.r6_lock_class,
3378 s7_parent: attrs.s7_parent,
3379 s7_abstract: attrs.s7_abstract,
3380 r_data_accessors: attrs.r_data_accessors,
3381 field_lookup: attrs.field_lookup,
3382 field_fallback: attrs.field_fallback,
3383 strict: attrs.strict,
3384 preconditions: attrs.preconditions,
3385 internal: attrs.internal,
3386 noexport: attrs.noexport,
3387 constructor_demoted: false,
3388 param_warnings,
3389 class_param_names,
3390 };
3391 parsed.check_constructor_markers()?;
3392 parsed.reject_unsupported_describe_in()?;
3393 field_syntax::check_collisions(&parsed)?;
3394 Ok(parsed)
3395 }
3396
3397 fn reject_unsupported_describe_in(&self) -> syn::Result<()> {
3417 for method in self.included_methods() {
3418 if crate::roxygen::describe_in_topic(&method.doc_tags).is_none() {
3419 continue;
3420 }
3421 let is_ctor = self.is_method_constructor(method);
3422 let is_static = method.env == ReceiverKind::None && !is_ctor;
3423 let supported = match self.class_system {
3424 ClassSystem::S3 | ClassSystem::Vctrs => !is_ctor,
3425 ClassSystem::S4 => is_ctor || is_static,
3426 ClassSystem::S7 => is_static,
3427 ClassSystem::Env | ClassSystem::R6 => false,
3428 };
3429 if supported {
3430 continue;
3431 }
3432 let kind = if is_ctor {
3433 "constructor"
3434 } else if is_static {
3435 "static method"
3436 } else {
3437 "instance method"
3438 };
3439 let system = match self.class_system {
3440 ClassSystem::S3 => "S3",
3441 ClassSystem::Vctrs => "vctrs",
3442 ClassSystem::S4 => "S4",
3443 ClassSystem::S7 => "S7",
3444 ClassSystem::Env => "Env",
3445 ClassSystem::R6 => "R6",
3446 };
3447 return Err(syn::Error::new_spanned(
3448 &method.ident,
3449 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`@describeIn` is not supported on the {1} {2} `{0}`: its R wrapper is not an R function roxygen2 can list in the destination\'s \"Functions\" section, so roxygen2 would drop the block. Use `@rdname <topic>` to document it on that page instead. `@describeIn` works on S3 instance methods, on the static methods of S3, S4, S7 and vctrs classes, and on S4 constructors.",
method.ident, system, kind))
})format!(
3450 "`@describeIn` is not supported on the {system} {kind} `{}`: its R wrapper \
3451 is not an R function roxygen2 can list in the destination's \"Functions\" \
3452 section, so roxygen2 would drop the block. Use `@rdname <topic>` to \
3453 document it on that page instead. `@describeIn` works on S3 instance \
3454 methods, on the static methods of S3, S4, S7 and vctrs classes, and on \
3455 S4 constructors.",
3456 method.ident,
3457 ),
3458 ));
3459 }
3460 Ok(())
3461 }
3462
3463 pub fn class_name(&self) -> String {
3465 self.class_name
3466 .clone()
3467 .unwrap_or_else(|| self.type_ident.to_string())
3468 }
3469
3470 pub fn class_settings(&self) -> String {
3479 let mut options: Vec<String> = Vec::new();
3480 match self.class_system {
3481 ClassSystem::Vctrs => {
3482 let vctrs = &self.vctrs_attrs;
3483 let kind = match vctrs.kind {
3484 VctrsKind::Vctr => "vctr",
3485 VctrsKind::Rcrd => "rcrd",
3486 VctrsKind::ListOf => "list_of",
3487 };
3488 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("kind = {0:?}", kind))
})format!("kind = {kind:?}"));
3489 if let Some(base) = &vctrs.base {
3490 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("base = {0:?}", base))
})format!("base = {base:?}"));
3491 }
3492 if let Some(inherit) = vctrs.inherit_base_type {
3493 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("inherit_base_type = {0}", inherit))
})format!("inherit_base_type = {inherit}"));
3494 }
3495 if let Some(ptype) = &vctrs.ptype {
3496 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("ptype = {0:?}", ptype))
})format!("ptype = {ptype:?}"));
3497 }
3498 if let Some(abbr) = &vctrs.abbr {
3499 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("abbr = {0:?}", abbr))
})format!("abbr = {abbr:?}"));
3500 }
3501 }
3502 ClassSystem::R6 => {
3503 if let Some(inherit) = &self.r6_inherit {
3504 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("inherit = {0:?}", inherit))
})format!("inherit = {inherit:?}"));
3505 }
3506 for (name, value) in [
3507 ("portable", self.r6_portable),
3508 ("cloneable", self.r6_cloneable),
3509 ("lock_objects", self.r6_lock_objects),
3510 ("lock_class", self.r6_lock_class),
3511 ] {
3512 if let Some(value) = value {
3513 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} = {1}", name, value))
})format!("{name} = {value}"));
3514 }
3515 }
3516 }
3517 ClassSystem::S7 => {
3518 if let Some(parent) = &self.s7_parent {
3519 options.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("parent = {0:?}", parent))
})format!("parent = {parent:?}"));
3520 }
3521 if self.s7_abstract {
3522 options.push("abstract".to_string());
3523 }
3524 }
3525 ClassSystem::Env | ClassSystem::S3 | ClassSystem::S4 => {}
3526 }
3527 match self.r_data_accessors {
3528 RDataAccessors::Off => {}
3529 RDataAccessors::GetSet => options.push("r_data_accessors".to_string()),
3530 RDataAccessors::GetOnly => options.push("r_data_accessors = \"get\"".to_string()),
3531 }
3532 if self.field_lookup == FieldLookup::List {
3533 options.push("lookup = \"list\"".to_string());
3534 }
3535
3536 let system = self.class_system.to_ident().to_string();
3537 let mut settings = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[if options.is_empty() {
system
} else {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}({0})",
options.join(", "), system))
})
}]))vec![if options.is_empty() {
3538 system
3539 } else {
3540 format!("{system}({})", options.join(", "))
3541 }];
3542 if let Some(class_name) = &self.class_name {
3543 settings.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("class = {0:?}", class_name))
})format!("class = {class_name:?}"));
3544 }
3545 if self.internal {
3546 settings.push("internal".to_string());
3547 }
3548 if self.noexport {
3549 settings.push("noexport".to_string());
3550 }
3551 for tag in CLASS_SETTING_TAGS {
3552 if crate::roxygen::has_roxygen_tag(&self.doc_tags, tag) {
3553 settings.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("@{0}", tag))
})format!("@{tag}"));
3554 }
3555 }
3556 settings.join(", ")
3557 }
3558
3559 pub fn class_definitions(&self) -> Vec<String> {
3566 let mut definitions = Vec::new();
3567 if self.declared_constructor().is_some() {
3568 definitions.push("a constructor".to_string());
3569 } else if let Some(inferred) = self.inferred_constructor() {
3570 definitions.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the inferred constructor `{0}`",
inferred.ident))
})format!("the inferred constructor `{}`", inferred.ident));
3571 }
3572 if self.class_system == ClassSystem::S7
3573 && self.included_methods().any(|m| {
3574 let s7 = &m.method_attrs.s7;
3575 s7.getter || s7.setter || s7.validate
3576 })
3577 {
3578 definitions.push("S7 properties".to_string());
3579 }
3580 if self.field_fallback.is_some() {
3581 definitions.push("the field fallback".to_string());
3582 }
3583 definitions
3584 }
3585
3586 pub fn included_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3588 self.methods.iter().filter(|m| m.should_include())
3589 }
3590
3591 pub fn constructor(&self) -> Option<&ParsedMethod> {
3596 self.declared_constructor()
3597 .or_else(|| self.inferred_constructor())
3598 }
3599
3600 pub fn declared_constructor(&self) -> Option<&ParsedMethod> {
3609 self.included_methods()
3610 .find(|m| m.method_attrs.constructor)
3611 .or_else(|| {
3612 self.included_methods().find(|m| {
3613 m.env == ReceiverKind::None
3614 && m.ident == "new"
3615 && (self.class_system == ClassSystem::Vctrs || m.returns_self())
3616 })
3617 })
3618 }
3619
3620 pub fn constructor_candidates(&self) -> impl Iterator<Item = &ParsedMethod> {
3628 let declared = self.declared_constructor();
3629 self.included_methods().filter(move |m| {
3630 self.class_system != ClassSystem::Vctrs
3631 && m.env == ReceiverKind::None
3632 && m.returns_self()
3633 && m.method_attrs.s7.convert_from.is_none()
3634 && !declared.is_some_and(|d| std::ptr::eq(d, *m))
3635 })
3636 }
3637
3638 pub fn inferred_constructor(&self) -> Option<&ParsedMethod> {
3645 if self.constructor_demoted || self.declared_constructor().is_some() {
3646 return None;
3647 }
3648 let mut candidates = self.constructor_candidates();
3649 let first = candidates.next()?;
3650 candidates.next().is_none().then_some(first)
3651 }
3652
3653 fn is_method_constructor(&self, m: &ParsedMethod) -> bool {
3655 self.constructor().is_some_and(|c| std::ptr::eq(c, m))
3656 }
3657
3658 fn static_doc_tags<'a>(
3666 &self,
3667 m: &'a ParsedMethod,
3668 call: &str,
3669 constructor: &str,
3670 params: bool,
3671 ) -> std::borrow::Cow<'a, [String]> {
3672 if !self.is_method_constructor(m) {
3673 return std::borrow::Cow::Borrowed(&m.doc_tags);
3674 }
3675 let kept = |tag: &&String| {
3676 let name = tag.split_whitespace().next().unwrap_or("");
3677 name == "@noRd" || name == "@keywords" || (params && name == "@param")
3678 };
3679 let mut tags = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[::alloc::__export::must_use({
::alloc::fmt::format(format_args!("@description `{0}` is another name for the constructor `{1}`.",
call, constructor))
})]))vec![format!(
3680 "@description `{call}` is another name for the constructor `{constructor}`."
3681 )];
3682 tags.extend(m.doc_tags.iter().filter(kept).cloned());
3683 std::borrow::Cow::Owned(tags)
3684 }
3685
3686 fn check_constructor_markers(&self) -> syn::Result<()> {
3689 let marker = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#[miniextendr({0}(constructor))]",
self.class_system.to_ident()))
})format!(
3690 "#[miniextendr({}(constructor))]",
3691 self.class_system.to_ident()
3692 );
3693 let mut marked = self
3694 .included_methods()
3695 .filter(|m| m.method_attrs.constructor);
3696 if let (Some(first), Some(second)) = (marked.next(), marked.next()) {
3697 return Err(syn::Error::new_spanned(
3698 &second.ident,
3699 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` and `{1}` are both marked `{2}`; a class has one constructor. Drop the marker from one: it becomes a static method.",
first.ident, second.ident, marker))
})format!(
3700 "`{}` and `{}` are both marked `{marker}`; a class has one constructor. \
3701 Drop the marker from one: it becomes a static method.",
3702 first.ident, second.ident,
3703 ),
3704 ));
3705 }
3706 Ok(())
3707 }
3708
3709 pub fn public_instance_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3712 self.methods.iter().filter(|m| {
3713 m.should_include()
3714 && m.env.is_instance()
3715 && !m.is_constructor()
3716 && !m.is_finalizer()
3717 && !m.method_attrs.r6.deep_clone
3718 && !m.is_private()
3719 && !m.is_active()
3720 })
3721 }
3722
3723 pub fn private_instance_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3725 self.methods.iter().filter(|m| {
3726 m.should_include()
3727 && m.env.is_instance()
3728 && !m.is_constructor()
3729 && !m.is_finalizer()
3730 && m.is_private()
3731 && !m.is_active()
3732 })
3733 }
3734
3735 pub fn active_instance_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3738 self.methods.iter().filter(|m| {
3739 m.should_include()
3740 && m.env.is_instance()
3741 && !m.is_constructor()
3742 && !m.is_finalizer()
3743 && m.is_active()
3744 && !m.method_attrs.r6.setter })
3746 }
3747
3748 pub fn active_setter_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3750 self.methods
3751 .iter()
3752 .filter(|m| m.should_include() && m.env.is_instance() && m.method_attrs.r6.setter)
3753 }
3754
3755 pub fn find_setter_for_prop(&self, prop_name: &str) -> Option<&ParsedMethod> {
3757 self.active_setter_methods().find(|m| {
3758 if let Some(ref explicit_prop) = m.method_attrs.r6.prop {
3760 explicit_prop == prop_name
3761 } else {
3762 let method_name = crate::naming::ident_name(&m.ident);
3764 method_name.strip_prefix("set_").unwrap_or(&method_name) == prop_name
3765 }
3766 })
3767 }
3768
3769 pub fn instance_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3771 self.methods.iter().filter(|m| {
3772 m.should_include() && m.env.is_instance() && !m.is_constructor() && !m.is_finalizer()
3773 })
3774 }
3775
3776 pub fn static_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3780 self.methods.iter().filter(|m| {
3781 m.should_include()
3782 && m.env == ReceiverKind::None
3783 && (!self.is_method_constructor(m) || self.constructor_keeps_own_name(m))
3784 && !m.is_finalizer()
3785 })
3786 }
3787
3788 fn constructor_keeps_own_name(&self, m: &ParsedMethod) -> bool {
3794 self.class_system != ClassSystem::Vctrs && m.r_method_name() != "new"
3795 }
3796
3797 pub fn as_coercion_methods(&self) -> impl Iterator<Item = &ParsedMethod> {
3802 self.methods
3803 .iter()
3804 .filter(|m| m.should_include() && m.method_attrs.as_coercion.is_some())
3805 }
3806
3807 pub fn finalizer(&self) -> Option<&ParsedMethod> {
3809 self.methods
3810 .iter()
3811 .find(|m| m.should_include() && m.is_finalizer())
3812 }
3813}
3814
3815pub fn generate_method_c_wrapper(parsed_impl: &ParsedImpl, method: &ParsedMethod) -> TokenStream {
3838 use crate::c_wrapper_builder::{CWrapperContext, ReturnHandling, ThreadStrategy};
3839
3840 let type_ident = &parsed_impl.type_ident;
3841 let method_ident = &method.ident;
3842 let c_ident = method.c_wrapper_ident(type_ident);
3843 let self_sexp = crate::naming::self_sexp_ident();
3844 let self_ptr = syn::Ident::new("self_ptr", proc_macro2::Span::mixed_site());
3845 let self_ref = syn::Ident::new("self_ref", proc_macro2::Span::mixed_site());
3846 let self_slot = syn::Ident::new("self_slot", proc_macro2::Span::mixed_site());
3847 let external_ptr = syn::Ident::new("__self_ptr", proc_macro2::Span::mixed_site());
3848 let taken = syn::Ident::new("__mx_taken", proc_macro2::Span::mixed_site());
3849
3850 let thread_strategy = if method.method_attrs.unsafe_main_thread
3857 || method.env.is_instance()
3858 || method.has_dots
3859 || method.method_attrs.check_interrupt
3860 || method.rng_guard.is_some()
3861 || crate::type_inspect::signature_holds_r_values(&method.sig)
3862 {
3863 ThreadStrategy::MainThread
3864 } else if method.method_attrs.worker {
3865 ThreadStrategy::WorkerThread
3866 } else {
3867 ThreadStrategy::MainThread
3868 };
3869
3870 let mut rust_args: Vec<TokenStream> = method
3873 .sig
3874 .inputs
3875 .iter()
3876 .filter_map(|arg| {
3877 if let syn::FnArg::Typed(pt) = arg
3878 && let syn::Pat::Ident(pat_ident) = pt.pat.as_ref()
3879 {
3880 let ident = &pat_ident.ident;
3881 Some({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ident, &mut _s);
_s
}quote! { #ident })
3882 } else {
3883 None
3884 }
3885 })
3886 .collect();
3887 if let Some(index) = method.rng_guard {
3888 rust_args.insert(index, crate::type_inspect::rng_guard_arg());
3889 }
3890
3891 #[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ValueMode { }
#[automatically_derived]
impl ::core::clone::Clone for ValueMode {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ValueMode { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ValueMode { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ValueMode {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ValueMode { }Eq)]
3893 enum ValueMode {
3894 WriteBack,
3896 Fallible,
3898 Terminal,
3900 }
3901 let value_mode = if method.returns_self() {
3902 ValueMode::WriteBack
3903 } else if method.returns_result_self() || method.returns_option_self() {
3904 ValueMode::Fallible
3905 } else {
3906 ValueMode::Terminal
3907 };
3908
3909 let (pre_call, post_conversion) = if method.env.is_instance() {
3917 let owner = syn::Ident::new("__mx_owner", proc_macro2::Span::mixed_site());
3918 let cell = syn::Ident::new("__mx_cell", proc_macro2::Span::mixed_site());
3919 let guard = syn::Ident::new("__mx_guard", proc_macro2::Span::mixed_site());
3920 let resolve = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&owner, &mut _s);
::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, "ReceiverOwner");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "resolve");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_sexp, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3921 let #owner =
3922 ::miniextendr_api::externalptr::ReceiverOwner::resolve::<#type_ident>(#self_sexp);
3923 };
3924 let cell_lookup = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&resolve, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedExternalPtr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "downcast_cell");
::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_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, "cell");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "cell");
::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_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, "handle_downcast_failed");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3927 #resolve
3928 let #self_ptr = unsafe {
3929 ::miniextendr_api::externalptr::ErasedExternalPtr::from_sexp(#owner.get())
3930 };
3931 let #cell = match #self_ptr.downcast_cell::<#type_ident>() {
3932 ::core::option::Option::Some(cell) => cell,
3933 ::core::option::Option::None => ::miniextendr_api::externalptr::handle_downcast_failed::<#type_ident>(&#self_ptr),
3934 };
3935 };
3936 let (lookup, borrow) = match method.env {
3937 ReceiverKind::RefMut => (
3938 cell_lookup,
3939 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::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, "borrow_value_mut");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3940 let mut #guard = ::miniextendr_api::externalptr::borrow_value_mut(#cell);
3941 let #self_ref = &mut *#guard;
3942 },
3943 ),
3944 ReceiverKind::Ref => (
3945 cell_lookup,
3946 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::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, "borrow_value");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3947 let #guard = ::miniextendr_api::externalptr::borrow_value(#cell);
3948 let #self_ref = &*#guard;
3949 },
3950 ),
3951 ReceiverKind::Value => match value_mode {
3952 ValueMode::Fallible => (
3956 cell_lookup,
3957 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&self_slot, &mut _s);
::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, "borrow_value_mut");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3958 let mut #self_slot = ::miniextendr_api::externalptr::borrow_value_mut(#cell);
3959 },
3960 ),
3961 ValueMode::WriteBack | ValueMode::Terminal => (
3966 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&resolve, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ErasedExternalPtr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3967 #resolve
3968 let mut #self_ptr = unsafe {
3969 ::miniextendr_api::externalptr::ErasedExternalPtr::from_sexp(#owner.get())
3970 };
3971 },
3972 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&taken, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "take_for_consuming");
::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_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_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, "handle_downcast_failed");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3973 let #taken = match #self_ptr.take_for_consuming::<#type_ident>() {
3974 ::core::option::Option::Some(v) => v,
3975 ::core::option::Option::None => ::miniextendr_api::externalptr::handle_downcast_failed::<#type_ident>(&#self_ptr),
3976 };
3977 },
3978 ),
3979 },
3980 ReceiverKind::ExternalPtrRef => (
3983 cell_lookup,
3984 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ExternalPtrRef");
::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, "from_raw_parts");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "owner");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3985 let #self_ref = unsafe {
3986 ::miniextendr_api::ExternalPtrRef::<#type_ident>::from_raw_parts(
3987 #owner.owner(),
3988 #cell,
3989 )
3990 };
3991 },
3992 ),
3993 ReceiverKind::ExternalPtrMut => (
3994 cell_lookup,
3995 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ExternalPtrMut");
::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, "from_raw_parts");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "owner");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
3996 let #self_ref = unsafe {
3997 ::miniextendr_api::ExternalPtrMut::<#type_ident>::from_raw_parts(
3998 #owner.owner(),
3999 #cell,
4000 )
4001 };
4002 },
4003 ),
4004 ReceiverKind::ExternalPtrValue => (
4007 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&resolve, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&external_ptr, &mut _s);
::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, "wrap_receiver");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&owner, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
4008 #resolve
4009 let #external_ptr =
4010 ::miniextendr_api::externalptr::wrap_receiver::<#type_ident>(#owner.get());
4011 },
4012 TokenStream::new(),
4013 ),
4014 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
4015 };
4016 (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[lookup]))vec![lookup], ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[borrow]))vec![borrow])
4017 } else {
4018 (::alloc::vec::Vec::new()vec![], ::alloc::vec::Vec::new()vec![])
4019 };
4020
4021 let fallible_self_ref = method.env.is_instance()
4025 && !#[allow(non_exhaustive_omitted_patterns)] match method.env {
ReceiverKind::Value => true,
_ => false,
}matches!(method.env, ReceiverKind::Value)
4026 && (method.returns_result_self_ref() || method.returns_option_self_ref());
4027
4028 let unwrap_marker = |call: TokenStream| -> TokenStream {
4033 let call = crate::type_inspect::prepare_return_value(
4034 call,
4035 method.visibility_marker,
4036 method.method_attrs.serialize,
4037 );
4038 match &method.return_wrap {
4039 Some(wrap) => wrap.prepare_value(call),
4040 None => call,
4041 }
4042 };
4043 let call_expr = match method.env {
4044 ReceiverKind::Ref | ReceiverKind::RefMut if fallible_self_ref => {
4045 let call = unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #self_ref.#method_ident(#(#rust_args),*) });
4046 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&call, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "map");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or(&mut _s);
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_or(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
}quote! { #call.map(|_| ()) }
4047 }
4048 ReceiverKind::Ref | ReceiverKind::RefMut => {
4049 unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #self_ref.#method_ident(#(#rust_args),*) })
4050 }
4051 ReceiverKind::Value => match value_mode {
4052 ValueMode::WriteBack => {
4053 let call =
4054 unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&taken, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #type_ident::#method_ident(#taken, #(#rust_args),*) });
4055 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__mx_out");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&call, &mut _s);
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&self_ptr, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s,
"restore_after_consuming");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__mx_out");
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
_s
}quote! {{
4056 let __mx_out = #call;
4057 #self_ptr.restore_after_consuming::<#type_ident>(__mx_out);
4058 }}
4059 }
4060 ValueMode::Fallible => {
4061 let call = unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_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, "clone_for_consuming");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&self_slot, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! {
4062 #type_ident::#method_ident(
4063 ::miniextendr_api::externalptr::clone_for_consuming::<#type_ident>(&*#self_slot),
4064 #(#rust_args),*
4065 )
4066 });
4067 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&call, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "map");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or(&mut _s);
::quote::__private::push_ident(&mut _s, "__mx_v");
::quote::__private::push_or(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&self_slot, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "__mx_v");
::quote::__private::push_semi(&mut _s);
_s
});
_s
});
_s
}quote! { #call.map(|__mx_v| { *#self_slot = __mx_v; }) }
4068 }
4069 ValueMode::Terminal => {
4070 unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&taken, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #type_ident::#method_ident(#taken, #(#rust_args),*) })
4071 }
4072 },
4073 ReceiverKind::ExternalPtrRef | ReceiverKind::ExternalPtrMut => {
4074 unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #type_ident::#method_ident(#self_ref, #(#rust_args),*) })
4075 }
4076 ReceiverKind::ExternalPtrValue => {
4077 unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&external_ptr, &mut _s);
::quote::__private::push_comma(&mut _s);
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #type_ident::#method_ident(#external_ptr, #(#rust_args),*) })
4078 }
4079 ReceiverKind::None => unwrap_marker({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rust_args, i) = rust_args.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rust_args =
match rust_args.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&rust_args, &mut _s);
}
}
_s
});
_s
}quote! { #type_ident::#method_ident(#(#rust_args),*) }),
4080 };
4081
4082 let return_handling = if method.env == ReceiverKind::Value && value_mode == ValueMode::WriteBack
4084 {
4085 ReturnHandling::SelfHandle
4088 } else if (method.env == ReceiverKind::Value && value_mode == ValueMode::Fallible)
4089 || fallible_self_ref
4090 {
4091 if method.returns_result_self() || method.returns_result_self_ref() {
4094 ReturnHandling::SelfHandleResult
4095 } else {
4096 ReturnHandling::SelfHandleOption
4097 }
4098 } else if method.returns_self() {
4099 ReturnHandling::ExternalPtr
4100 } else if method.returns_self_ref() && method.env.is_instance() {
4101 ReturnHandling::SelfHandle
4106 } else if method.method_attrs.unwrap_in_r
4107 && crate::return_type_analysis::output_is_result(&method.sig.output)
4108 {
4109 ReturnHandling::IntoR
4110 } else {
4111 crate::c_wrapper_builder::detect_return_handling(
4112 &method.sig.output,
4113 method.return_wrap.as_ref(),
4114 )
4115 };
4116
4117 let mut builder = CWrapperContext::builder(method_ident.clone(), c_ident)
4119 .r_name(method.r_method_name())
4120 .inputs(method.sig.inputs.clone())
4121 .output(method.sig.output.clone())
4122 .pre_call(pre_call)
4123 .post_conversion(post_conversion)
4124 .call_expr(call_expr)
4125 .thread_strategy(thread_strategy)
4126 .return_handling(return_handling)
4127 .err_parts(crate::c_wrapper_builder::ErrPartsMode::from_spec(
4128 method
4129 .method_attrs
4130 .serde_error
4131 .as_ref()
4132 .map(|spec| spec.with_self_type(type_ident))
4133 .as_ref(),
4134 ))
4135 .cfg_attrs(parsed_impl.cfg_attrs.clone())
4136 .type_context(type_ident.clone())
4137 .formals(method.formals());
4138
4139 if method.env.is_instance() {
4140 builder = builder.has_self();
4141 }
4142
4143 if method.method_attrs.coerce {
4144 builder = builder.coerce_all();
4145 }
4146
4147 if method.method_attrs.check_interrupt {
4148 builder = builder.check_interrupt();
4149 }
4150
4151 if method.method_attrs.rng {
4152 builder = builder.rng();
4153 }
4154
4155 if parsed_impl.strict {
4156 builder = builder.strict();
4157 }
4158
4159 for (rust_name, attrs) in &method.method_attrs.per_param {
4169 if let Some(leaf) = attrs.layered_leaf() {
4170 builder = builder.layered_choice(rust_name.clone(), leaf);
4171 } else if attrs.match_arg && attrs.several_ok {
4172 builder = builder.match_arg_several_ok(rust_name.clone());
4173 }
4174 if attrs.checks.no_na {
4175 builder = builder.no_na(rust_name.clone(), attrs.checks.no_na_message.clone());
4176 }
4177 }
4178 for (rust_name, markers) in &method.param_markers {
4181 builder = builder.param_markers(rust_name.clone(), markers.clone());
4182 }
4183
4184 let c_wrapper_and_def = builder.build().generate();
4185
4186 let match_arg_entries = generate_method_match_arg_entries(parsed_impl, method);
4187
4188 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&c_wrapper_and_def, &mut _s);
::quote::ToTokens::to_tokens(&match_arg_entries, &mut _s);
_s
}quote! {
4189 #c_wrapper_and_def
4190 #match_arg_entries
4191 }
4192}
4193
4194fn generate_method_match_arg_entries(
4197 parsed_impl: &ParsedImpl,
4198 method: &ParsedMethod,
4199) -> TokenStream {
4200 if !method.method_attrs.per_param.values().any(|a| a.match_arg) {
4201 return TokenStream::new();
4202 }
4203
4204 let type_ident = &parsed_impl.type_ident;
4205 let c_ident = method.c_wrapper_ident(type_ident);
4206 let c_ident_str = c_ident.to_string();
4207 let cfg_attrs = &parsed_impl.cfg_attrs;
4208
4209 let mut out = TokenStream::new();
4210
4211 for (rust_name, attrs) in crate::miniextendr_fn::per_param_in_signature_order(
4213 &method.sig.inputs,
4214 &method.method_attrs.per_param,
4215 ) {
4216 if !attrs.match_arg {
4217 continue;
4218 }
4219 let Some(param_ty) = find_param_type(&method.sig.inputs, rust_name) else {
4221 continue;
4222 };
4223 let several_ok = attrs.several_ok;
4227 let choices_ty = crate::match_arg_choices_ty(param_ty, several_ok).clone();
4228
4229 let key = crate::match_arg_keys::param_key(rust_name);
4230
4231 let placeholder = crate::r_class_formatter::match_arg_placeholder(&c_ident_str, &key);
4234 let entry_ident = syn::Ident::new(
4235 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("match_arg_choices_entry_{0}",
crate::match_arg_keys::placeholder_ident_suffix(&placeholder)))
})format!(
4236 "match_arg_choices_entry_{}",
4237 crate::match_arg_keys::placeholder_ident_suffix(&placeholder)
4238 ),
4239 proc_macro2::Span::call_site(),
4240 );
4241 let doc_placeholder =
4242 crate::r_class_formatter::match_arg_param_doc_placeholder(&c_ident_str, &key);
4243 let doc_entry_ident = syn::Ident::new(
4244 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("match_arg_param_doc_entry_{0}",
crate::match_arg_keys::placeholder_ident_suffix(&doc_placeholder)))
})format!(
4245 "match_arg_param_doc_entry_{}",
4246 crate::match_arg_keys::placeholder_ident_suffix(&doc_placeholder)
4247 ),
4248 proc_macro2::Span::call_site(),
4249 );
4250
4251 let preferred_default = attrs
4252 .default
4253 .as_deref()
4254 .map(crate::match_arg_keys::extract_match_arg_default)
4255 .unwrap_or_default();
4256 let aliases_placeholder = crate::match_arg_keys::aliases_placeholder(&c_ident_str, &key);
4257 let choices_entry_tokens = crate::match_arg_keys::choices_entry_tokens(
4258 cfg_attrs,
4259 &entry_ident,
4260 &placeholder,
4261 &aliases_placeholder,
4262 &choices_ty,
4263 &preferred_default,
4264 );
4265 let param_doc_entry_tokens = crate::match_arg_keys::param_doc_entry_tokens(
4266 cfg_attrs,
4267 &doc_entry_ident,
4268 &doc_placeholder,
4269 several_ok,
4270 &attrs.choice_doc_suffix(),
4271 &choices_ty,
4272 );
4273
4274 out.extend({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&choices_entry_tokens, &mut _s);
::quote::ToTokens::to_tokens(¶m_doc_entry_tokens, &mut _s);
_s
}quote! {
4275 #choices_entry_tokens
4276 #param_doc_entry_tokens
4277 });
4278 }
4279
4280 out
4281}
4282
4283fn find_param_type<'a>(
4285 inputs: &'a syn::punctuated::Punctuated<syn::FnArg, ::syn::token::Commasyn::Token![,]>,
4286 name: &str,
4287) -> Option<&'a syn::Type> {
4288 for arg in inputs {
4289 if let syn::FnArg::Typed(pt) = arg
4290 && let syn::Pat::Ident(pat_ident) = pt.pat.as_ref()
4291 && crate::naming::unraw(&pat_ident.ident) == name
4292 {
4293 return Some(pt.ty.as_ref());
4294 }
4295 }
4296 None
4297}
4298
4299fn vctrs_ctor_returns_self_or_type(output: &syn::ReturnType, type_ident: &syn::Ident) -> bool {
4306 let syn::ReturnType::Type(_, ty) = output else {
4307 return false;
4308 };
4309 ty_is_self_or_named(ty.as_ref(), type_ident)
4310}
4311
4312fn ty_is_self_or_named(ty: &syn::Type, type_ident: &syn::Ident) -> bool {
4315 match ty {
4316 syn::Type::Path(p) => {
4317 let last = match p.path.segments.last() {
4318 Some(s) => s,
4319 None => return false,
4320 };
4321 if last.ident == "Self" || last.ident == *type_ident {
4323 return true;
4324 }
4325 if last.ident == "Result"
4327 && let syn::PathArguments::AngleBracketed(ref args) = last.arguments
4328 && let Some(syn::GenericArgument::Type(first_ty)) = args.args.first()
4329 {
4330 return ty_is_self_or_named(first_ty, type_ident);
4331 }
4332 if last.ident == "Box"
4334 && let syn::PathArguments::AngleBracketed(ref args) = last.arguments
4335 && let Some(syn::GenericArgument::Type(inner)) = args.args.first()
4336 {
4337 return ty_is_self_or_named(inner, type_ident);
4338 }
4339 false
4340 }
4341 syn::Type::Reference(r) => ty_is_self_or_named(r.elem.as_ref(), type_ident),
4343 _ => false,
4344 }
4345}
4346
4347mod env_class;
4351mod field_syntax;
4353mod r6_class;
4355mod s3_class;
4357pub(crate) mod s4_class;
4359pub(crate) mod s7_class;
4361mod vctrs_class;
4363
4364pub(crate) use env_class::generate_env_class;
4365#[cfg(test)]
4366pub(crate) use env_class::generate_env_r_wrapper;
4367pub(crate) use r6_class::generate_r6_class;
4368#[cfg(test)]
4369pub(crate) use r6_class::generate_r6_r_wrapper;
4370pub(crate) use s3_class::generate_s3_class;
4371#[cfg(test)]
4372pub(crate) use s3_class::generate_s3_r_wrapper;
4373pub(crate) use s4_class::generate_s4_class;
4374#[cfg(test)]
4375pub(crate) use s4_class::generate_s4_r_wrapper;
4376pub(crate) use s7_class::generate_s7_class;
4377#[cfg(test)]
4378pub(crate) use s7_class::generate_s7_r_wrapper;
4379#[cfg(test)]
4380use s7_class::rust_type_to_s7_class;
4381pub(crate) use vctrs_class::generate_vctrs_class;
4382#[cfg(test)]
4383pub(crate) use vctrs_class::generate_vctrs_r_wrapper;
4384
4385pub(crate) fn no_constructor_guard(class_name: &str) -> String {
4390 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if (is.null(.ptr)) stop(\"`{0}` has no constructor: its objects come from the functions that return one.\", call. = FALSE)",
class_name))
})format!(
4391 "if (is.null(.ptr)) stop(\"`{class_name}` has no constructor: its objects come from \
4392 the functions that return one.\", call. = FALSE)"
4393 )
4394}
4395
4396pub(crate) const CLASS_DOC_LINES_MARKER: &str = ".__MX_CLASS_DOC_LINES__";
4401
4402pub(crate) const CLASS_DOCS_MARKER: &str = ".__MX_CLASS_DOCS__";
4407
4408pub(crate) const CLASS_DEFAULT_PREFIX: &str = ".__MX_CLASS_DEFAULT__";
4416
4417pub(crate) const CLASS_MEMBER_DEFAULT_PREFIX: &str = ".__MX_CLASS_MEMBER_DEFAULT__";
4423
4424pub(crate) fn member_default(line: impl std::fmt::Display) -> String {
4425 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}",
CLASS_MEMBER_DEFAULT_PREFIX, line))
})format!("{CLASS_MEMBER_DEFAULT_PREFIX}{line}")
4426}
4427
4428pub(crate) fn push_member_rdname(lines: &mut Vec<String>, tags: &[String], class: &str) {
4431 if crate::roxygen::describe_in_topic(tags).is_some()
4432 || crate::roxygen::rdname_value(tags).is_some()
4433 {
4434 crate::roxygen::push_rdname_or_default(lines, tags, class);
4435 } else {
4436 lines.push(member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}", class))
})format!("#' @rdname {class}")));
4437 }
4438}
4439
4440pub(crate) fn class_default(line: impl std::fmt::Display) -> String {
4443 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", CLASS_DEFAULT_PREFIX,
line))
})format!("{CLASS_DEFAULT_PREFIX}{line}")
4444}
4445
4446pub(crate) const CLASS_DOCS_ONLY_MARKER: &str = ".__MX_CLASS_DOCS_ONLY__";
4452
4453pub(crate) fn docs_only_class_block(parsed_impl: &ParsedImpl, kind: &str) -> Vec<String> {
4468 let class_name = parsed_impl.class_name();
4469 let tags = &parsed_impl.doc_tags;
4470 let mut lines = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[CLASS_DOCS_ONLY_MARKER.to_string()]))vec![CLASS_DOCS_ONLY_MARKER.to_string()];
4471 let no_rd = crate::roxygen::has_roxygen_tag(tags, "noRd")
4472 || (parsed_impl.noexport && !parsed_impl.internal);
4473 if no_rd {
4474 if !crate::roxygen::has_roxygen_tag(tags, "noRd") {
4475 lines.push("#' @noRd".to_string());
4476 }
4477 } else {
4478 if let Some(topic) = crate::roxygen::rdname_value(tags) {
4479 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @name {0}", topic))
})format!("#' @name {topic}"));
4480 lines.push("#' @aliases NULL".to_string());
4481 if !crate::roxygen::has_roxygen_tag(tags, "order") {
4482 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' {0}",
crate::roxygen::ORDER_AFTER_TOPIC_BLOCKS))
})format!("#' {}", crate::roxygen::ORDER_AFTER_TOPIC_BLOCKS));
4483 }
4484 } else {
4485 if !crate::roxygen::has_roxygen_tag(tags, "title") {
4487 lines.push(class_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @title {0} {1} Class",
class_name, kind))
})format!(
4488 "#' @title {class_name} {kind} Class"
4489 )));
4490 }
4491 if !crate::roxygen::has_roxygen_tag(tags, "name") {
4492 lines.push(class_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @name {0}", class_name))
})format!("#' @name {class_name}")));
4493 }
4494 }
4495 if parsed_impl.internal && !crate::roxygen::has_roxygen_tag(tags, "keywords internal") {
4496 lines.push("#' @keywords internal".to_string());
4497 }
4498 }
4499 lines.push(CLASS_DOCS_MARKER.to_string());
4500 lines.push("NULL".to_string());
4501 lines
4502}
4503
4504#[cfg(test)]
4507fn class_docs_say_something(class_docs: &[String], class_doc_lines: &[String]) -> bool {
4508 const PAGE_TAGS: &[&str] = &["rdname", "noRd", "keywords", "order", "export"];
4509 !class_doc_lines.is_empty()
4510 || class_docs.iter().any(|line| {
4511 line.strip_prefix("#' @")
4512 .and_then(|rest| rest.split_whitespace().next())
4513 .is_none_or(|tag| !PAGE_TAGS.contains(&tag))
4514 })
4515}
4516
4517#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ClassWrapper {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["head", "class_docs", "class_doc_lines", "members", "tail",
"member_names"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.head, &self.class_docs, &self.class_doc_lines,
&self.members, &self.tail, &&self.member_names];
::core::fmt::Formatter::debug_struct_fields_finish(f, "ClassWrapper",
names, values)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for ClassWrapper {
#[inline]
fn default() -> Self {
ClassWrapper {
head: ::core::default::Default::default(),
class_docs: ::core::default::Default::default(),
class_doc_lines: ::core::default::Default::default(),
members: ::core::default::Default::default(),
tail: ::core::default::Default::default(),
member_names: ::core::default::Default::default(),
}
}
}Default)]
4522pub struct ClassWrapper {
4523 pub head: Vec<String>,
4528 pub class_docs: Vec<String>,
4531 pub class_doc_lines: Vec<String>,
4533 pub members: Vec<String>,
4535 pub tail: Vec<String>,
4537 pub member_names: Vec<String>,
4540}
4541
4542impl ClassWrapper {
4543 fn mark_class_doc_lines(&mut self, head: &mut Vec<String>, parsed_impl: &ParsedImpl) {
4547 let pos = head.len().saturating_sub(1);
4548 head.insert(pos, CLASS_DOC_LINES_MARKER.to_string());
4549 if let Some(import) = crate::lifecycle::collect_lifecycle_imports(
4550 parsed_impl
4551 .methods
4552 .iter()
4553 .filter_map(|m| m.method_attrs.lifecycle.as_ref()),
4554 ) {
4555 self.class_doc_lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' {0}", import))
})format!("#' {import}"));
4556 }
4557 }
4558
4559 #[cfg(test)]
4562 pub fn render(&self) -> String {
4563 let mut lines = Vec::new();
4564 let keep_docs_only = class_docs_say_something(&self.class_docs, &self.class_doc_lines);
4565 let mut skipping = false;
4566 for line in &self.head {
4567 if skipping {
4568 skipping = line != "NULL";
4569 continue;
4570 }
4571 if line == CLASS_DOCS_ONLY_MARKER {
4572 skipping = !keep_docs_only;
4573 } else if line == CLASS_DOCS_MARKER {
4574 lines.extend(self.class_docs.iter().cloned());
4575 } else if line == CLASS_DOC_LINES_MARKER {
4576 lines.extend(self.class_doc_lines.iter().map(|l| strip_class_default(l)));
4577 } else {
4578 lines.push(strip_class_default(line));
4579 }
4580 }
4581 lines.extend(self.members.iter().cloned());
4582 lines.extend(self.tail.iter().cloned());
4583 lines
4584 .join("\n")
4585 .split('\n')
4586 .map(|line| {
4587 line.strip_prefix(CLASS_MEMBER_DEFAULT_PREFIX)
4588 .unwrap_or(line)
4589 })
4590 .collect::<Vec<_>>()
4591 .join("\n")
4592 }
4593}
4594
4595#[cfg(test)]
4598fn strip_class_default(line: &str) -> String {
4599 line.strip_prefix(CLASS_DEFAULT_PREFIX)
4600 .unwrap_or(line)
4601 .to_string()
4602}
4603
4604pub fn generate_as_coercion_methods(parsed_impl: &ParsedImpl) -> String {
4619 use crate::r_class_formatter::MethodContext;
4620
4621 let class_name = parsed_impl.class_name();
4622 let type_ident = &parsed_impl.type_ident;
4623
4624 let class_doc_tags = &parsed_impl.doc_tags;
4626 let class_has_no_rd = crate::roxygen::has_roxygen_tag(class_doc_tags, "noRd");
4627 let class_has_internal = crate::roxygen::has_roxygen_tag(class_doc_tags, "keywords internal")
4628 || parsed_impl.internal;
4629 let should_export = !class_has_no_rd && !class_has_internal && !parsed_impl.noexport;
4630
4631 let mut lines = Vec::new();
4632
4633 for method in parsed_impl.as_coercion_methods() {
4634 let coercion_target = match &method.method_attrs.as_coercion {
4636 Some(target) => target.clone(),
4637 None => continue,
4638 };
4639
4640 let mut ctx = MethodContext::new(method, type_ident)
4642 .with_impl_preconditions(parsed_impl.preconditions);
4643 ctx.args = crate::r_wrapper_builder::RArgumentBuilder::new(&method.sig.inputs)
4647 .with_formals(method.formals())
4648 .build_call_args();
4649
4650 let r_generic = match coercion_target.as_str() {
4658 "numeric" | "double" => "as.double".to_string(),
4659 "tibble" => "as_tibble".to_string(),
4660 "ts" => "as.ts".to_string(),
4661 other => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("as.{0}", other))
})format!("as.{}", other),
4662 };
4663
4664 let s3_method_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.{1}", r_generic, class_name))
})format!("{}.{}", r_generic, class_name);
4666
4667 if !class_has_no_rd {
4669 if !method.doc_tags.is_empty() {
4671 crate::roxygen::push_roxygen_tags(&mut lines, &method.doc_tags);
4672 }
4673 let describe_in = crate::roxygen::describe_in_topic(&method.doc_tags).is_some();
4680 if !describe_in && !crate::roxygen::has_roxygen_tag(&method.doc_tags, "name") {
4681 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @name {0}", s3_method_name))
})format!("#' @name {}", s3_method_name));
4682 }
4683 if !describe_in {
4684 if crate::roxygen::has_roxygen_tag(&method.doc_tags, "rdname") {
4685 if !crate::roxygen::has_roxygen_tag(&method.doc_tags, "title") {
4687 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @title {0}", s3_method_name))
})format!("#' @title {}", s3_method_name));
4688 }
4689 } else {
4690 lines.push(member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}", class_name))
})format!("#' @rdname {}", class_name)));
4691 }
4692 }
4693 crate::roxygen::push_order_after_topic_blocks(
4694 &mut lines,
4695 &method.doc_tags,
4696 &class_name,
4697 );
4698 lines.extend(crate::roxygen::method_source_tag(type_ident, &method.ident));
4699 }
4700
4701 if should_export {
4703 lines.push("#' @export".to_string());
4704 }
4705 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method {0} {1}", r_generic,
class_name))
})format!("#' @method {} {}", r_generic, class_name));
4706
4707 let r_formals = method.formals();
4710 let method_params = crate::r_wrapper_builder::build_r_formals_from_sig(
4711 &method.sig,
4712 &r_formals,
4713 &r_formals.rekey(method.param_defaults.clone()),
4714 );
4715 let formals = if method_params.is_empty() {
4716 "x, ...".to_string()
4717 } else {
4718 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("x, {0}, ...", method_params))
})format!("x, {}, ...", method_params)
4719 };
4720
4721 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
s3_method_name, formals))
})format!("{} <- function({}) {{", s3_method_name, formals));
4722
4723 let call = ctx.instance_call("x");
4725 let strategy = crate::ReturnStrategy::for_method(method);
4726 let return_builder = crate::MethodReturnBuilder::new(call)
4727 .with_strategy(strategy)
4728 .with_invisible(method.is_invisible())
4729 .with_class_name(class_name.clone())
4730 .with_return_class_from_method(method, &type_ident.to_string());
4731 lines.extend(return_builder.build_s3_body());
4732
4733 lines.push("}".to_string());
4734 lines.push(String::new());
4735 }
4736
4737 lines.join("\n")
4738}
4739
4740pub fn generate_as_coercion_trait_impls(parsed_impl: &ParsedImpl) -> TokenStream {
4754 let type_ident = &parsed_impl.type_ident;
4755 let cfg_attrs = &parsed_impl.cfg_attrs;
4756
4757 let mut impls = Vec::new();
4758
4759 for method in parsed_impl.as_coercion_methods() {
4760 let coercion_target = match &method.method_attrs.as_coercion {
4761 Some(target) => target.as_str(),
4762 None => continue,
4763 };
4764
4765 if !method.sig.inputs.is_empty() {
4768 continue;
4769 }
4770
4771 if method.env != ReceiverKind::Ref {
4773 continue;
4774 }
4775
4776 let (trait_name, trait_method): (&str, &str) = match coercion_target {
4779 "data.frame" => ("RCoerceDataFrame", "as_data_frame"),
4780 "list" => ("RCoerceList", "as_list"),
4781 "character" => ("RCoerceCharacter", "as_character"),
4782 "numeric" | "double" => ("RCoerceNumeric", "as_numeric"),
4783 "integer" => ("RCoerceInteger", "as_integer"),
4784 "logical" => ("RCoerceLogical", "as_logical"),
4785 "matrix" => ("RCoerceMatrix", "as_matrix"),
4786 "vector" => ("RCoerceVector", "as_vector"),
4787 "factor" => ("RCoerceFactor", "as_factor"),
4788 "Date" => ("RCoerceDate", "as_date"),
4789 "POSIXct" => ("RCoercePOSIXct", "as_posixct"),
4790 "complex" => ("RCoerceComplex", "as_complex"),
4791 "raw" => ("RCoerceRaw", "as_raw"),
4792 "environment" => ("RCoerceEnvironment", "as_environment"),
4793 "function" => ("RCoerceFunction", "as_function"),
4794 _ => continue, };
4796
4797 let trait_ident = syn::Ident::new(trait_name, proc_macro2::Span::call_site());
4798 let trait_method_ident = syn::Ident::new(trait_method, proc_macro2::Span::call_site());
4799 let user_method_ident = &method.ident;
4800
4801 let return_type = match coercion_target {
4804 "data.frame" | "list" => {
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_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "List");
::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, "r_coerce");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCoerceError");
::quote::__private::push_gt(&mut _s);
_s
}quote! {
4805 ::core::result::Result<::miniextendr_api::List, ::miniextendr_api::r_coerce::RCoerceError>
4806 },
4807 _ => {
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_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_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, "r_coerce");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCoerceError");
::quote::__private::push_gt(&mut _s);
_s
}quote! {
4808 ::core::result::Result<::miniextendr_api::SEXP, ::miniextendr_api::r_coerce::RCoerceError>
4809 },
4810 };
4811
4812 impls.push({
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let cfg_attrs =
match cfg_attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
}
}
::quote::__private::push_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, "r_coerce");
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&trait_ident, &mut _s);
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&type_ident, &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, "fn");
::quote::ToTokens::to_tokens(&trait_method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "self");
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::ToTokens::to_tokens(&return_type, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "self");
::quote::__private::push_dot(&mut _s);
::quote::ToTokens::to_tokens(&user_method_ident, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
_s
}quote! {
4813 #(#cfg_attrs)*
4814 impl ::miniextendr_api::r_coerce::#trait_ident for #type_ident {
4815 fn #trait_method_ident(&self) -> #return_type {
4816 self.#user_method_ident()
4817 }
4818 }
4819 });
4820 }
4821
4822 {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut impls, i) = impls.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let impls =
match impls.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&impls, &mut _s);
}
}
_s
}quote! { #(#impls)* }
4823}
4824
4825fn check_s7_shortcut_collisions(parsed: &ParsedImpl) -> syn::Result<()> {
4844 if parsed.class_system != ClassSystem::S7 {
4845 return Ok(());
4846 }
4847 let class_name = parsed.class_name();
4848
4849 let mut seen: std::collections::HashMap<String, proc_macro2::Span> =
4852 std::collections::HashMap::new();
4853
4854 for m in parsed.static_methods() {
4856 let name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_{1}", class_name,
m.r_method_name()))
})format!("{}_{}", class_name, m.r_method_name());
4857 seen.entry(name).or_insert_with(|| m.ident.span());
4858 }
4859
4860 for m in parsed.instance_methods() {
4864 if m.method_attrs.s7.fallback
4865 || m.method_attrs.s7.no_shortcut
4866 || m.method_attrs.s7.getter
4867 || m.method_attrs.s7.setter
4868 || m.method_attrs.s7.validate
4869 {
4870 continue;
4871 }
4872 let Some(name) = s7_class::s7_shortcut_name(&class_name, &m.r_method_name()) else {
4873 continue;
4874 };
4875 if seen.contains_key(&name) {
4876 return Err(syn::Error::new(
4877 m.ident.span(),
4878 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("S7 fast-path shortcut `{0}` collides with another generated function of the same name on `{1}`. Rename one (e.g. `#[miniextendr(s7(r_name = \"...\"))]`) or opt this method out of the shortcut with `#[miniextendr(s7(no_shortcut))]`.",
name, class_name))
})format!(
4879 "S7 fast-path shortcut `{name}` collides with another generated function \
4880 of the same name on `{class_name}`. Rename one (e.g. \
4881 `#[miniextendr(s7(r_name = \"...\"))]`) or opt this method out of the \
4882 shortcut with `#[miniextendr(s7(no_shortcut))]`."
4883 ),
4884 ));
4885 }
4886 seen.insert(name, m.ident.span());
4887 }
4888
4889 Ok(())
4890}
4891
4892fn check_env_member_collisions(parsed: &ParsedImpl) -> syn::Result<()> {
4895 if parsed.class_system != ClassSystem::Env {
4896 return Ok(());
4897 }
4898 let mut seen = std::collections::HashMap::new();
4899 if let Some(constructor) = parsed.constructor() {
4900 seen.insert("new".to_owned(), constructor);
4901 }
4902 for method in parsed.instance_methods().chain(parsed.static_methods()) {
4903 let name = method.r_method_name();
4904 if let Some(previous) = seen.insert(name.clone(), method) {
4905 return Err(syn::Error::new_spanned(
4906 &method.ident,
4907 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Env member `{0}${3}` is defined by both `{1}` and `{2}`. Constructors always occupy `new`; instance and static methods share the class environment. Rename a colliding method with `#[miniextendr(r_name = \"...\")]`.",
parsed.class_name(), previous.ident, method.ident, name))
})format!(
4908 "Env member `{}${name}` is defined by both `{}` and `{}`. \
4909 Constructors always occupy `new`; instance and static methods \
4910 share the class environment. Rename a colliding method with \
4911 `#[miniextendr(r_name = \"...\")]`.",
4912 parsed.class_name(),
4913 previous.ident,
4914 method.ident,
4915 ),
4916 ));
4917 }
4918 }
4919 Ok(())
4920}
4921
4922fn check_r6_initialize_collision(parsed: &ParsedImpl) -> syn::Result<()> {
4926 if parsed.class_system != ClassSystem::R6 {
4927 return Ok(());
4928 }
4929 for method in parsed
4930 .public_instance_methods()
4931 .chain(parsed.private_instance_methods())
4932 .chain(parsed.active_instance_methods())
4933 {
4934 let name = if method.is_active() {
4935 method
4936 .method_attrs
4937 .r6
4938 .prop
4939 .clone()
4940 .unwrap_or_else(|| method.r_method_name())
4941 } else {
4942 method.r_method_name()
4943 };
4944 if name == "initialize" {
4945 return Err(syn::Error::new_spanned(
4946 &method.ident,
4947 "R6 member `initialize` conflicts with the generated constructor. \
4948 Rename the method or use `#[miniextendr(r_name = \"...\")]`; \
4949 for an active binding, choose a different `r6(prop = \"...\")`.",
4950 ));
4951 }
4952 }
4953 Ok(())
4954}
4955
4956const R6_GENERATOR_BINDINGS: &[&str] = &[
4962 "active",
4963 "class",
4964 "classname",
4965 "clone_method",
4966 "cloneable",
4967 "debug",
4968 "debug_names",
4969 "get_inherit",
4970 "has_private",
4971 "inherit",
4972 "is_locked",
4973 "lock",
4974 "lock_class",
4975 "lock_objects",
4976 "new",
4977 "parent_env",
4978 "portable",
4979 "private_fields",
4980 "private_methods",
4981 "public_fields",
4982 "public_methods",
4983 "self",
4984 "set",
4985 "undebug",
4986 "unlock",
4987];
4988
4989fn check_r6_static_collisions(parsed: &ParsedImpl) -> syn::Result<()> {
4993 if parsed.class_system != ClassSystem::R6 {
4994 return Ok(());
4995 }
4996 for method in parsed.static_methods() {
4997 let name = method.r_method_name();
4998 if R6_GENERATOR_BINDINGS.contains(&name.as_str()) {
4999 return Err(syn::Error::new_spanned(
5000 &method.ident,
5001 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("R6 static method `{0}${1}` would replace the R6 generator\'s own `{1}`: static methods are assigned onto the generator object. Rename it with `#[miniextendr(r_name = \"...\")]`.",
parsed.class_name(), name))
})format!(
5002 "R6 static method `{class}${name}` would replace the R6 generator's own \
5003 `{name}`: static methods are assigned onto the generator object. Rename \
5004 it with `#[miniextendr(r_name = \"...\")]`.",
5005 class = parsed.class_name(),
5006 ),
5007 ));
5008 }
5009 }
5010 Ok(())
5011}
5012
5013fn check_s4_generic_collisions(parsed: &ParsedImpl) -> syn::Result<()> {
5020 if parsed.class_system != ClassSystem::S4 {
5021 return Ok(());
5022 }
5023 let mut seen = std::collections::HashMap::new();
5024 for method in parsed.instance_methods() {
5025 let generic = s4_class::s4_generic_name(method);
5026 if let Some(previous) = seen.insert(generic.clone(), method) {
5027 return Err(syn::Error::new_spanned(
5028 &method.ident,
5029 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("S4 generic `{3}` gets a method for `{0}` from both `{1}` and `{2}`; the second `setMethod()` would replace the first. Rename one with `#[miniextendr(r_name = \"...\")]` or give it another `s4(generic = \"...\")`.",
parsed.class_name(), previous.ident, method.ident, generic))
})format!(
5030 "S4 generic `{generic}` gets a method for `{}` from both `{}` and `{}`; \
5031 the second `setMethod()` would replace the first. Rename one with \
5032 `#[miniextendr(r_name = \"...\")]` or give it another \
5033 `s4(generic = \"...\")`.",
5034 parsed.class_name(),
5035 previous.ident,
5036 method.ident,
5037 ),
5038 ));
5039 }
5040 }
5041 Ok(())
5042}
5043
5044fn check_method_formals(parsed: &ParsedImpl) -> syn::Result<()> {
5059 let receiver = |name: &str, method: &str| {
5060 (
5061 name.to_string(),
5062 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("is the receiver of the generated {0}",
method))
})format!("is the receiver of the generated {method}"),
5063 )
5064 };
5065 for m in parsed.included_methods() {
5066 let is_ctor = parsed.is_method_constructor(m);
5067 let instance = m.env.is_instance() && !is_ctor && !m.is_finalizer();
5068 if (m.method_attrs.receiver.is_some() || m.method_attrs.no_dispatch_dots) && !instance {
5069 return Err(syn::Error::new_spanned(
5070 &m.ident,
5071 "`receiver` and `no_dots` apply only to instance methods",
5072 ));
5073 }
5074 let generic_receiver = m.method_attrs.receiver.as_deref().unwrap_or("x");
5075 let s7 = &m.method_attrs.s7;
5076 let formals = m.formals();
5077 if parsed.class_system == ClassSystem::S7
5078 && (s7.getter || s7.setter || s7.validate)
5079 && let Some(lit) = m
5080 .method_attrs
5081 .per_param
5082 .values()
5083 .find_map(|a| a.formal.as_ref())
5084 {
5085 return Err(syn::Error::new(
5086 lit.span(),
5087 "`formal(...)` on an S7 property getter, setter or validator: S7 calls it with \
5088 fixed arguments (`self`, `value`), so a declared formal would name nothing",
5089 ));
5090 }
5091 let reserved = match parsed.class_system {
5092 ClassSystem::R6 if instance || is_ctor => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[("self".to_string(),
"is R6's `self` binding inside the class, the object the generated \
method works on".to_string()),
("private".to_string(),
"is R6's `private` binding inside the class, where the generated method \
reads the object's pointer".to_string())]))vec![
5093 (
5094 "self".to_string(),
5095 "is R6's `self` binding inside the class, the object the generated \
5096 method works on"
5097 .to_string(),
5098 ),
5099 (
5100 "private".to_string(),
5101 "is R6's `private` binding inside the class, where the generated method \
5102 reads the object's pointer"
5103 .to_string(),
5104 ),
5105 ],
5106 ClassSystem::S3 if instance => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[receiver(generic_receiver, "S3 method")]))vec![receiver(generic_receiver, "S3 method")],
5107 ClassSystem::S4 if instance => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[receiver(generic_receiver, "S4 method")]))vec![receiver(generic_receiver, "S4 method")],
5108 ClassSystem::S7 if instance && !(s7.getter || s7.setter || s7.validate) => {
5109 let generic = m
5110 .method_attrs
5111 .generic
5112 .clone()
5113 .unwrap_or_else(|| m.r_method_name());
5114 let dispatch =
5115 s7_class::s7_dispatch_args(m, &s7_class::s7_generic_target(&generic));
5116 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[receiver(&dispatch[0], "S7 method")]))vec![receiver(&dispatch[0], "S7 method")]
5117 }
5118 _ => Vec::new(),
5119 };
5120 crate::r_wrapper_builder::check_r_formals(&m.sig.inputs, &formals, &reserved)?;
5121 }
5122 Ok(())
5123}
5124
5125fn check_s3_replacement_methods(parsed: &ParsedImpl) -> syn::Result<()> {
5134 if !#[allow(non_exhaustive_omitted_patterns)] match parsed.class_system {
ClassSystem::S3 | ClassSystem::Vctrs => true,
_ => false,
}matches!(parsed.class_system, ClassSystem::S3 | ClassSystem::Vctrs) {
5135 return Ok(());
5136 }
5137 for m in parsed.instance_methods() {
5138 let generic = m
5139 .method_attrs
5140 .generic
5141 .clone()
5142 .unwrap_or_else(|| m.r_method_name());
5143 crate::miniextendr_fn::check_replacement_value_param(
5144 &generic,
5145 &m.sig.inputs,
5146 &m.formals(),
5147 m.ident.span(),
5148 )?;
5149 }
5150 Ok(())
5151}
5152
5153fn check_dots_policies(parsed: &ParsedImpl) -> syn::Result<()> {
5160 for m in &parsed.methods {
5161 if let Some(policy) = &m.method_attrs.dots_policy {
5162 policy.check_signature(
5163 m.has_dots,
5164 m.has_dots || has_dispatch_dots(parsed.class_system, m),
5165 )?;
5166 }
5167 }
5168 Ok(())
5169}
5170
5171fn has_dispatch_dots(class_system: ClassSystem, m: &ParsedMethod) -> bool {
5177 match class_system {
5178 ClassSystem::Vctrs => m.method_attrs.vctrs_protocol.is_some(),
5179 _ if !m.env.is_instance() => false,
5180 ClassSystem::S3 | ClassSystem::S4 => !m.method_attrs.no_dispatch_dots,
5181 ClassSystem::S7 => !m.method_attrs.s7.no_dots,
5182 ClassSystem::Env | ClassSystem::R6 => false,
5183 }
5184}
5185
5186fn check_s7_dispatch(parsed: &ParsedImpl) -> syn::Result<()> {
5199 if parsed.class_system != ClassSystem::S7 {
5200 return Ok(());
5201 }
5202 for m in parsed.instance_methods() {
5203 if m.method_attrs.s7.getter || m.method_attrs.s7.setter || m.method_attrs.s7.validate {
5204 continue;
5205 }
5206 let ctx = crate::r_class_formatter::MethodContext::new(m, &parsed.type_ident);
5207 check_s7_method_dispatch(m, &ctx.params)
5208 .map_err(|message| syn::Error::new(m.ident.span(), message))?;
5209 }
5210 Ok(())
5211}
5212
5213fn check_s7_method_dispatch(m: &ParsedMethod, params: &str) -> Result<(), String> {
5216 use s7_class::{S7GenericTarget, s7_dispatch_args, s7_generic_target};
5217
5218 let rust_name = crate::naming::ident_name(&m.ident);
5219 let generic = m
5220 .method_attrs
5221 .generic
5222 .clone()
5223 .unwrap_or_else(|| m.r_method_name());
5224 let target = s7_generic_target(&generic);
5225 let op = target.name();
5226 if op == "!" {
5227 return Err(
5228 "S7 methods cannot be generated for the `!` operator: S7 does not dispatch \
5229 `!` (its Ops handling covers the binary operators only). Keep this method \
5230 under an ordinary name and call it directly."
5231 .to_string(),
5232 );
5233 }
5234
5235 let dispatch = s7_dispatch_args(m, &target);
5236 let spec = m
5237 .method_attrs
5238 .s7
5239 .dispatch
5240 .clone()
5241 .unwrap_or_else(|| dispatch.join(", "));
5242 let formals = crate::roxygen::split_r_formals(params);
5243 let names: Vec<&str> = formals
5244 .iter()
5245 .map(|f| crate::roxygen::formal_name(f))
5246 .collect();
5247 let listed = if names.is_empty() {
5248 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` has no parameters besides the receiver",
rust_name))
})format!("`{rust_name}` has no parameters besides the receiver")
5249 } else {
5250 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the R parameters of `{1}` are {0}",
names.iter().map(|n|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
})).collect::<Vec<_>>().join(", "), rust_name))
})format!(
5251 "the R parameters of `{rust_name}` are {}",
5252 names
5253 .iter()
5254 .map(|n| format!("`{n}`"))
5255 .collect::<Vec<_>>()
5256 .join(", ")
5257 )
5258 };
5259
5260 let mut seen = std::collections::HashSet::new();
5261 for d in &dispatch {
5262 if !crate::naming::is_syntactic_r_name(d) || d.starts_with("..") {
5264 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(dispatch = \"{0}\")` on `{1}`: `{2}` is not a syntactic R argument name (S7 dispatch arguments are plain names, and `...` cannot be one)",
spec, rust_name, d))
})format!(
5265 "`s7(dispatch = \"{spec}\")` on `{rust_name}`: `{d}` is not a syntactic R \
5266 argument name (S7 dispatch arguments are plain names, and `...` cannot be one)"
5267 ));
5268 }
5269 if !seen.insert(d.as_str()) {
5270 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(dispatch = \"{0}\")` on `{1}` names `{2}` twice",
spec, rust_name, d))
})format!(
5271 "`s7(dispatch = \"{spec}\")` on `{rust_name}` names `{d}` twice"
5272 ));
5273 }
5274 }
5275
5276 let is_base_operator = #[allow(non_exhaustive_omitted_patterns)] match target {
S7GenericTarget::BaseOperator(_) => true,
_ => false,
}matches!(target, S7GenericTarget::BaseOperator(_));
5277 if let Some(pair) = s7_class::s7_operator_dispatch_args(op).filter(|_| is_base_operator) {
5278 let [left, right] = pair;
5279 if dispatch != pair {
5280 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("S7 dispatches `{0}` on `{1}` and `{2}`, so `s7(dispatch = \"{3}\")` cannot be used on `{4}`: drop it (the pair is the default for `{0}`)",
op, left, right, spec, rust_name))
})format!(
5281 "S7 dispatches `{op}` on `{left}` and `{right}`, so `s7(dispatch = \"{spec}\")` \
5282 cannot be used on `{rust_name}`: drop it (the pair is the default for `{op}`)"
5283 ));
5284 }
5285 if m.method_attrs.s7.fallback {
5286 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(fallback)` cannot be combined with the `{0}` operator on `{1}`: it would register the method for every pair of operands, not for this class",
op, rust_name))
})format!(
5287 "`s7(fallback)` cannot be combined with the `{op}` operator on `{rust_name}`: \
5288 it would register the method for every pair of operands, not for this class"
5289 ));
5290 }
5291 let operands: Vec<&str> = names.iter().copied().filter(|n| *n != "...").collect();
5292 if operands.len() != 1 {
5293 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` implements the `{1}` operator, so it takes exactly one parameter besides the receiver: the right operand, named `{2}` (S7 calls the method as `{3} {1} {2}`); {4}",
rust_name, op, right, left, listed))
})format!(
5294 "`{rust_name}` implements the `{op}` operator, so it takes exactly one parameter \
5295 besides the receiver: the right operand, named `{right}` (S7 calls the method \
5296 as `{left} {op} {right}`); {listed}"
5297 ));
5298 }
5299 if operands[0] != right {
5300 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("S7 dispatches `{1}` on `{2}` and `{3}`: the receiver becomes `{2}` and the right operand of `{4}` must be named `{3}`. Rename the parameter `{0}` to `{3}`.",
operands[0], op, left, right, rust_name))
})format!(
5301 "S7 dispatches `{op}` on `{left}` and `{right}`: the receiver becomes `{left}` and \
5302 the right operand of `{rust_name}` must be named `{right}`. Rename the parameter \
5303 `{}` to `{right}`.",
5304 operands[0]
5305 ));
5306 }
5307 }
5308 if is_base_operator && s7_class::s7_operator_dispatch_args(op).is_none() && dispatch.len() > 1 {
5309 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("S7 dispatches `{0}` through the base primitive on its first argument only, so `s7(dispatch = \"{1}\")` cannot be used on `{2}`: drop it",
op, spec, rust_name))
})format!(
5310 "S7 dispatches `{op}` through the base primitive on its first argument only, so \
5311 `s7(dispatch = \"{spec}\")` cannot be used on `{rust_name}`: drop it"
5312 ));
5313 }
5314
5315 for (i, d) in dispatch.iter().enumerate().skip(1) {
5318 let Some(&found) = names.get(i - 1) else {
5319 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(dispatch = \"{0}\")` on `{1}`: dispatch argument `{2}` must be parameter {3} of the method (S7 needs a method\'s formals to start with the generic\'s dispatch arguments, the first naming the receiver), but {4}",
spec, rust_name, d, i, listed))
})format!(
5320 "`s7(dispatch = \"{spec}\")` on `{rust_name}`: dispatch argument `{d}` must be \
5321 parameter {i} of the method (S7 needs a method's formals to start with the \
5322 generic's dispatch arguments, the first naming the receiver), but {listed}"
5323 ));
5324 };
5325 if found != d {
5326 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(dispatch = \"{0}\")` on `{1}`: dispatch argument `{2}` must be parameter {3} of the method, found `{4}` (S7 needs a method\'s formals to start with the generic\'s dispatch arguments, in order, the first naming the receiver); {5}",
spec, rust_name, d, i, found, listed))
})format!(
5327 "`s7(dispatch = \"{spec}\")` on `{rust_name}`: dispatch argument `{d}` must be \
5328 parameter {i} of the method, found `{found}` (S7 needs a method's formals to \
5329 start with the generic's dispatch arguments, in order, the first naming the \
5330 receiver); {listed}"
5331 ));
5332 }
5333 if formals[i - 1].contains('=') {
5334 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(dispatch = \"{1}\")` on `{2}`: dispatch argument `{3}` has a default value (`{0}`), which S7 does not allow on dispatch arguments",
formals[i - 1].trim(), spec, rust_name, d))
})format!(
5335 "`s7(dispatch = \"{spec}\")` on `{rust_name}`: dispatch argument `{d}` has a \
5336 default value (`{}`), which S7 does not allow on dispatch arguments",
5337 formals[i - 1].trim()
5338 ));
5339 }
5340 }
5341 if m.method_attrs.s7.no_dots
5342 && #[allow(non_exhaustive_omitted_patterns)] match target {
S7GenericTarget::Local(_) => true,
_ => false,
}matches!(target, S7GenericTarget::Local(_))
5343 && let Some(extra) = names.get(dispatch.len() - 1)
5344 {
5345 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`s7(no_dots)` on `{0}` makes a generic without `...`, and S7 then requires every method\'s formals to equal its dispatch arguments, but `{1}` is not one. Add it to `s7(dispatch = \"...\")` or drop `no_dots`.",
rust_name, extra))
})format!(
5346 "`s7(no_dots)` on `{rust_name}` makes a generic without `...`, and S7 then requires \
5347 every method's formals to equal its dispatch arguments, but `{extra}` is not one. \
5348 Add it to `s7(dispatch = \"...\")` or drop `no_dots`."
5349 ));
5350 }
5351 Ok(())
5352}
5353
5354pub fn expand_impl(
5375 attr: proc_macro::TokenStream,
5376 item: proc_macro::TokenStream,
5377) -> proc_macro::TokenStream {
5378 let item_impl = match syn::parse::<syn::ItemImpl>(item.clone()) {
5379 Ok(i) => i,
5380 Err(e) => return e.into_compile_error().into(),
5381 };
5382
5383 if item_impl.trait_.is_some() {
5385 return crate::miniextendr_impl_trait::expand_miniextendr_impl_trait(attr, item);
5387 }
5388
5389 let attrs = match syn::parse::<ImplAttrs>(attr) {
5391 Ok(a) => a,
5392 Err(e) => return e.into_compile_error().into(),
5393 };
5394
5395 let mut parsed = match ParsedImpl::parse(attrs, item_impl) {
5396 Ok(p) => p,
5397 Err(e) => return e.into_compile_error().into(),
5398 };
5399
5400 if let Err(e) = check_class_members(&parsed) {
5401 return e.into_compile_error().into();
5402 }
5403 let infers_constructor = parsed.inferred_constructor().is_some();
5408 let demoted_class = if infers_constructor {
5409 parsed.constructor_demoted = true;
5410 let demoted = parsed
5411 .reject_unsupported_describe_in()
5412 .and_then(|()| check_class_members(&parsed))
5413 .map(|()| (generate_class_wrapper(&parsed), parsed.class_definitions()));
5414 parsed.constructor_demoted = false;
5415 match demoted {
5416 Ok(class) => Some(class),
5417 Err(e) => return e.into_compile_error().into(),
5418 }
5419 } else {
5420 None
5421 };
5422
5423 let type_ident = &parsed.type_ident;
5424 let cfg_attrs = &parsed.cfg_attrs;
5425
5426 let c_wrappers: Vec<TokenStream> = parsed
5428 .included_methods()
5429 .map(|m| generate_method_c_wrapper(&parsed, m))
5430 .collect();
5431 let fallback_entries = field_syntax::fallback_c_entries(&parsed);
5434
5435 let class = generate_class_wrapper(&parsed);
5437
5438 let original_impl = &parsed.original_impl;
5439
5440 let trait_impls = generate_as_coercion_trait_impls(&parsed);
5442
5443 let formals = crate::r_shadowing::formal_names(
5446 parsed
5447 .included_methods()
5448 .map(|m| (&m.sig.inputs, m.formals())),
5449 );
5450 let r_part = |lines: &[String]| crate::r_wrapper_raw_literal(&lines.join("\n"), &formals);
5451 let class_parts = |class: &ClassWrapper, defines: &[String]| {
5452 let head = r_part(&class.head);
5453 let class_docs = r_part(&class.class_docs);
5454 let class_doc_lines = r_part(&class.class_doc_lines);
5455 let members = r_part(&class.members);
5456 let tail = r_part(&class.tail);
5457 let member_names = &class.member_names;
5458 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "defines");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut defines, i) = defines.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let defines =
match defines.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&defines, &mut _s);
}
}
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "head");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&head, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "class_docs");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&class_docs, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "class_doc_lines");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&class_doc_lines, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "members");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&members, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "member_names");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut member_names, i) = member_names.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let member_names =
match member_names.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&member_names, &mut _s);
}
}
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "tail");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&tail, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
}quote! {
5459 defines: &[#(#defines),*],
5460 head: #head,
5461 class_docs: #class_docs,
5462 class_doc_lines: #class_doc_lines,
5463 members: #members,
5464 member_names: &[#(#member_names),*],
5465 tail: #tail,
5466 }
5467 };
5468
5469 let source_loc_doc = crate::source_location_doc(type_ident.span());
5470 let source_start = type_ident.span().start();
5471 let source_line_lit = syn::LitInt::new(&source_start.line.to_string(), type_ident.span());
5472 let source_col_lit =
5473 syn::LitInt::new(&(source_start.column + 1).to_string(), type_ident.span());
5474
5475 let param_warnings = &parsed.param_warnings;
5476
5477 let r_class_name_str = parsed.class_name();
5480 let class_system_str = parsed.class_system.to_ident().to_string();
5481 let field_syntax = parsed.r_data_accessors.enabled()
5485 && #[allow(non_exhaustive_omitted_patterns)] match parsed.class_system {
ClassSystem::S3 | ClassSystem::S4 | ClassSystem::Env => true,
_ => false,
}matches!(
5486 parsed.class_system,
5487 ClassSystem::S3 | ClassSystem::S4 | ClassSystem::Env
5488 );
5489 let settings = parsed.class_settings();
5490 let parts = class_parts(&class, &parsed.class_definitions());
5491 let constructor = parsed
5492 .constructor()
5493 .map(|m| crate::naming::ident_name(&m.ident))
5494 .unwrap_or_default();
5495 let candidates: Vec<String> = parsed
5496 .constructor_candidates()
5497 .map(|m| crate::naming::ident_name(&m.ident))
5498 .collect();
5499 let block_entry = |constructor: &str, inferred: bool, demoted, parts| {
5500 {
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, "ClassBlockEntry");
::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::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "type_path");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_or_or(&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, "any");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "type_name");
::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_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "r_class_name");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&r_class_name_str, &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);
::quote::__private::push_ident(&mut _s, "source_column");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&source_col_lit, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "settings");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&settings, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "constructor");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&constructor, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "constructor_inferred");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&inferred, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "constructor_candidates");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut candidates, i) = candidates.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let candidates =
match candidates.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&candidates, &mut _s);
}
}
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "demoted");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&demoted, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&parts, &mut _s);
_s
});
_s
}quote! {
5501 ::miniextendr_api::registry::ClassBlockEntry {
5502 rust_type: ::core::stringify!(#type_ident),
5503 type_path: || ::core::any::type_name::<#type_ident>(),
5504 r_class_name: #r_class_name_str,
5505 source_file: ::core::file!(),
5506 source_line: #source_line_lit,
5507 source_column: #source_col_lit,
5508 settings: #settings,
5509 constructor: #constructor,
5510 constructor_inferred: #inferred,
5511 constructor_candidates: &[#(#candidates),*],
5512 demoted: #demoted,
5513 #parts
5514 }
5515 }
5516 };
5517 let (demoted_static, demoted_ref) = match &demoted_class {
5520 Some((demoted, definitions)) => {
5521 let entry = block_entry(
5522 "",
5523 false,
5524 {
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!(::core::option::Option::None),
5525 class_parts(demoted, definitions),
5526 );
5527 (
5528 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "static");
::quote::__private::push_ident(&mut _s, "DEMOTED");
::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, "ClassBlockEntry");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&entry, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
5529 static DEMOTED: ::miniextendr_api::registry::ClassBlockEntry = #entry;
5530 },
5531 {
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_and(&mut _s);
::quote::__private::push_ident(&mut _s, "DEMOTED");
_s
});
_s
}quote!(::core::option::Option::Some(&DEMOTED)),
5532 )
5533 }
5534 None => (::quote::__private::TokenStream::new()quote!(), {
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!(::core::option::Option::None)),
5535 };
5536 let class_block = block_entry(&constructor, infers_constructor, demoted_ref, parts);
5537 let constructor_check = constructor_check(&parsed);
5538
5539 let expanded = {
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(&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, "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::ToTokens::to_tokens(&original_impl, &mut _s);
::quote::ToTokens::to_tokens(¶m_warnings, &mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut c_wrappers, i) = c_wrappers.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let c_wrappers =
match c_wrappers.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&c_wrappers, &mut _s);
}
}
::quote::ToTokens::to_tokens(&fallback_entries, &mut _s);
::quote::ToTokens::to_tokens(&trait_impls, &mut _s);
::quote::ToTokens::to_tokens(&constructor_check, &mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let cfg_attrs =
match cfg_attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
}
}
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_eq(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&demoted_static, &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, "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_CLASS_BLOCKS");
_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_ident(&mut _s, "static");
::quote::__private::push_ident(&mut _s, "CLASS_BLOCK");
::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, "ClassBlockEntry");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&class_block, &mut _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, "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_CLASS_NAMES");
_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_ident(&mut _s, "static");
::quote::__private::push_ident(&mut _s, "CLASS_NAME");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ClassNameEntry");
::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, "ClassNameEntry");
::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::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "stringify");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&type_ident, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "r_class_name");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&r_class_name_str, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "class_system");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&class_system_str, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "field_syntax");
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&field_syntax, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
5543 #[doc = #source_loc_doc]
5544 #[doc = ::core::concat!("Generated from source file `", ::core::file!(), "`.")]
5545 #original_impl
5546
5547 #param_warnings
5549
5550 #(#c_wrappers)*
5552 #fallback_entries
5553
5554 #trait_impls
5556
5557 #constructor_check
5558
5559 #(#cfg_attrs)*
5560 const _: () = {
5561 #demoted_static
5562
5563 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_CLASS_BLOCKS), linkme(crate = ::miniextendr_api::linkme))]
5566 static CLASS_BLOCK: ::miniextendr_api::registry::ClassBlockEntry = #class_block;
5567
5568 #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_CLASS_NAMES), linkme(crate = ::miniextendr_api::linkme))]
5571 static CLASS_NAME: ::miniextendr_api::registry::ClassNameEntry =
5572 ::miniextendr_api::registry::ClassNameEntry {
5573 rust_type: ::core::stringify!(#type_ident),
5574 r_class_name: #r_class_name_str,
5575 class_system: #class_system_str,
5576 field_syntax: #field_syntax,
5577 };
5578 };
5579 };
5580
5581 expanded.into()
5582}
5583
5584fn check_class_members(parsed: &ParsedImpl) -> syn::Result<()> {
5587 check_method_formals(parsed)?;
5590 check_env_member_collisions(parsed)?;
5591 check_r6_initialize_collision(parsed)?;
5592 check_r6_static_collisions(parsed)?;
5593 check_s4_generic_collisions(parsed)?;
5594 check_s3_replacement_methods(parsed)?;
5596 check_dots_policies(parsed)?;
5598 check_s7_shortcut_collisions(parsed)?;
5604 check_s7_dispatch(parsed)
5608}
5609
5610fn generate_class_wrapper(parsed: &ParsedImpl) -> ClassWrapper {
5613 let mut class = match parsed.class_system {
5614 ClassSystem::Env => generate_env_class(parsed),
5615 ClassSystem::R6 => generate_r6_class(parsed),
5616 ClassSystem::S3 => generate_s3_class(parsed),
5617 ClassSystem::S7 => generate_s7_class(parsed),
5618 ClassSystem::S4 => generate_s4_class(parsed),
5619 ClassSystem::Vctrs => generate_vctrs_class(parsed),
5620 };
5621 let as_coercion_wrappers = generate_as_coercion_methods(parsed);
5622 if !as_coercion_wrappers.is_empty() {
5623 class.members.push(String::new());
5624 class.members.push(as_coercion_wrappers);
5625 }
5626 class
5627}
5628
5629fn constructor_check(parsed: &ParsedImpl) -> TokenStream {
5638 let cfg_attrs = &parsed.cfg_attrs;
5639 let (impl_generics, _, where_clause) = parsed.original_impl.generics.split_for_impl();
5640 let self_ty = &parsed.original_impl.self_ty;
5641 if parsed.declared_constructor().is_some() {
5642 return {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let cfg_attrs =
match cfg_attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
}
}
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_eq(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "struct");
::quote::__private::push_ident(&mut _s, "__MxConstructorBlock");
::quote::__private::push_semi(&mut _s);
::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, "registry");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ClassConstructor");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "__MxConstructorBlock");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&self_ty, &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::__private::push_semi(&mut _s);
_s
}quote! {
5643 #(#cfg_attrs)*
5644 const _: () = {
5645 struct __MxConstructorBlock;
5647 impl #impl_generics
5648 ::miniextendr_api::registry::ClassConstructor<__MxConstructorBlock>
5649 for #self_ty #where_clause {}
5650 };
5651 };
5652 }
5653 if parsed.constructor_candidates().nth(1).is_none() {
5654 return TokenStream::new();
5655 }
5656 let requirements = parsed.constructor_candidates().map(|m| {
5658 let mut ty = parsed.type_ident.clone();
5659 ty.set_span(m.ident.span());
5660 {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span =
::quote::__private::get_span(m.ident.span()).__into_span();
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "miniextendr_api");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "registry");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span,
"require_class_constructor");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_lt_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_comma_spanned(&mut _s, _span);
::quote::__private::push_underscore_spanned(&mut _s, _span);
::quote::__private::push_gt_spanned(&mut _s, _span);
::quote::__private::push_group_spanned(&mut _s, _span,
::quote::__private::Delimiter::Parenthesis,
{
let _: ::quote::__private::Span =
::quote::__private::get_span(_span).__into_span();
::quote::__private::TokenStream::new()
});
::quote::__private::push_semi_spanned(&mut _s, _span);
_s
}quote::quote_spanned! {m.ident.span()=>
5661 ::miniextendr_api::registry::require_class_constructor::<#ty, _>();
5662 }
5663 });
5664 {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let cfg_attrs =
match cfg_attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
}
}
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_eq(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_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
});
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "constructor_check");
::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();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut requirements, i) = requirements.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let requirements =
match requirements.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&requirements, &mut _s);
}
}
_s
});
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
5665 #(#cfg_attrs)*
5666 const _: () = {
5667 #[allow(dead_code)]
5668 fn constructor_check() {
5669 #(#requirements)*
5670 }
5671 };
5672 }
5673}
5674
5675#[cfg(test)]
5676mod tests;
5677