pub struct Preserved {
sexp: SEXP,
_not_send: PhantomData<*mut ()>,
}Expand description
An owned GC root for one R object: R_PreserveObject when made,
R_ReleaseObject when dropped.
Hold one where a Rust value keeps an R object across allocations or past
the .Call() that made it, such as a field of a struct that lives in an
ExternalPtr and drops with its finalizer.
The object stays reachable for as long as the handle lives, whatever the
drop order. ProtectScope and
OwnedProtect use R’s protect stack instead, which
unwinds in order and ends with the call.
struct Fit {
data: Preserved, // the data frame the model was fitted on
}
let fit = Fit { data: Preserved::new(df) };
// Any number of allocations and `.Call()`s later:
let n = fit.data.len();Clonepreserves the object again. Each handle releases its own entry, so clones drop in any order.- The handle dereferences to its
SEXP, soSexpExtmethods apply to it. ASEXPcopied out of it (*handle,as_sexp) stays rooted only while the handle lives. IntoRreleases the root and hands the object to the caller: return the handle from a#[miniextendr]function to return the object.!Send + !Sync: the precious list is R main-thread state. Make, clone and drop the handle on R’s main thread.
§Cost
R keeps the precious list as one linked list. Preserving conses a cell onto
its head, an allocation. Releasing searches the list from the head, one step
per object preserved after this one and not yet released. Starting R with
the environment variable R_HASH_PRECIOUS set splits the list into 1069
hashed buckets.
That suits a few long-lived objects. For many roots, or roots released in
no particular order, use a ProtectPool: it preserves
one list and inserts and releases in O(1), and it roots every
ExternalPtr, because a Vec of handles
dropped front to back makes each release scan the whole precious list.
RefCountedArena does the same with a count per
object. Within one call, the protect stack (ProtectScope) allocates
nothing.
Fields§
§sexp: SEXP§_not_send: PhantomData<*mut ()>!Send + !Sync: preserving and releasing edit R’s precious list.
Implementations§
Source§impl Preserved
impl Preserved
Sourcepub fn new(value: impl IntoR) -> Self
pub fn new(value: impl IntoR) -> Self
Convert value to an R object and preserve it.
A SEXP converts to itself, so Preserved::new(sexp) roots an
existing object. Rooting is immediate: nothing allocates between the
conversion and R_PreserveObject, which keeps its argument reachable
while it allocates its cell, so a fresh, unprotected object is safe to
pass. Call it on R’s main thread.
Methods from Deref<Target = SEXP>§
Sourcepub fn is_null_ptr(self) -> bool
pub fn is_null_ptr(self) -> bool
Is this SEXP a C null pointer (address 0x0)?
This answers a pointer question, not an R question. An SEXP that R
hands you (a .Call() argument, a list element, an attribute) is never
a C null pointer: R’s NULL is the R_NilValue singleton, a real
object at a non-zero address. A C null pointer only shows up where C
code uses address zero for “nothing here”: an uninitialised static or
field (SEXP::null()), an ALTREP data1/data2 slot that was never
set, or an FFI function that returns NULL on failure.
To ask “is this R’s NULL?”, use SEXP::is_nil().
use miniextendr_api::SEXP;
let unset = SEXP::null();
assert!(unset.is_null_ptr());There is no SEXP::is_null(): the name read like a test for R’s
NULL, so it is gone on purpose.
use miniextendr_api::SEXP;
let unset = SEXP::null();
assert!(unset.is_null());See also: SEXP::is_nil(), SEXP::is_null_or_nil(), SEXP::null()
Sourcepub fn is_nil(self) -> bool
pub fn is_nil(self) -> bool
Is this SEXP R’s NULL (R_NilValue)?
This is the check for an R value: an optional argument that defaults
to NULL, an absent attribute, an empty list slot. It compares the
address against the R_NilValue singleton and never dereferences
self, so it is safe on a stale SEXP. A C null pointer is not R’s
NULL; for that, use SEXP::is_null_ptr().
use miniextendr_api::SEXP;
// `x` is an argument whose R default is `NULL`: `f()` and `f(NULL)`
// both arrive as `R_NilValue`.
fn given(x: SEXP) -> bool {
!x.is_nil()
}See also: SEXP::nil(), SEXP::is_null_ptr(), SEXP::is_null_or_nil()
Sourcepub fn is_null_or_nil(self) -> bool
pub fn is_null_or_nil(self) -> bool
Is this SEXP either a C null pointer or R’s NULL?
For a slot that can hold either kind of “nothing”: unset (address
zero) or set to R_NilValue, such as an external pointer’s protected
value. For an R value alone, SEXP::is_nil() is the right check.
use miniextendr_api::SEXP;
// A slot that was never set counts as empty.
assert!(SEXP::null().is_null_or_nil());See also: SEXP::is_nil(), SEXP::is_null_ptr()
Sourcepub unsafe fn altrep_data1_raw(self) -> SEXP
pub unsafe fn altrep_data1_raw(self) -> SEXP
Get the raw SEXP in the ALTREP data1 slot.
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn altrep_data1_raw_unchecked(self) -> SEXP
pub unsafe fn altrep_data1_raw_unchecked(self) -> SEXP
Get the raw SEXP in the ALTREP data1 slot (unchecked — no thread routing).
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn set_altrep_data1(self, v: SEXP)
pub unsafe fn set_altrep_data1(self, v: SEXP)
Set the ALTREP data1 slot.
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn altrep_data2_raw(self) -> SEXP
pub unsafe fn altrep_data2_raw(self) -> SEXP
Get the raw SEXP in the ALTREP data2 slot.
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn altrep_data2_raw_unchecked(self) -> SEXP
pub unsafe fn altrep_data2_raw_unchecked(self) -> SEXP
Get the raw SEXP in the ALTREP data2 slot (unchecked — no thread routing).
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn set_altrep_data2(self, v: SEXP)
pub unsafe fn set_altrep_data2(self, v: SEXP)
Set the ALTREP data2 slot.
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Sourcepub unsafe fn set_altrep_data2_unchecked(self, v: SEXP)
pub unsafe fn set_altrep_data2_unchecked(self, v: SEXP)
Set the ALTREP data2 slot (unchecked — no thread routing).
§Safety
selfmust be a valid ALTREP SEXP- Must be called from the R main thread
Trait Implementations§
Auto Trait Implementations§
impl !Send for Preserved
impl !Sync for Preserved
impl Freeze for Preserved
impl RefUnwindSafe for Preserved
impl Unpin for Preserved
impl UnsafeUnpin for Preserved
impl UnwindSafe for Preserved
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> ConsumingFallible for Twhere
T: Clone,
Source§impl<T> RDebug for Twhere
T: Debug,
impl<T> RDebug for Twhere
T: Debug,
Source§impl<T> SizeHint for Twhere
T: ?Sized,
impl<T> SizeHint for Twhere
T: ?Sized,
Source§default fn lower_bound(&self) -> usize
default fn lower_bound(&self) -> usize
core_io_internals)[u8; 12] could return any value between 0 and
12 inclusively as a correct implementation. Read moreSource§impl<T> SizedTypeProperties for T
impl<T> SizedTypeProperties for T
Source§#[doc(hidden)]const SIZE: usize = _
#[doc(hidden)]const SIZE: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGN: usize = _
#[doc(hidden)]const ALIGN: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGNMENT: Alignment = _
#[doc(hidden)]const ALIGNMENT: Alignment = _
ptr_alignment_type)Source§#[doc(hidden)]const IS_ZST: bool = _
#[doc(hidden)]const IS_ZST: bool = _
sized_type_properties)Source§#[doc(hidden)]const LAYOUT: Layout = _
#[doc(hidden)]const LAYOUT: Layout = _
sized_type_properties)Source§#[doc(hidden)]const MAX_SLICE_LEN: usize = _
#[doc(hidden)]const MAX_SLICE_LEN: usize = _
sized_type_properties)[Self]. Read moreLayout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 8 bytes