Expand description
VECSXP-backed protection pool with generational keys.
A GC protection mechanism that stores protected SEXPs in a single R VECSXP (generic list), with slot management and generation tracking on the Rust side.
§Performance
Benchmarked at 10.1 ns/op for single insert+release. Zero R allocation per
insert (unlike preserve.rs DLL which allocates a CONSXP each time).
See analysis/gc-protection-benchmarks-results.md for full data.
§When to use
Use this for cross-.Call protection when:
- You have many protected objects or frequent insert/release churn
- You need any-order release (not LIFO)
- You want generational safety (stale-key detection)
For temporaries within a .Call, use ProtectScope
instead (7.4 ns/op, zero allocation, LIFO bulk cleanup).
For a few long-lived objects that are never released in a loop (like ExternalPtr),
use R_PreserveObject directly (13 ns/op, zero
Rust-side bookkeeping).
§Architecture
┌─────────────────────────────────────┐
│ R side: VECSXP (GC-traced slots) │ ← one R_PreserveObject, ever
│ [SEXP][SEXP][NIL][SEXP][NIL][SEXP] │
└──────┬──────────────────────────────┘
│ slot indices
┌──────┴──────────────────────────────┐
│ Rust side: Vec<u32> generations │ ← one free list, one generation array
│ + Vec<usize> free_slots │
└─────────────────────────────────────┘No external dependencies for slot management. The generation counter per slot detects stale keys. Single free list for VECSXP slot reuse.
Structs§
- Protect
Key - Generational key for a slot in a
ProtectPool. - Protect
Pool - A VECSXP-backed pool for GC protection with generational keys.
Type Aliases§
- NoSend
Sync 🔒 - Enforces
!Send + !Sync(R API is not thread-safe).