Expand description
Deprecated: Use ProtectPool or
R_PreserveObject instead. This module
remains for benchmark comparisons only. See analysis/gc-protection-benchmarks-results.md.
R object preservation using a circular doubly-linked list.
This module provides a protection scheme for R objects (SEXPs) that need to
survive R’s garbage collection across multiple .Call invocations.
§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 This Module
Use preserve (this module) when:
- Objects must survive across multiple
.Callinvocations - You need to release protections in arbitrary order (not LIFO)
- Example:
RAllocatorbacking memory
Use gc_protect instead when:
- Protection is short-lived (within a single
.Call) - You want RAII-based automatic PROTECT/UNPROTECT balancing
Use ExternalPtr instead when:
- You want R to own a Rust value with automatic cleanup
§Architecture
This module uses a cpp11-style circular doubly-linked list approach, which has advantages over the R protect stack:
- No balance requirement (PROTECT/UNPROTECT pairs must be balanced)
- Can release protections in any order
- Thread-local storage (each thread has its own preserve list)
- More ergonomic with RAII patterns
The preservation list is a circular doubly-linked cons list where:
- The list itself is preserved with
R_PreserveObject(never GC’d) - Each protected SEXP is stored as the TAG of a cell
- CAR points to previous cell, CDR points to next cell
- Head and tail are sentinel nodes
§Safety
All functions in this module are unsafe and must be called from the R main thread.
Constants§
- PRESERVE_
LIST 🔒 - The per-thread preservation list.
Functions§
- get 🔒 ⚠
- Get the current thread’s preservation list, initializing if needed.
- get_
unchecked 🔒 ⚠ - Get the current thread’s preservation list (unchecked version).
- init 🔒 ⚠
- Initialize the preservation list.
- init_
unchecked 🔒 ⚠ - Initialize the preservation list (unchecked version).
- insert⚠
- Insert a SEXP into the preservation list, protecting it from GC.
- insert_
unchecked ⚠ - Insert a SEXP into the preservation list (unchecked version).
- release⚠
- Release a previously protected SEXP from the preservation list.
- release_
unchecked ⚠ - Release a previously protected SEXP (unchecked version).