1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
use super::*;
use std::any::Any;
use std::fmt::Debug;
/// Wrapper for creating R objects containing any Rust object.
///
/// ```
/// use extendr_api::prelude::*;
/// test! {
/// let extptr = ExternalPtr::new(1);
/// assert_eq!(*extptr, 1);
/// let robj : Robj = extptr.into();
/// let extptr2 : ExternalPtr<i32> = robj.try_into().unwrap();
/// assert_eq!(*extptr2, 1);
/// }
/// ```
///
#[derive(PartialEq, Clone)]
pub struct ExternalPtr<T> {
/// This is the contained Robj.
pub(crate) robj: Robj,
/// This is a zero-length object that holds the type of the object.
_marker: std::marker::PhantomData<T>,
}
impl<T: Debug + 'static> robj::GetSexp for ExternalPtr<T> {
unsafe fn get(&self) -> SEXP {
self.robj.get()
}
unsafe fn get_mut(&mut self) -> SEXP {
self.robj.get_mut()
}
/// Get a reference to a Robj for this type.
fn as_robj(&self) -> &Robj {
&self.robj
}
/// Get a mutable reference to a Robj for this type.
fn as_robj_mut(&mut self) -> &mut Robj {
&mut self.robj
}
}
/// len() and is_empty()
impl<T: Debug + 'static> Length for ExternalPtr<T> {}
/// rtype() and rany()
impl<T: Debug + 'static> Types for ExternalPtr<T> {}
/// as_*()
impl<T: Debug + 'static> Conversions for ExternalPtr<T> {}
/// find_var() etc.
impl<T: Debug + 'static> Rinternals for ExternalPtr<T> {}
/// as_typed_slice_raw() etc.
impl<T: Debug + 'static> Slices for ExternalPtr<T> {}
/// dollar() etc.
impl<T: Debug + 'static> Operators for ExternalPtr<T> {}
impl<T: Debug + 'static> Deref for ExternalPtr<T> {
type Target = T;
/// This allows us to treat the Robj as if it is the type T.
fn deref(&self) -> &Self::Target {
self.addr()
}
}
impl<T: Debug + 'static> DerefMut for ExternalPtr<T> {
/// This allows us to treat the Robj as if it is the mutable type T.
fn deref_mut(&mut self) -> &mut Self::Target {
self.addr_mut()
}
}
impl<T: Any + Debug> ExternalPtr<T> {
/// Construct an external pointer object from any type T.
/// In this case, the R object owns the data and will drop the Rust object
/// when the last reference is removed via register_c_finalizer.
///
/// An ExternalPtr behaves like a Box except that the information is
/// tracked by a R object.
pub fn new(val: T) -> Self {
single_threaded(|| unsafe {
// This allocates some memory for our object and moves the object into it.
let boxed = Box::new(val);
// This constructs an external pointer to our boxed data.
// into_raw() converts the box to a malloced pointer.
let robj = Robj::make_external_ptr(Box::into_raw(boxed), r!(()));
extern "C" fn finalizer<T>(x: SEXP) {
unsafe {
let ptr = R_ExternalPtrAddr(x) as *mut T;
// Free the `tag`, which is the type-name
R_SetExternalPtrTag(x, R_NilValue);
// Convert the pointer to a box and drop it implictly.
// This frees up the memory we have used and calls the "T::drop" method if there is one.
drop(Box::from_raw(ptr));
// Now set the pointer in ExternalPTR to C `NULL`
R_ClearExternalPtr(x);
}
}
// Tell R about our finalizer
robj.register_c_finalizer(Some(finalizer::<T>));
// Return an object in a wrapper.
Self {
robj,
_marker: std::marker::PhantomData,
}
})
}
// TODO: make a constructor for references?
/// Get the "tag" of an external pointer. This is the type name in the common case.
pub fn tag(&self) -> Robj {
unsafe { Robj::from_sexp(R_ExternalPtrTag(self.robj.get())) }
}
/// Get the "protected" field of an external pointer. This is NULL in the common case.
pub fn protected(&self) -> Robj {
unsafe { Robj::from_sexp(R_ExternalPtrProtected(self.robj.get())) }
}
/// Get the "address" field of an external pointer.
/// Normally, we will use Deref to do this.
pub fn addr<'a>(&self) -> &'a T {
unsafe {
let ptr = R_ExternalPtrAddr(self.robj.get()) as *const T;
&*ptr as &'a T
}
}
/// Get the "address" field of an external pointer as a mutable reference.
/// Normally, we will use DerefMut to do this.
pub fn addr_mut(&mut self) -> &mut T {
unsafe {
let ptr = R_ExternalPtrAddr(self.robj.get()) as *mut T;
&mut *ptr as &mut T
}
}
}
impl<T: Any + Debug> TryFrom<&Robj> for ExternalPtr<T> {
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
let clone = robj.clone();
if clone.rtype() != Rtype::ExternalPtr {
Err(Error::ExpectedExternalPtr(clone))
} else if clone.check_external_ptr_type::<T>() {
let res = ExternalPtr::<T> {
robj: clone,
_marker: std::marker::PhantomData,
};
Ok(res)
} else {
Err(Error::ExpectedExternalPtrType(
clone,
std::any::type_name::<T>().into(),
))
}
}
}
impl<T: Any + Debug> TryFrom<Robj> for ExternalPtr<T> {
type Error = Error;
fn try_from(robj: Robj) -> Result<Self> {
<ExternalPtr<T>>::try_from(&robj)
}
}
impl<T: Any + Debug> From<ExternalPtr<T>> for Robj {
fn from(val: ExternalPtr<T>) -> Self {
val.robj
}
}
impl<T: Debug + 'static> std::fmt::Debug for ExternalPtr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(&**self as &T).fmt(f)
}
}