Expand description
§Trait Support for #[miniextendr]
This module handles #[miniextendr] applied to trait definitions,
generating the ABI infrastructure for cross-package trait dispatch.
§Overview
When #[miniextendr] is applied to a trait, it generates:
- Type tag constant (
TAG_<TraitName>) - 128-bit identifier for runtime type checking - Vtable struct (
<TraitName>VTable) - Function pointer table for method dispatch - View struct (
<TraitName>View) - Runtime wrapper combining data pointer and vtable - Method shims -
extern "C"functions that convert SEXP arguments and call methods - Vtable builder -
__<trait>_build_vtable::<T>()for impl blocks
§Usage
#[miniextendr]
pub trait Counter {
fn value(&self) -> i32;
fn increment(&mut self);
fn add(&mut self, n: i32);
}Generates (conceptually):
// Original trait (passed through)
pub trait Counter {
fn value(&self) -> i32;
fn increment(&mut self);
fn add(&mut self, n: i32);
}
// Type tag for runtime identification
pub const TAG_Counter: mx_tag = mx_tag::new(0x..., 0x...);
// Vtable with one entry per method
#[repr(C)]
pub struct CounterVTable {
pub value: mx_meth,
pub increment: mx_meth,
pub add: mx_meth,
}
// View over the data and vtable pointers; roots its R receiver
pub struct CounterView {
__mx_view: miniextendr_api::trait_abi::TraitViewData<CounterVTable>,
}
// Shim for each method
unsafe extern "C" fn __Counter_value_shim<T: Counter>(
data: *mut c_void, argc: i32, argv: *const SEXP
) -> SEXP {
// 1. Check arity
// 2. Cast data to &T
// 3. Call method
// 4. Convert result to SEXP
// 5. Catch panics
}
// Builder to create vtable for a concrete type
pub const fn __Counter_build_vtable<T: Counter>() -> CounterVTable {
CounterVTable {
value: __Counter_value_shim::<T>,
increment: __Counter_increment_shim::<T>,
add: __Counter_add_shim::<T>,
}
}§Supported Method Signatures
Methods must follow these constraints:
- Receiver:
&self,&mut self,self: ExternalPtrRef<'_, Self>orself: ExternalPtrMut<'_, Self>for instance methods, or none for static methods. Borrowed-owner receivers requireSelf: TypedExternal; their emitted Rust signatures are associated functions accepting the handle by value. - Arguments: Types that implement
TryFromSexp - Return: Types that implement
IntoR, or() - No generics: Methods cannot have generic type parameters
- No async: Async methods are not supported
- Static methods: Methods without a receiver are allowed and resolved at compile time (they don’t go through the vtable)
§Default Methods
Default method implementations are supported. The vtable builder will use the default implementation if the concrete type doesn’t override it.
#[miniextendr]
pub trait Counter {
fn value(&self) -> i32;
// Default implementation - included in vtable
fn is_zero(&self) -> bool {
self.value() == 0
}
}§Error Handling
A method shim runs inside with_r_unwind_protect_shim, which turns a Rust
panic into a tagged condition SEXP; the View re-panics with it in the
caller’s guard. These panic:
- Arity mismatch: “expected N arguments, got M”
- Aliased native borrows: two arguments (or two elements of one) that borrow the same R vector, at least one mutably, checked before any argument is converted
- Type conversion failure: the converter’s error message
- The method itself
§GC Protection
A View method converts each argument to a fresh SEXP, and the next
conversion allocates, so it protects every converted argument in a
ProtectScope as soon as it exists and keeps it protected across the
vtable call. The returned SEXP is protected across the tagged-error check
and its conversion back to Rust.
§Thread Safety
All generated shims are main-thread only. They do not route through
with_r_thread because R invokes .Call on the main thread.
Structs§
- Extra
Bounds 🔒 - Extra trait bounds inferred from method signatures.
- Method
Info 🔒 - Information extracted from a trait method for code generation.
Functions§
- associated_
method_ 🔒shim - Move the declaration shim into the trait so an impl can name it through
any path to that trait.
Self: Sizedkeeps these static ABI callbacks out of Rust trait objects. Types in the body still resolve at the declaration. - build_
where_ 🔒predicates - Build combined where predicates from the trait’s own where clause and computed extra bounds.
- compute_
extra_ 🔒bounds - Compute extra bounds needed for the shim and build_vtable functions.
- expand_
trait - Expand
#[miniextendr]applied to a trait definition. - extract_
method_ 🔒info - Extract method information from a trait method definition.
- generate_
method_ 🔒shim - Generate a method shim function for a trait method.
- generate_
trait_ 🔒abi - Generate the ABI infrastructure for a trait.
- generate_
view_ 🔒method - Generate a method wrapper for the View struct.
- rewrite_
self_ 🔒in_ type - Rewrite
SelfandSelf::AssocTypein a type tree to use__ImplT. - trait_
abi_ 🔒tag_ path - Encode the exported interface, in vtable order, for
mx_tag_from_path. - type_
contains_ 🔒ident - Check if a type syntactically contains a specific identifier.
- type_
contains_ 🔒self - Check if a type syntactically contains
Self. - type_
contains_ 🔒self_ assoc - Check if a type syntactically contains
Self::AssocTypefor a given associated type name. - validate_
method 🔒 - Validate a single trait method for ABI compatibility.
- validate_
trait 🔒 - Validate that the trait meets requirements for ABI generation.