Skip to main content

Module miniextendr_impl

Module miniextendr_impl 

Source
Expand description

§Impl-block Parsing and Wrapper Generation

This module handles #[miniextendr] applied to inherent impl blocks, generating R wrappers for different class systems.

§Architecture Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                         #[miniextendr(r6)]                              │
│                         impl MyType { ... }                             │
└─────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                           PARSING PHASE                                 │
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────────┐ │
│  │   ImplAttrs     │    │  ParsedMethod   │    │    ParsedImpl       │ │
│  │ - class_system  │    │ - ident         │───▶│ - type_ident        │ │
│  │ - class_name    │    │ - receiver      │    │ - class_system      │ │
│  └─────────────────┘    │ - sig           │    │ - methods[]         │ │
│                         │ - doc_tags      │    │ - doc_tags          │ │
│                         │ - method_attrs  │    └─────────────────────┘ │
│                         └─────────────────┘                             │
└─────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                        CODE GENERATION PHASE                            │
│                                                                         │
│  For each method:                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ generate_c_wrapper_for_method()                                 │   │
│  │   └─▶ CWrapperContext (shared builder from c_wrapper_builder)   │   │
│  │         - thread strategy (main vs worker)                      │   │
│  │         - SEXP→Rust conversion                                  │   │
│  │         - return handling                                       │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  For the whole impl:                                                    │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ generate_{class_system}_r_wrapper()                             │   │
│  │   - generate_env_r_wrapper()   → Type$method(self, ...)         │   │
│  │   - generate_r6_r_wrapper()    → R6Class with methods           │   │
│  │   - generate_s3_r_wrapper()    → generic + method.Type          │   │
│  │   - generate_s4_r_wrapper()    → setClass + setMethod           │   │
│  │   - generate_s7_r_wrapper()    → new_class + method<-           │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                              OUTPUTS                                    │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │ C wrapper fns   │  │ R wrapper code  │  │  R_CallMethodDef       │ │
│  │ C_*_Type__method│  │ (as const str)  │  │  registration entries  │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘

§Supported Class Systems

SystemSyntaxR PatternUse Case
Env#[miniextendr]obj$method()Simple, environment-based dispatch
R6#[miniextendr(r6)]R6Class with $new()OOP with encapsulation
S3#[miniextendr(s3)]generic(obj) dispatchIdiomatic R generics
S4#[miniextendr(s4)]setClass/setMethodFormal OOP, multiple dispatch
S7#[miniextendr(s7)]new_class/new_genericModern R OOP
vctrs#[miniextendr(vctrs)]new_vctr/new_rcrd/new_list_ofvctrs-compatible vectors

§Method Categorization

Methods are categorized by their receiver type:

ReceiverReceiverKindGenerated as
&selfRefInstance method (immutable)
&mut selfRefMutInstance method (mutable, chainable)
self: ExternalPtrRef<'_, Self>ExternalPtrRefInstance method (immutable, with the R object: sidecar fields)
self: ExternalPtrMut<'_, Self>ExternalPtrMutInstance method (mutable, with the R object: sidecar fields)
self: ExternalPtr<Self>ExternalPtrValueInstance method (the handle itself, unborrowed)
selfValueConsuming method: -> Self writes the result back into the same handle; -> Result<Self, E> / Option<Self> run on a clone (T: Clone) and overwrite on success; any other return consumes the handle (later use errors)
(none)NoneStatic method or constructor

Special methods:

  • Constructor: Returns Self with no receiver, marked with #[miniextendr(constructor)] or named new
  • Finalizer: R6 only, marked with #[miniextendr(r6(finalize))] (never inferred from the receiver)
  • Private: R6 only, marked with #[miniextendr(r6(private))]

§Shared Builders

This module uses shared infrastructure from:

§Example

ⓘ
#[miniextendr(r6)]
impl Counter {
    fn new(value: i32) -> Self { Counter { value } }
    fn get(&self) -> i32 { self.value }
    fn increment(&mut self) { self.value += 1; }
}

Generates:

  • C wrappers: C_<crate>_Counter__new, C_<crate>_Counter__get, C_<crate>_Counter__increment
  • R6Class with initialize, get, increment methods
  • Registration entries for R’s .Call() interface

Modules§

env_class 🔒
Environment-based class wrapper generator (obj$method() dispatch). Env-class R wrapper generator.
field_syntax 🔒
$ / [[ field methods of r_data_accessors for S3, S4 and env classes (#1848). $ / [[ field syntax for the #[r_data] fields of S3, S4 and env classes: s3(r_data_accessors), s4(r_data_accessors), env(r_data_accessors), and their getters-only form r_data_accessors = "get" (#1848).
r6_class 🔒
R6 class wrapper generator (R6Class with $new(), active bindings, private methods). R6-class R wrapper generator.
s3_class 🔒
S3 class wrapper generator (structure() + generic.Class dispatch). S3-class R wrapper generator.
s4_class 🔒
S4 class wrapper generator (setClass / setMethod formal OOP). S4-class R wrapper generator.
s7_class 🔒
S7 class wrapper generator (new_class / new_generic modern R OOP). S7-class R wrapper generator.
vctrs_class 🔒
vctrs-compatible class wrapper generator (new_vctr / new_rcrd / new_list_of). Vctrs class R wrapper generator.

Structs§

ClassWrapper
One impl block’s R wrapper, in the parts the wrapper writer merges per Rust type (#1776): the class is defined once, from the defining block’s head and tail, and every block’s members attach to it. See miniextendr_api::registry::ClassBlockEntry.
FieldFallback
The fallback of the field readers of s3(r_data_accessors), s4(r_data_accessors) and env(r_data_accessors) (#2150): fallback = "Self::column", and optionally fallback_names = "Self::column_names", in the path style of #[r_data(get = "Self::f")].
ImplAttrs
Attributes parsed from #[miniextendr(...)] on an impl block.
MethodAttrs
Per-method attributes for class system customization.
ParsedImpl
Fully parsed #[miniextendr] impl block, ready for code generation.
ParsedMethod
Parsed method from an impl block.
R6MethodAttrs
R6-specific per-method markers, separated from MethodAttrs so the r6 parser branch and R6 class generator own a self-contained bag.
S7MethodAttrs
S7-specific per-method markers, separated from MethodAttrs so the S7 class generator has a self-contained bag of its own state (property getters/setters, generic-dispatch controls, convert() wiring) and the other class generators don’t have to look past them.
VctrsAttrs
Attributes for vctrs class generation.

Enums§

ClassSystem
Class system flavor for wrapper generation.
FieldLookup
How the S3 readers of s3(r_data_accessors) look a field up on a bare pointer (field_syntax.rs): s3(r_data_accessors, lookup = "list"). Neither lookup matches a prefix of a name (#1922).
RDataAccessors
What the impl option r_data_accessors asks for: the class-level form of the pub #[r_data] fields of #[derive(ExternalPtr)], next to the standalone Type_get_f() / Type_set_f() every class gets.
ReceiverKind
Receiver kind for methods.
VctrsKind
Kind of vctrs class being created.

Constants§

CLASS_DEFAULT_PREFIX 🔒
Opens a roxygen line of a class’s roxygen block that a doc tag written on another impl block of the type replaces: a generated @title, @name, @rdname, @export, constructor @param or R6 @field. The wrapper writer drops the line when another block’s ClassWrapper::class_docs have the tag (for @param / @field, for the same name), and otherwise keeps it without the prefix. Spelled the same as miniextendr_api::registry::CLASS_DEFAULT_PREFIX.
CLASS_DOCS_MARKER 🔒
The line of ClassWrapper::head where the class’s roxygen block takes the ClassWrapper::class_docs of every impl block of the type, the defining block’s first. Spelled the same as miniextendr_api::registry::CLASS_DOCS_MARKER.
CLASS_DOCS_ONLY_MARKER 🔒
Opens a class’s roxygen block that only carries the impl docs (docs_only_class_block). The wrapper writer writes the block, up to its closing NULL, only when the type’s impl docs or member-derived class docs say something, so a readers-only impl adds no page (#1918). Spelled the same as miniextendr_api::registry::CLASS_DOCS_ONLY_MARKER.
CLASS_DOC_LINES_MARKER 🔒
The line of ClassWrapper::head where the class’s roxygen block takes the ClassWrapper::class_doc_lines of every impl block of the type. Spelled the same as miniextendr_api::registry::CLASS_DOC_LINES_MARKER, which the wrapper writer replaces.
CLASS_MEMBER_DEFAULT_PREFIX 🔒
A generated member-documentation default resolved when the wrapper writer knows the defining impl block’s help topic (#2068). Unlike class defaults, these belong to individual member blocks: an inherited author topic replaces their page and drops generated parameter/structural prose, never author tags. Spelled the same as miniextendr_api::registry::CLASS_MEMBER_DEFAULT_PREFIX.
CLASS_SETTING_TAGS 🔒
The impl doc tags that are class settings rather than class documentation: they decide whether every block’s members are documented and exported, so each impl block of a type repeats them (ParsedImpl::class_settings).
IMPL_OPTIONS_HELP 🔒
Every impl-block option, for the “unknown impl block option” errors of the bare and the key = value forms.
R6_GENERATOR_BINDINGS 🔒
The bindings of an R6::R6Class() generator object (R6 2.6). The R6 generator assigns static methods onto that object (Class$name <- function), so a static method under one of these names silently replaces R6’s own: new stops creating objects, set and lock are the generated $set() / $lock() calls, and $new() reads the data fields.

Functions§

check_class_members 🔒
The checks of the members a block generates, which expand_impl runs on each rendering of the block.
check_dots_policies 🔒
Refuse a dots = empty | forward(..) | data (#2157) that describes a ... the method’s wrapper doesn’t have (DotsPolicy::check_signature): forward and data need the method’s own ... parameter; empty the wrapper’s ... formal, which is that parameter or the dispatch ... a method of a generic gets (has_dispatch_dots).
check_env_member_collisions 🔒
Env constructors, instance methods and static methods all occupy the same class environment. Check the emitted names before one overwrites another.
check_method_formals 🔒
Check the R formals of every generated method (check_r_formals), reserving the names each class system’s wrapper binds itself:
check_r6_initialize_collision 🔒
R6 always has an initialize member, including classes without a Rust constructor. R6 requires public, private and active names to be distinct; reject collisions before the generated class fails during package loading.
check_r6_static_collisions 🔒
Reject an R6 static method whose R name is one of the generator object’s own bindings (R6_GENERATOR_BINDINGS), which the static would replace without a warning when the package loads.
check_s3_replacement_methods 🔒
Check that every S3 instance method for a replacement generic (s3(generic = "[[<-"), or an r_name ending in <-) takes the new value last, as value (check_replacement_value_param, #1853). The generator puts the dispatch ... before that formal (s3_method_formals). Other class systems register their methods themselves, and static methods are plain functions.
check_s4_generic_collisions 🔒
Two instance methods of one S4 impl block that dispatch through the same generic emit two setMethod("<generic>", "<Class>", ...) calls with the same signature, and the second silently replaces the first. The default generic follows the R method name (s4_<r_name>), so r_name = "x" next to a method x is one way to get there; two equal s4(generic = "...") overrides are another.
check_s7_dispatch 🔒
Validate the S7 dispatch arguments of every S7 instance method: an explicit s7(dispatch = "..."), and the pair S7 fixes for an Ops / %*% operator generic (e1, e2 / x, y).
check_s7_method_dispatch 🔒
check_s7_dispatch for one method; params is its R formals string (normalized names, with defaults).
check_s7_shortcut_collisions 🔒
Detect S7 fast-path shortcut name collisions within an inherent impl block.
class_default 🔒
line as a generated default of the class’s roxygen block (CLASS_DEFAULT_PREFIX).
constructor_check 🔒
The compile-time half of the constructor decision. A block that declares the constructor implements the hidden miniextendr_api::registry::ClassConstructor for its type, under a type private to the block. A block with several constructor candidates and none declared requires that impl, once per candidate and spanned at it, so the type compiles only when another of its impl blocks declares the constructor; the error names each candidate. Two candidates in two blocks are the wrapper writer’s to refuse.
docs_only_class_block 🔒
The roxygen block of an S3 or vctrs class without a constructor that the package names and builds itself (class = "...", #1918), documenting no object: it carries the impl docs.
expand_impl
Top-level entry point for expanding #[miniextendr] on impl blocks.
find_param_type 🔒
Find a parameter’s Rust type from a stripped signature by identifier name.
generate_as_coercion_methods
Generate R S3 method wrappers for as.<class>() coercion methods.
generate_as_coercion_trait_impls
Generate impl RCoerce* trait impls for methods with #[miniextendr(as = "...")].
generate_class_wrapper 🔒
The block’s R wrapper, in the parts the wrapper writer merges per type (#1776), with the as.<class>() coercion methods (any class system).
generate_method_c_wrapper
Generate a C-callable wrapper function for a single method in an impl block.
generate_method_match_arg_entries 🔒
Register enum choices, aliases, defaults and parameter documentation for write-time placeholder substitution. R calls no choice-lookup C helper.
has_dispatch_dots 🔒
Whether the class system gives m’s R wrapper a ... formal the Rust method doesn’t take: the dispatch ... of an S3, S4 or S7 instance method (unless no_dispatch_dots / s7(no_dots)), and of a vctrs protocol method. Env and R6 methods and every other static method have only the formals of the Rust signature.
is_builtin_return_type_name 🔒
is_external_ptr_type 🔒
Check if a type is ExternalPtr<...> (possibly fully qualified).
is_known_return_container_name 🔒
member_default 🔒
no_constructor_guard 🔒
The first line of R6’s initialize and S7’s constructor for a class without a constructor: called without a .ptr, they raise an error rather than build an object holding no pointer. The factories and other classes’ methods always pass the .ptr.
no_field_fallback_error 🔒
The error for fallback / fallback_names under a class system without field syntax: R6 active bindings and S7 properties are a fixed set of names, and a vctr has no pointer.
old_handle_receiver 🔒
Refuse the receivers self: &ExternalPtr<Self> / self: &mut ExternalPtr<Self>, which #2106 replaced by the views: a handle behind a reference reads its value unchecked, while a view holds the borrow.
parse_fallback_value 🔒
Parses the value of a fallback / fallback_names key inside s3(...) / s4(...) / env(...), after the key: = "path", where the path names a function (a leading Self is the impl’s type).
parse_r_data_accessors_value 🔒
Parses an r_data_accessors key inside s3(...) / s4(...) / env(...) / r6(...) / s7(...), after the key: nothing, or = "get" (S3, S4 and env only).
push_member_rdname 🔒
A companion block follows a method’s explicit page; otherwise its page is inherited from the defining impl at wrapper-write time.
rewrite_external_ptr_receivers 🔒
Rewrite methods with handle receivers so they compile on stable Rust (which lacks arbitrary_self_types).
strip_miniextendr_attrs_from_impl 🔒
Strip #[miniextendr(...)] attributes and roxygen doc tags from an impl block and all of its items (functions, constants, types, macros).
ty_is_self_or_named 🔒
Recursively checks whether ty is Self, &Self, &mut Self, Box<Self>, the named type, or Result<(Self | NamedType), _>.
vctrs_ctor_returns_self_or_type 🔒
Returns true if a vctrs constructor’s return type is Self, &Self, &mut Self, the named impl type, Box<Self>, Result<Self, _>, or Result<NamedType, _>.