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
| System | Syntax | R Pattern | Use Case |
|---|---|---|---|
| Env | #[miniextendr] | obj$method() | Simple, environment-based dispatch |
| R6 | #[miniextendr(r6)] | R6Class with $new() | OOP with encapsulation |
| S3 | #[miniextendr(s3)] | generic(obj) dispatch | Idiomatic R generics |
| S4 | #[miniextendr(s4)] | setClass/setMethod | Formal OOP, multiple dispatch |
| S7 | #[miniextendr(s7)] | new_class/new_generic | Modern R OOP |
| vctrs | #[miniextendr(vctrs)] | new_vctr/new_rcrd/new_list_of | vctrs-compatible vectors |
§Method Categorization
Methods are categorized by their receiver type:
| Receiver | ReceiverKind | Generated as |
|---|---|---|
&self | Ref | Instance method (immutable) |
&mut self | RefMut | Instance method (mutable, chainable) |
self: ExternalPtrRef<'_, Self> | ExternalPtrRef | Instance method (immutable, with the R object: sidecar fields) |
self: ExternalPtrMut<'_, Self> | ExternalPtrMut | Instance method (mutable, with the R object: sidecar fields) |
self: ExternalPtr<Self> | ExternalPtrValue | Instance method (the handle itself, unborrowed) |
self | Value | Consuming 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) | None | Static method or constructor |
Special methods:
- Constructor: Returns
Selfwith no receiver, marked with#[miniextendr(constructor)]or namednew - 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:
crate::c_wrapper_builder: C wrapper generation with thread strategycrate::r_wrapper_builder: R function signatures and.Call()argscrate::method_return_builder: Return value handling per class systemcrate::roxygen: Documentation extraction from Rust doc comments
§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,incrementmethods - 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 ofr_data_accessorsfor 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 formr_data_accessors = "get"(#1848).- r6_
class 🔒 - R6 class wrapper generator (
R6Classwith$new(), active bindings, private methods). R6-class R wrapper generator. - s3_
class 🔒 - S3 class wrapper generator (
structure()+generic.Classdispatch). S3-class R wrapper generator. - s4_
class 🔒 - S4 class wrapper generator (
setClass/setMethodformal OOP). S4-class R wrapper generator. - s7_
class 🔒 - S7 class wrapper generator (
new_class/new_genericmodern 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§
- Class
Wrapper - 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
headandtail, and every block’smembersattach to it. Seeminiextendr_api::registry::ClassBlockEntry. - Field
Fallback - The fallback of the field readers of
s3(r_data_accessors),s4(r_data_accessors)andenv(r_data_accessors)(#2150):fallback = "Self::column", and optionallyfallback_names = "Self::column_names", in the path style of#[r_data(get = "Self::f")]. - Impl
Attrs - Attributes parsed from
#[miniextendr(...)]on an impl block. - Method
Attrs - Per-method attributes for class system customization.
- Parsed
Impl - Fully parsed
#[miniextendr]impl block, ready for code generation. - Parsed
Method - Parsed method from an impl block.
- R6Method
Attrs - R6-specific per-method markers, separated from
MethodAttrsso ther6parser branch and R6 class generator own a self-contained bag. - S7Method
Attrs - S7-specific per-method markers, separated from
MethodAttrsso 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. - Vctrs
Attrs - Attributes for vctrs class generation.
Enums§
- Class
System - Class system flavor for wrapper generation.
- Field
Lookup - 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). - RData
Accessors - What the impl option
r_data_accessorsasks for: the class-level form of thepub#[r_data]fields of#[derive(ExternalPtr)], next to the standaloneType_get_f()/Type_set_f()every class gets. - Receiver
Kind - Receiver kind for methods.
- Vctrs
Kind - 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@paramor R6@field. The wrapper writer drops the line when another block’sClassWrapper::class_docshave the tag (for@param/@field, for the same name), and otherwise keeps it without the prefix. Spelled the same asminiextendr_api::registry::CLASS_DEFAULT_PREFIX. - CLASS_
DOCS_ 🔒MARKER - The line of
ClassWrapper::headwhere the class’s roxygen block takes theClassWrapper::class_docsof every impl block of the type, the defining block’s first. Spelled the same asminiextendr_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 closingNULL, 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 asminiextendr_api::registry::CLASS_DOCS_ONLY_MARKER. - CLASS_
DOC_ 🔒LINES_ MARKER - The line of
ClassWrapper::headwhere the class’s roxygen block takes theClassWrapper::class_doc_linesof every impl block of the type. Spelled the same asminiextendr_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 = valueforms. - 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:newstops creating objects,setandlockare 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_implruns 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):forwardanddataneed the method’s own...parameter;emptythe 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
initializemember, 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 anr_nameending in<-) takes the new value last, asvalue(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>), sor_name = "x"next to a methodxis one way to get there; two equals4(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 anOps/%*%operator generic (e1, e2/x, y). - check_
s7_ 🔒method_ dispatch check_s7_dispatchfor one method;paramsis 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 🔒 lineas 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::ClassConstructorfor 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 (unlessno_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
initializeand S7’sconstructorfor 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_namesunder 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_nameskey insides3(...)/s4(...)/env(...), after the key:= "path", where the path names a function (a leadingSelfis the impl’s type). - parse_
r_ 🔒data_ accessors_ value - Parses an
r_data_accessorskey insides3(...)/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
tyisSelf,&Self,&mut Self,Box<Self>, the named type, orResult<(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, _>, orResult<NamedType, _>.