Skip to main content

ProtectScope

Struct ProtectScope 

Source
pub struct ProtectScope {
    n: Cell<i32>,
    armed: Cell<bool>,
    _nosend: PhantomData<Rc<()>>,
}
Expand description

A scope that automatically balances UNPROTECT(n) on drop.

This is the primary tool for managing GC protection in batch operations. Each call to protect or protect_with_index increments an internal counter; when the scope is dropped, UNPROTECT(n) is called.

§Example

unsafe fn my_call(x: SEXP, y: SEXP) -> SEXP {
    let scope = ProtectScope::new();
    let x = scope.protect(x);
    let y = scope.protect(y);

    // Both x and y are protected until scope drops
    let result = scope.protect(some_operation(x.get(), y.get()));
    result.get()
} // UNPROTECT(3)

§Nested Scopes

Scopes can be nested. Each scope tracks only its own protections:

unsafe fn outer(x: SEXP) -> SEXP {
    let scope = ProtectScope::new();
    let x = scope.protect(x);

    let result = helper(&scope, x.get());
    scope.protect(result).get()
} // UNPROTECT(2)

unsafe fn helper(_parent: &ProtectScope, x: SEXP) -> SEXP {
    let scope = ProtectScope::new();
    let temp = scope.protect(allocate_something());
    combine(x, temp.get())
} // UNPROTECT(1) - only this scope's protections

Fields§

§n: Cell<i32>§armed: Cell<bool>§_nosend: PhantomData<Rc<()>>

Implementations§

Source§

impl ProtectScope

Source

pub unsafe fn new() -> Self

Create a new protection scope.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn protect<'a>(&'a self, x: SEXP) -> Root<'a>

Protect x and return a rooted handle tied to this scope.

This always calls Rf_protect. The protection is released when the scope is dropped (along with all other protections in this scope).

§Safety
  • Must be called from the R main thread
  • x must be a valid SEXP
Source

pub unsafe fn protect_raw(&self, x: SEXP) -> SEXP

Protect and return the raw SEXP (sometimes more convenient).

§Safety

Same as protect.

Source

pub unsafe fn protect_with_index<'a>(&'a self, x: SEXP) -> ReprotectSlot<'a>

Protect x with an index slot so it can be replaced later via R_Reprotect.

Use this when you need to update a protected value in-place without growing the protection stack.

§Safety
  • Must be called from the R main thread
  • x must be a valid SEXP
§Example
unsafe fn accumulate(values: &[SEXP]) -> SEXP {
    let scope = ProtectScope::new();
    let slot = scope.protect_with_index(values[0]);

    for &v in &values[1..] {
        let combined = combine(slot.get(), v);
        slot.set(combined);  // Reprotect without growing stack
    }

    slot.get()
}
Source

pub unsafe fn protect2<'a>(&'a self, a: SEXP, b: SEXP) -> (Root<'a>, Root<'a>)

Protect two values at once (convenience method).

§Safety

Same as protect.

Source

pub unsafe fn protect3<'a>( &'a self, a: SEXP, b: SEXP, c: SEXP, ) -> (Root<'a>, Root<'a>, Root<'a>)

Protect three values at once (convenience method).

§Safety

Same as protect.

Source

pub fn count(&self) -> i32

Return the current protection count.

Source

pub unsafe fn disarm(&self)

Escape hatch: disable UNPROTECT on drop.

After calling this, the scope will not unprotect its values when dropped. You become responsible for ensuring correct unprotection.

§Safety

You must ensure the protects performed in this scope are correctly unprotected elsewhere, or you will leak protect stack entries.

Source

pub unsafe fn rearm(&self)

Re-arm a previously disarmed scope.

§Safety

Only call if you know the scope was disarmed and you want to restore automatic unprotection. Be careful not to double-unprotect.

Source

pub unsafe fn alloc_vector<'a>(&'a self, ty: SEXPTYPE, n: R_xlen_t) -> Root<'a>

Allocate a vector of the given type and length, and immediately protect it.

This combines allocation and protection in a single step, eliminating the GC gap that exists when you separately allocate and then protect.

§Safety
  • Must be called from the R main thread
  • Only protects the newly allocated object; does not protect other live unprotected objects during allocation
§Example
unsafe fn make_ints(n: R_xlen_t) -> SEXP {
    let scope = ProtectScope::new();
    let vec = scope.alloc_vector(SEXPTYPE::INTSXP, n);
    // fill via INTEGER(vec.get()) ...
    vec.get()
}
Source

pub unsafe fn alloc_matrix<'a>( &'a self, ty: SEXPTYPE, nrow: i32, ncol: i32, ) -> Root<'a>

Allocate a matrix of the given type and dimensions, and immediately protect it.

§Safety

Same as alloc_vector.

Source

pub unsafe fn alloc_list<'a>(&'a self, n: i32) -> Root<'a>

Allocate a list (VECSXP) of the given length and immediately protect it.

§Safety

Same as alloc_vector.

Source

pub unsafe fn alloc_strsxp<'a>(&'a self, n: usize) -> Root<'a>

Allocate a STRSXP (character vector) of the given length and immediately protect it.

§Safety

Same as alloc_vector.

Source

pub unsafe fn alloc_vecsxp<'a>(&'a self, n: usize) -> Root<'a>

Allocate a VECSXP (generic list) of the given length and immediately protect it.

§Safety

Same as alloc_vector.

Source

pub unsafe fn alloc_integer<'a>(&'a self, n: usize) -> Root<'a>

Allocate an integer vector (INTSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn alloc_real<'a>(&'a self, n: usize) -> Root<'a>

Allocate a real vector (REALSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn alloc_logical<'a>(&'a self, n: usize) -> Root<'a>

Allocate a logical vector (LGLSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn alloc_raw<'a>(&'a self, n: usize) -> Root<'a>

Allocate a raw vector (RAWSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn alloc_complex<'a>(&'a self, n: usize) -> Root<'a>

Allocate a complex vector (CPLXSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn alloc_character<'a>(&'a self, n: usize) -> Root<'a>

Allocate a character vector (STRSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_integer<'a>(&'a self, x: i32) -> Root<'a>

Create a scalar integer (length-1 INTSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_real<'a>(&'a self, x: f64) -> Root<'a>

Create a scalar real (length-1 REALSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_logical<'a>(&'a self, x: bool) -> Root<'a>

Create a scalar logical (length-1 LGLSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_complex<'a>(&'a self, x: Rcomplex) -> Root<'a>

Create a scalar complex (length-1 CPLXSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_raw<'a>(&'a self, x: u8) -> Root<'a>

Create a scalar raw (length-1 RAWSXP), protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn scalar_string<'a>(&'a self, s: &str) -> Root<'a>

Create a scalar string (length-1 STRSXP) from a Rust &str, protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn mkchar<'a>(&'a self, s: &str) -> Root<'a>

Create a CHARSXP from a Rust &str, protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn duplicate<'a>(&'a self, x: SEXP) -> Root<'a>

Deep-duplicate a SEXP, protected.

§Safety

Must be called from the R main thread. x must be a valid SEXP.

Source

pub unsafe fn shallow_duplicate<'a>(&'a self, x: SEXP) -> Root<'a>

Shallow-duplicate a SEXP, protected.

§Safety

Must be called from the R main thread. x must be a valid SEXP.

Source

pub unsafe fn coerce<'a>(&'a self, x: SEXP, target: SEXPTYPE) -> Root<'a>

Coerce a SEXP to a different type, protected.

§Safety

Must be called from the R main thread. x must be a valid SEXP.

Source

pub unsafe fn new_env<'a>( &'a self, parent: SEXP, hash: bool, size: i32, ) -> Root<'a>

Create a new environment, protected.

§Safety

Must be called from the R main thread.

Source

pub unsafe fn rooted<'a>(&'a self, sexp: SEXP) -> Root<'a>

Create a Root<'a> for an already-protected SEXP without adding protection.

This is useful when you have a SEXP that is already protected by some other mechanism (e.g., a ReprotectSlot) and want to return it as a Root tied to this scope’s lifetime for API consistency.

§Safety
  • The caller must ensure sexp is already protected and will remain protected for at least the lifetime of this scope
  • Must be called from the R main thread
Source

pub unsafe fn collect<'a, T, I>(&'a self, iter: I) -> Root<'a>
where T: RNativeType, I: IntoIterator<Item = T>, I::IntoIter: ExactSizeIterator,

Collect an iterator into a typed R vector.

This allocates once, protects, and fills directly - the most efficient pattern for typed vectors. The element type T determines the R vector type via the RNativeType trait.

§Type Mapping
Rust TypeR Vector Type
i32INTSXP
f64REALSXP
u8RAWSXP
RLogicalLGLSXP
RcomplexCPLXSXP
§Safety

Must be called from the R main thread.

§Example
unsafe fn squares(n: usize) -> SEXP {
    let scope = ProtectScope::new();
    // Type inferred from iterator
    scope.collect((0..n).map(|i| (i * i) as i32)).get()
}
§Unknown Length

For iterators without exact size (e.g., filter), collect to Vec first:

let evens: Vec<i32> = data.iter().filter(|x| *x % 2 == 0).copied().collect();
scope.collect(evens)

Trait Implementations§

Source§

impl Default for ProtectScope

Source§

fn default() -> Self

Create a new scope. Equivalent to unsafe { ProtectScope::new() }.

§Safety

The caller must ensure this is called from the R main thread.

Source§

impl Drop for ProtectScope

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Protector for ProtectScope

Source§

unsafe fn protect(&mut self, sexp: SEXP) -> SEXP

Protect a SEXP from garbage collection. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> RDefault for T
where T: Default,

Source§

fn default() -> T

Create a new instance with default values.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.