Expand description
ExternalPtr<T> — a Box-like owned pointer that wraps R’s EXTPTRSXP.
This provides ownership semantics similar to Box<T>, with the key difference
that cleanup is deferred to R’s garbage collector via finalizers.
§Submodules
| Module | Contents |
|---|---|
altrep_helpers | ALTREP data1/data2 slot access helpers + Sidecar marker type |
§Core Types
ExternalPtr<T>— owned pointer wrapping EXTPTRSXPTypedExternal— trait for type-safe identification across packagesExternalSlice<T>— helper for slice data in external pointersErasedExternalPtr— type-erasedExternalPtr<()>aliasIntoExternalPtr— conversion trait for wrapping values
PartialEq/PartialOrd compare the pointee values (like Box<T>). Use
ptr_eq when you care about pointer identity, and as_ref()/as_mut() for
explicit by-value comparisons.
§Protection Strategies in miniextendr
miniextendr provides three complementary protection mechanisms for different scenarios:
| Strategy | Module | Lifetime | Release Order | Use Case |
|---|---|---|---|---|
| PROTECT stack | gc_protect | Within .Call | LIFO (stack) | Temporary allocations |
| Preserve list | preserve | Across .Calls | Any order | Long-lived R objects |
| R ownership | ExternalPtr | Until R GCs | R decides | Rust data owned by R |
§When to Use ExternalPtr
Use ExternalPtr (this module) when:
- You want R to own a Rust value
- The Rust value should be dropped when R garbage collects the pointer
- You’re exposing Rust structs to R code
Use gc_protect instead when:
- You’re allocating temporary R objects during computation
- Protection is short-lived (within a single
.Call)
Use preserve instead when:
- You need R objects (not Rust values) to survive across
.Calls - You need arbitrary-order release of protections
§How ExternalPtr Protection Works
┌─────────────────────────────────────────────────────────────────┐
│ ExternalPtr<MyStruct>::new(value) │
│ ├── Rf_protect() during construction (temporary) │
│ ├── R_MakeExternalPtr() creates EXTPTRSXP │
│ ├── R_RegisterCFinalizerEx() registers cleanup callback │
│ └── Rf_unprotect() after construction complete │
│ │
│ Return to R → R now owns the EXTPTRSXP │
│ ├── SEXP is live as long as R has references │
│ └── Rust value is accessible via ExternalPtr::wrap_sexp() │
│ │
│ R GC runs → finalizer called → Rust Drop executes │
└─────────────────────────────────────────────────────────────────┘§Type Identification
Type safety is enforced via Any::downcast (Rust’s TypeId). R symbols
in the tag and prot slots are retained for display and error messages.
Internally, data is stored as Box<Box<dyn Any>> — a thin pointer (fits
in R’s R_ExternalPtrAddr) pointing to a fat pointer (carries the Any
vtable for runtime downcasting).
The tag slot holds a symbol (type name, for display).
The prot slot holds a VECSXP (list) with two elements:
- Index 0: SYMSXP (interned type ID symbol, for error messages)
- Index 1: User-protected SEXP slot (for preventing GC of R objects)
§ExternalPtr is Not an R Native Type
Unlike R’s native atomic types (integer, double, character, etc.),
external pointers cannot be coerced to vectors or used in R’s vectorized
operations. This is an R limitation, not a miniextendr limitation:
> matrix(new("externalptr"), 1, 1)
Error in `as.vector()`:
! cannot coerce type 'externalptr' to vector of type 'any'If you need your Rust type to participate in R’s vector/matrix operations,
consider implementing IntoList (via #[derive(IntoList)])
to convert your struct to a named R list, or use ALTREP to expose Rust
iterators as lazy R vectors.
Modules§
- altrep_
helpers 🔒 - ALTREP helpers for
ExternalPtr— data1/data2 slot access.
Structs§
- External
Ptr - An owned pointer stored in R’s external pointer SEXP.
- External
Slice - A slice stored as a standalone struct, suitable for wrapping in ExternalPtr.
- RSidecar
- Marker type for enabling R sidecar accessors in an
ExternalPtrstruct.
Enums§
- Type
Mismatch Error - Error returned when type checking fails in
try_from_sexp_with_error.
Constants§
- PROT_
TYPE_ 🔒ID_ INDEX - Index of the type SYMSXP contained in the
prot(aVECSXPlist) - PROT_
USER_ 🔒INDEX - Index of user-protected objects contained in the
prot(aVECSXPlist) - PROT_
VEC_ 🔒LEN - Length of the
protlist (VECSXP)
Traits§
- Into
External Ptr - Marker trait for types that should be converted to R as ExternalPtr.
- Typed
External - Trait for types that can be stored in an ExternalPtr.
Functions§
- altrep_
data1_ ⚠as - Extract the ALTREP data1 slot as a typed
ExternalPtr<T>. - altrep_
data1_ ⚠as_ unchecked - Extract the ALTREP data1 slot (unchecked version).
- altrep_
data1_ ⚠mut - Get a mutable reference to data in ALTREP data1 slot via
ErasedExternalPtr. - altrep_
data1_ ⚠mut_ unchecked - Get a mutable reference to data in ALTREP data1 slot (unchecked version).
- altrep_
data2_ ⚠as - Extract the ALTREP data2 slot as a typed
ExternalPtr<T>. - altrep_
data2_ ⚠as_ unchecked - Extract the ALTREP data2 slot (unchecked version).
- is_
type_ 🔒erased - release_
any 🔒 - Non-generic C finalizer called by R’s garbage collector.
- sendable_
any_ 🔒ptr_ into_ ptr - Get the raw pointer, consuming the sendable wrapper.
- sendable_
any_ 🔒 ⚠ptr_ new - Create a new sendable pointer from a raw
*mut Box<dyn Any>. - symbol_
name 🔒 - Get the type name from a stored symbol SEXP.
- type_
id_ 🔒 ⚠symbol - Get the namespaced type ID symbol for type checking.
- type_
id_ 🔒 ⚠symbol_ unchecked - Unchecked version of
type_id_symbol. - type_
symbol 🔒 ⚠ - Get the interned R symbol for a type’s name.
- type_
symbol_ 🔒 ⚠unchecked - Unchecked version of
type_symbol- no thread safety checks.
Type Aliases§
- Erased
External Ptr - Type-erased
ExternalPtrfor cases where the concreteTis not needed. - Sendable
AnyPtr 🔒 - A wrapper around a raw pointer that implements
Send.