Skip to main content

Module preserve

Module preserve 

Source
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:

StrategyModuleLifetimeRelease OrderUse Case
PROTECT stackgc_protectWithin .CallLIFO (stack)Temporary allocations
Preserve listpreserveAcross .CallsAny orderLong-lived R objects
R ownershipExternalPtrUntil R GCsR decidesRust data owned by R

§When to Use This Module

Use preserve (this module) when:

  • Objects must survive across multiple .Call invocations
  • You need to release protections in arbitrary order (not LIFO)
  • Example: RAllocator backing 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).