Skip to main content

Crate miniextendr_macros

Crate miniextendr_macros 

Source
Expand description

§miniextendr-macros - Procedural macros for Rust <-> R interop

This crate provides the procedural macros that power miniextendr’s code generation. Most users should depend on miniextendr-api and use its re-exports, but this crate can be used directly when you only need macros.

Primary macros and derives:

  • #[miniextendr] on functions, impl blocks, trait defs, and trait impls.
  • #[r_ffi_checked] for main-thread routing of C-ABI wrappers.
  • Derives: ExternalPtr, RNativeType, ALTREP derives, RFactor.
  • Helpers: typed_list for typed list builders.

R wrapper generation is driven by Rust doc comments (roxygen tags are extracted). During package build, the wrapper-gen pass loads the installed shared object into R and calls miniextendr_write_wrappers, which walks the linkme #[distributed_slice] tables and writes R/<pkg>-wrappers.R.

§Quick start

ⓘ
use miniextendr_api::miniextendr;

#[miniextendr]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

§Macro expansion pipeline

§Overview

┌──────────────────────────────────────────────────────────────────────────┐
│                         #[miniextendr] on fn                             │
│                                                                          │
│  1. Parse: syn::ItemFn → MiniextendrFunctionParsed                       │
│  2. Analyze return type (Result<T>, Option<T>, raw SEXP, etc.)           │
│  3. Generate:                                                            │
│     ├── C wrapper: extern "C-unwind" fn C_<crate>_<name>(...) → SEXP     │
│     ├── R wrapper: static R_WRAPPER_<name>: RWrapperEntry                  │
│     └── Registration: const call_method_def_<name>: R_CallMethodDef      │
│  4. Original function preserved (with added attributes)                  │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│                    #[miniextendr(env|r6|s3|s4|s7)] on impl               │
│                                                                          │
│  1. Parse: syn::ItemImpl → extract methods                               │
│  2. For each method:                                                     │
│     ├── Generate C wrapper (handles self parameter)                      │
│     ├── Generate R method wrapper string                                 │
│     └── Generate registration entry                                      │
│  3. Generate class definition code per class system:                     │
│     ├── env: new.env() + method assignment                               │
│     ├── r6: R6Class() definition                                         │
│     ├── s3: S3 generics + methods                                        │
│     ├── s4: setClass() + setMethod()                                     │
│     └── s7: new_class() definition                                       │
│  4. Emit const with combined R code                                      │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│                         #[miniextendr] on trait                          │
│                                                                          │
│  1. Parse: syn::ItemTrait → extract method signatures                    │
│  2. Generate:                                                            │
│     ├── Trait tag constant: const TAG_<TRAIT>: mx_tag = ...              │
│     ├── Vtable struct: struct __vtable_<Trait> { ... }                   │
│     └── CCalls table: static MX_CCALL_<TRAIT>: [...] = ...               │
│  3. Original trait preserved                                             │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│                    #[miniextendr] impl Trait for Type                    │
│                                                                          │
│  1. Parse: syn::ItemImpl (trait impl)                                    │
│  2. Generate:                                                            │
│     ├── Vtable instance: static __VTABLE_<crate>_<Trait>_FOR_<Type>     │
│     ├── Shared runtime storage: ErasedObject<Type>                     │
│     ├── Shared query: registry::universal_query                        │
│     └── Base vtable: static __MX_BASE_VTABLE_<Type>: ...                 │
│  3. Original impl preserved                                              │
└──────────────────────────────────────────────────────────────────────────┘

§Key Modules

ModulePurpose
miniextendr_fnFunction parsing and attribute handling
c_wrapper_builderC wrapper generation (extern "C-unwind")
r_wrapper_builderR wrapper code generation
rust_conversion_builderRust→SEXP return value conversion
miniextendr_implimpl Type block processing
r_class_formatterClass system code generation (env/r6/s3/s4/s7)
miniextendr_traitTrait ABI metadata generation
miniextendr_impl_traitimpl Trait for Type vtable generation
altrep / altrep_deriveALTREP struct derivation
externalptr_derive#[derive(ExternalPtr)]
roxygenRoxygen doc comment handling

§Generated Symbol Naming

Every #[no_mangle] symbol is prefixed with the consuming crate’s name (from CARGO_CRATE_NAME) so two packages loaded into one webR session can’t collide on a C symbol (#1273; helpers in naming.rs). For a function my_func in a crate mypkg:

  • C wrapper: C_mypkg_my_func
  • R wrapper registration: R_WRAPPER_my_func
  • Registration: call_method_def_my_func

For a type MyType with trait Counter in a crate mypkg:

  • Vtable: __VTABLE_mypkg_Counter_FOR_MyType
  • Storage: runtime ErasedObject<MyType>
  • Query: __mx_query_mytype

§Return Type Handling

The return_type_analysis module determines how to convert Rust returns to SEXP:

Rust TypeStrategyR Result
T: IntoR.into_sexp()Converted value
Result<T, E>Unwrap or R errorValue or error
Option<T>Some → value, None → NULLValue or NULL
SEXPPass throughRaw SEXP
()Invisible NULLinvisible(NULL)

Use #[miniextendr(unwrap_in_r)] to return Result<T, E> to R without unwrapping.

§Thread Strategy

By default, #[miniextendr] functions run on R’s main thread. Opt into worker-thread execution with #[miniextendr(worker)] (requires the worker-thread feature on miniextendr-api). A worker opt-in is ignored when the signature requires main-thread execution (returns/takes SEXP, uses variadic dots, or sets check_interrupt).

Note: ExternalPtr<T> is Send — it can be returned from worker thread functions. All R API operations on ExternalPtr are serialized through with_r_thread.

§Class Systems

The r_class_formatter module generates R code for different class systems:

SystemGenerated R CodeSelf Parameter
envnew.env() with methodsself environment
r6R6Class()self environment
s3structure() + genericsFirst argument
s4setClass() + setMethod()First argument
s7new_class()self property

Modules§

all_equal_derive 🔒
#[derive(AllEqual)] - all.equal() for a pointer-backed class (#2149)
altrep 🔒
ALTREP registration code generation.
altrep_derive 🔒
Derive macros for ALTREP data traits.
c_wrapper_builder 🔒
Unified C wrapper generation for standalone functions and impl methods.
call_method_def 🔒
Shared .Call registration for generated SEXP wrappers.
cfg_gates 🔒
Resolve cfg / cfg_attr on the members of a #[miniextendr] item before anything is generated from it.
condition_derive 🔒
Code generation for #[derive(RCondition)].
crate_config 🔒
Crate-level #[miniextendr] defaults read from the user crate’s manifest.
dataframe_derive 🔒
Derive macros for bidirectional row ↔ dataframe conversions.
deprecation 🔒
Compile-time warnings for deprecated #[miniextendr] options (#2117).
dots_policy 🔒
#[miniextendr(dots = ...)]: typed_list!(...), or what the function’s ... is for (#2157).
externalptr_args 🔒
Borrowed external arguments (#2106): &T / &mut T for a TypedExternal type, the views ExternalPtrRef<'_, T> / ExternalPtrMut<'_, T>, and an Option of either.
externalptr_derive 🔒
#[derive(ExternalPtr)] - ExternalPtr Support
factor_derive 🔒
#[derive(RFactor)] - Enum ↔ R Factor Support
lifecycle 🔒
Lifecycle support for R package deprecation management.
list_derive 🔒
List and Preference Derive Macros
list_macro 🔒
Parser for the list! macro.
match_arg_derive 🔒
#[derive(MatchArg)] - Enum ↔ R String with match.arg Support
match_arg_keys 🔒
Write-time placeholder & symbol-name formatting for the match_arg pipeline.
method_return_builder 🔒
Shared utilities for handling method return values in R wrapper generation.
miniextendr_fn 🔒
Function signature parsing for #[miniextendr].
miniextendr_impl 🔒
Impl-block Parsing and Wrapper Generation
miniextendr_impl_trait 🔒
#[miniextendr] on trait impls - Trait Implementation Registration
miniextendr_trait 🔒
Trait Support for #[miniextendr]
misplaced_dots 🔒
Diagnostic for a Rust ... parameter that is not the last one (#1737).
naming 🔒
Naming helpers for the static symbols the #[miniextendr] attribute emits.
newtype_derive 🔒
#[derive(TryFromSexp)] / #[derive(IntoR)] — forward R↔Rust conversions from a single-field newtype to its inner type. #[derive(IsNA)] uses the same parser to forward native missing-value detection.
r_class_formatter 🔒
Shared utilities for R class wrapper generation.
r_macro 🔒
Implementation of the r! proc-macro.
r_preconditions 🔒
R-side precondition generation for type checking.
r_shadowing 🔒
Calls to base functions that a formal of the same name would shadow.
r_wrapper_builder 🔒
Shared utilities for building R wrapper code.
receiver_body 🔒
Rewrite an explicit handle receiver without changing independent Rust scopes.
reexport 🔒
reexport!(pkg::name, ...): R re-exports declared from Rust (#1910).
return_type_analysis 🔒
Return type analysis for #[miniextendr] functions.
return_wrap 🔒
One explicit class-wrapping decision for marker and attribute spellings.
roxygen 🔒
Roxygen tag extraction and processing for R wrapper generation.
rust_conversion_builder 🔒
Shared utilities for converting R SEXP parameters to Rust types.
s7_conversion 🔒
Feed S7 conversion markers and attributes into the same registration plan.
struct_enum_dispatch 🔒
Dispatch #[miniextendr] on structs and enums to the appropriate derive helpers.
trait_receiver 🔒
Explicit owner-bearing trait receivers, rewritten for stable Rust.
trait_self_ref 🔒
Shared pre-conversion alias checks and Self-reference lowering for trait shims.
trait_signature 🔒
Infer inherited argument types from a concrete method item, not copied paths.
type_inspect 🔒
Lightweight type-introspection helpers shared by parsing and codegen.
typed_dataframe 🔒
Parser and expansion for the typed_dataframe! macro.
typed_external_macro 🔒
impl_typed_external! — explicit monomorphization of TypedExternal for generic types.
typed_list 🔒
Parser for the typed_list! macro.
util 🔒
Small cross-cutting helpers used by multiple macro modules.
vctrs_generics 🔒
Known vctrs S3 generic names used to auto-insert @importFrom vctrs.

Macros§

__mx_trait_impl_expand 👻
Internal proc macro used by TPIE (Trait-Provided Impl Expansion).
impl_typed_external
Generate TypedExternal and IntoExternalPtr impls for a concrete monomorphization of a generic type.
list
Construct an R list from Rust values.
miniextendr_init
Generate the R_init_* entry point for a miniextendr R package.
r
Evaluate R code written as Rust tokens, validated at compile time.
reexport
Re-export other packages’ R functions from this package.
typed_dataframe
Define a compile-time-validated wrapper for an R data.frame input.
typed_list
Create a TypedListSpec for validating ... arguments or lists.

Functions§

apply_return_pref 🔒
Maps a ReturnPref attribute value onto an auto-detected ReturnHandling.
build_dots_validation_stmt 🔒
Builds the let dots_typed = <dots>.typed(<spec>)... statement injected at the start of a function body when #[miniextendr(dots = typed_list!(...))] is used.
expand_fn 🔒
#[miniextendr] on a function. It reads proc_macro2 tokens and returns the token type its caller asks for: proc_macro’s from the attribute, or proc_macro2’s in the unit tests, which run outside a proc macro.
expand_miniextendr 🔒
The #[miniextendr] expansion, before the deprecated-option warnings (deprecation) are appended.
return_handling_category_description 🔒
Human-readable description of a ReturnHandling category, for the apply_return_pref compile error. Only describes the categories c_wrapper_builder::detect_return_handling can actually produce; the wildcard arm covers variants that never reach apply_return_pref as auto (IntoR itself, method-only SelfHandle, and the As*Of variants apply_return_pref produces as output, never takes as input).
return_pref_names 🔒
Human-readable (attribute value, wrapper type) pair for a ReturnPref, used to phrase the apply_return_pref compile error.
validate_extern_signature 🔒
Validate the signature of an extern "C-unwind" fn exported via #[miniextendr].

Attribute Macros§

miniextendr
Export Rust items to R.
r_ffi_checked
Generate thread-safe wrappers for R FFI functions.

Derive Macros§

AllEqual
Derive an all.equal() method for the R class of an ExternalPtr type, comparing the struct field by field (#2149).
Altrep
Derive ALTREP registration for a data struct.
AltrepComplex
Derive macro for ALTREP complex vector data types.
AltrepInteger
Derive macro for ALTREP integer vector data types.
AltrepList
Derive macro for ALTREP list vector data types.
AltrepLogical
Derive macro for ALTREP logical vector data types.
AltrepRaw
Derive macro for ALTREP raw vector data types.
AltrepReal
Derive macro for ALTREP real vector data types.
AltrepString
Derive macro for ALTREP string vector data types.
DataFrameRow
Derive DataFrameRow: generates a companion *DataFrame type with collection fields, plus IntoR / TryFromSexp / IntoDataFrame impls for seamless R data.frame conversion.
ExternalPtr
Derive macro for implementing TypedExternal on a type.
IntoList
Derive IntoList for a struct (Rust → R list).
IntoR
Derive IntoR for a single-field newtype: forward the Rust → R conversion to the inner type.
IsNA
Derive IsNA for a native newtype by forwarding to its single field.
MatchArg
Derive MatchArg: enables conversion between Rust enums and R character strings with match.arg semantics (partial matching, informative errors).
PreferExternalPtr
Derive PreferExternalPtr: return a type with a hand-written TypedExternal implementation as an R external pointer. #[derive(ExternalPtr)] already supplies IntoR; adding this derive to it creates conflicting implementations.
PreferList
Derive PreferList: emits an IntoR impl selecting list as the type’s default Rust→R conversion (via IntoList::into_list).
PreferRNativeType
Derive PreferRNativeType: when a newtype wraps an RNativeType and also implements other conversions, this selects the native R vector conversion as the default IntoR path.
RCondition
Derive an R condition type for a struct or enum: RConditionData (the R class vector, the message and the data fields handlers read as e$<name>) and From<Self> for miniextendr_api::RCondition.
RFactor
Derive RFactor: enables conversion between Rust enums and R factors.
RNativeType
Derive macro for implementing RNativeType on a newtype wrapper.
TryFromList
Derive TryFromList for a struct (R list → Rust).
TryFromSexp
Derive TryFromSexp for a single-field newtype: forward the R → Rust conversion to the inner type.