Skip to main content

Module externalptr_derive

Module externalptr_derive 

Source
Expand description

§#[derive(ExternalPtr)] - ExternalPtr Support

This module implements the #[derive(ExternalPtr)] macro which generates a TypedExternal impl for use with ExternalPtr<T>.

Trait ABI wrapper infrastructure is automatically generated when you use #[miniextendr] on impl Trait for Type blocks.

§Usage

§Basic (no traits)

#[derive(ExternalPtr)]
struct MyData {
    value: i32,
}
// Generates: impl TypedExternal for MyData { ... }

§With R Sidecar Slots and Class System

The #[r_data] attribute marks fields for R-side storage. Use #[externalptr(...)] to specify a class system for appropriate R wrapper generation:

Class SystemAttributeR Accessors
Environment#[externalptr(env)] (default)Type_get_field(), Type_set_field()
R6#[externalptr(r6)]Active bindings in R6Class
S3#[externalptr(s3)]$.class, $<-.class methods
S4#[externalptr(s4)]Slot accessors
S7#[externalptr(s7)]Properties via new_property()

Three field tiers are supported:

  1. Raw SEXP (SEXP) - Direct SEXP access, no conversion
  2. Zero-overhead scalars (i32, f64, bool, u8) - Direct R memory access
  3. Conversion types (anything else) - Uses IntoR/TryFromSexp traits
#[derive(ExternalPtr)]
#[externalptr(r6)]  // R6 class - generates active bindings
pub struct MyType {
    pub x: i32,

    #[r_data]
    r: RSidecar,  // Selector - enables R accessors for this type

    #[r_data]
    pub raw_slot: SEXP,  // Raw SEXP, no conversion

    #[r_data]
    pub count: i32,  // Zero-overhead: stored as R INTEGER(1)

    #[r_data]
    pub score: f64,  // Zero-overhead: stored as R REAL(1)

    #[r_data]
    pub name: String,  // Conversion: uses IntoR/TryFromSexp
}
// Generates: active bindings `count`, `score`, `name` in R6Class

§Trait ABI wiring

#[derive(ExternalPtr)]
struct MyCounter {
    value: i32,
}

#[miniextendr]
impl Counter for MyCounter { /* ... */ }

§Generated Types (trait impls)

§Wrapper Struct

#[repr(C)]
struct __MxWrapperMyCounter {
    erased: mx_erased,  // Must be first field
    data: MyCounter,
}

§Base Vtable

static __MX_BASE_VTABLE_MYCOUNTER: mx_base_vtable = mx_base_vtable {
    drop: __mx_drop_mycounter,
    concrete_tag: TAG_MYCOUNTER,
    query: __mx_query_mycounter,
};

§Query Function

The query function maps trait tags to vtable pointers:

unsafe extern "C" fn __mx_query_mycounter(
    ptr: *mut mx_erased,
    trait_tag: mx_tag,
) -> *const c_void {
    if trait_tag == TAG_COUNTER {
        return std::ptr::from_ref(&__VTABLE_COUNTER_FOR_MYCOUNTER).cast::<c_void>();
    }
    std::ptr::null()
}

Structs§

SidecarInfo 🔒
Aggregated sidecar information extracted from struct field analysis.
SidecarSlot 🔒
Information about a single #[r_data]-annotated sidecar slot field.

Enums§

SlotKind 🔒
The kind of sidecar slot, determining how getter/setter FFI functions are generated.

Functions§

derive_external_ptr
Main entry point for #[derive(ExternalPtr)].
generate_class_integration_r_code 🔒
Generate class-integrated R code for sidecar fields.
generate_erased_wrapper 🔒
Generate the type-erased wrapper infrastructure for trait ABI dispatch.
generate_getter_body 🔒
Generate the token stream for a sidecar getter function body.
generate_into_external_ptr 🔒
Generate the IntoExternalPtr marker trait impl.
generate_r_wrapper_for_slot 🔒
Generate R wrapper code (roxygen-annotated R functions) for a single sidecar slot.
generate_setter_body 🔒
Generate the token stream for a sidecar setter function body.
generate_sidecar_accessors 🔒
Generate sidecar accessor constants and extern "C-unwind" functions.
generate_typed_external 🔒
Generate the TypedExternal trait implementation for the derive target.
has_r_data_attr 🔒
Check if a field has the #[r_data] attribute.
is_pub 🔒
Check if a field is public.
is_rsidecar_type 🔒
Check if a field type is RSidecar.
parse_externalptr_attrs 🔒
Parse #[externalptr(...)] attributes to extract class system.
parse_r_data_prop_doc 🔒
Parse prop_doc = "..." from an #[r_data(prop_doc = "...")] attribute.
parse_sidecar_info 🔒
Parse struct fields for sidecar information.
slot_kind_for_type 🔒
Determine the SlotKind for a field type by inspecting its last path segment.