extendr_api/wrapper/
externalptr.rs1use super::*;
21use extendr_ffi::{
22 R_ClearExternalPtr, R_ExternalPtrAddr, R_ExternalPtrProtected, R_ExternalPtrTag,
23 R_MakeExternalPtr, R_NilValue, R_SetExternalPtrTag,
24};
25use std::{any::Any, fmt::Debug};
26#[repr(transparent)]
39pub struct ExternalPtr<T> {
40 pub(crate) robj: Robj,
42
43 _marker: std::marker::PhantomData<T>,
45}
46
47impl<T> PartialEq for ExternalPtr<T> {
50 fn eq(&self, other: &Self) -> bool {
51 self.robj == other.robj && self._marker == other._marker
52 }
53}
54
55impl<T> Clone for ExternalPtr<T> {
57 fn clone(&self) -> Self {
58 Self {
59 robj: self.robj.clone(),
60 _marker: self._marker,
61 }
62 }
63}
64
65impl<T> robj::GetSexp for ExternalPtr<T> {
66 unsafe fn get(&self) -> SEXP {
67 self.robj.get()
68 }
69
70 unsafe fn get_mut(&mut self) -> SEXP {
71 self.robj.get_mut()
72 }
73
74 fn as_robj(&self) -> &Robj {
76 &self.robj
77 }
78
79 fn as_robj_mut(&mut self) -> &mut Robj {
81 &mut self.robj
82 }
83}
84
85impl<T> Length for ExternalPtr<T> {}
87
88impl<T> Types for ExternalPtr<T> {}
90
91impl<T> Attributes for ExternalPtr<T> {}
93
94impl<T> Conversions for ExternalPtr<T> {}
96
97impl<T> Rinternals for ExternalPtr<T> {}
99
100impl<T> Slices for ExternalPtr<T> {}
102
103impl<T> Operators for ExternalPtr<T> {}
105
106impl<T: 'static> Deref for ExternalPtr<T> {
107 type Target = T;
108
109 fn deref(&self) -> &Self::Target {
111 self.addr()
112 }
113}
114
115impl<T: 'static> DerefMut for ExternalPtr<T> {
116 fn deref_mut(&mut self) -> &mut Self::Target {
118 self.addr_mut()
119 }
120}
121
122impl<T: 'static> ExternalPtr<T> {
123 pub fn new(val: T) -> Self {
130 single_threaded(|| unsafe {
131 let boxed: Box<dyn Any> = Box::new(val);
133 let boxed: Box<Box<dyn Any>> = Box::new(boxed);
134
135 let robj = {
138 let boxed_ptr = Box::into_raw(boxed);
139 let prot = Robj::null();
140 let type_name: Robj = std::any::type_name::<T>().into();
141
142 Robj::from_sexp(single_threaded(|| {
143 R_MakeExternalPtr(boxed_ptr.cast(), type_name.get(), prot.get())
144 }))
145 };
146
147 extern "C" fn finalizer(x: SEXP) {
148 unsafe {
149 let ptr = R_ExternalPtrAddr(x).cast::<Box<dyn Any>>();
150
151 R_SetExternalPtrTag(x, R_NilValue);
153
154 drop(Box::from_raw(ptr));
157
158 R_ClearExternalPtr(x);
160 }
161 }
162
163 robj.register_c_finalizer(Some(finalizer));
165
166 Self {
168 robj,
169 _marker: std::marker::PhantomData,
170 }
171 })
172 }
173
174 pub fn tag(&self) -> Robj {
178 unsafe { Robj::from_sexp(R_ExternalPtrTag(self.robj.get())) }
179 }
180
181 pub fn protected(&self) -> Robj {
183 unsafe { Robj::from_sexp(R_ExternalPtrProtected(self.robj.get())) }
184 }
185
186 pub fn addr(&self) -> &T {
193 self.try_addr().unwrap()
194 }
195
196 pub fn addr_mut(&mut self) -> &mut T {
203 self.try_addr_mut().unwrap()
204 }
205
206 pub fn try_addr(&self) -> Result<&T> {
213 unsafe {
214 R_ExternalPtrAddr(self.robj.get())
215 .cast::<Box<dyn Any>>()
216 .as_ref()
217 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(self.robj.clone()))
218 .and_then(|x| {
219 x.downcast_ref::<T>().ok_or_else(|| {
220 Error::ExpectedExternalPtrType(
221 self.robj.clone(),
222 std::any::type_name::<T>().to_string(),
223 )
224 })
225 })
226 }
227 }
228
229 pub fn try_addr_mut(&mut self) -> Result<&mut T> {
236 unsafe {
237 R_ExternalPtrAddr(self.robj.get_mut())
238 .cast::<Box<dyn Any>>()
239 .as_mut()
240 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(self.robj.clone()))
241 .and_then(|x| {
242 x.downcast_mut::<T>().ok_or_else(|| {
243 Error::ExpectedExternalPtrType(
244 self.robj.clone(),
245 std::any::type_name::<T>().to_string(),
246 )
247 })
248 })
249 }
250 }
251}
252
253impl<T: 'static> TryFrom<&Robj> for &ExternalPtr<T> {
254 type Error = Error;
255
256 fn try_from(value: &Robj) -> Result<Self> {
257 if !value.is_external_pointer() {
258 return Err(Error::ExpectedExternalPtr(value.clone()));
259 }
260
261 let boxed_ptr = unsafe {
263 value
264 .external_ptr_addr::<Box<dyn Any>>()
265 .cast_const()
266 .as_ref()
267 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(value.clone()))?
268 };
269
270 if boxed_ptr.downcast_ref::<T>().is_none() {
271 return Err(Error::ExpectedExternalPtrType(
272 value.clone(),
273 std::any::type_name::<T>().to_string(),
274 ));
275 }
276
277 unsafe { Ok(std::mem::transmute::<&Robj, &ExternalPtr<T>>(value)) }
278 }
279}
280
281impl<T: 'static> TryFrom<&mut Robj> for &mut ExternalPtr<T> {
282 type Error = Error;
283
284 fn try_from(value: &mut Robj) -> Result<Self> {
285 if !value.is_external_pointer() {
286 return Err(Error::ExpectedExternalPtr(value.clone()));
287 }
288
289 let boxed_ptr = unsafe {
291 value
292 .external_ptr_addr::<Box<dyn Any>>()
293 .cast_const()
294 .as_ref()
295 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(value.clone()))?
296 };
297
298 if boxed_ptr.downcast_ref::<T>().is_none() {
299 return Err(Error::ExpectedExternalPtrType(
300 value.clone(),
301 std::any::type_name::<T>().to_string(),
302 ));
303 }
304
305 unsafe { Ok(std::mem::transmute::<&mut Robj, &mut ExternalPtr<T>>(value)) }
306 }
307}
308
309impl<T: 'static> TryFrom<&Robj> for ExternalPtr<T> {
310 type Error = Error;
311
312 fn try_from(robj: &Robj) -> Result<Self> {
313 let result: &Self = robj.try_into()?;
314 Ok(result.clone())
315 }
316}
317
318impl<T: 'static> TryFrom<Robj> for ExternalPtr<T> {
319 type Error = Error;
320
321 fn try_from(robj: Robj) -> Result<Self> {
322 <ExternalPtr<T>>::try_from(&robj)
323 }
324}
325
326impl<T> From<ExternalPtr<T>> for Robj {
327 fn from(val: ExternalPtr<T>) -> Self {
328 val.robj
329 }
330}
331
332impl<T> From<Option<ExternalPtr<T>>> for Robj {
333 fn from(value: Option<ExternalPtr<T>>) -> Self {
334 match value {
335 None => nil_value(),
336 Some(value) => value.into(),
337 }
338 }
339}
340
341impl<T: Debug + 'static> std::fmt::Debug for ExternalPtr<T> {
342 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343 (&**self as &T).fmt(f)
344 }
345}
346
347impl<T: 'static> AsRef<T> for ExternalPtr<T> {
348 fn as_ref(&self) -> &T {
349 self.addr()
350 }
351}
352
353impl<T: 'static> AsMut<T> for ExternalPtr<T> {
354 fn as_mut(&mut self) -> &mut T {
355 self.addr_mut()
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use std::error::Error;
362
363 use super::*;
364 use extendr_engine::with_r;
365
366 #[derive(Debug)]
367 struct BareWrapper(i32);
368
369 #[test]
370 fn externalptr_is_ptr() -> std::result::Result<(), Box<dyn Error>> {
371 with_r(|| {
372 let a = BareWrapper(42);
373 let b = BareWrapper(42);
374 assert_eq!(a.0, b.0);
375
376 let a_ptr = std::ptr::addr_of!(a);
377 let b_ptr = std::ptr::addr_of!(b);
378 let a_externalptr = ExternalPtr::new(a);
379 let b_externalptr = ExternalPtr::new(b);
380
381 assert_ne!(
382 a_ptr, b_ptr,
383 "pointers has to be equal by address, not value"
384 );
385
386 assert_ne!(
387 a_externalptr.robj, b_externalptr.robj,
388 "R only knows about the pointer, and not the pointee"
389 );
390 assert_ne!(
391 a_externalptr, b_externalptr,
392 "ExternalPtr acts exactly like a pointer"
393 );
394 assert_ne!(&a_externalptr, &b_externalptr,);
395 Ok(())
396 })
397 }
398
399 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
400 struct Wrapper(i32);
401
402 #[test]
403 fn compare_externalptr_pointee() -> std::result::Result<(), Box<dyn Error>> {
404 with_r(|| {
405 let a = Wrapper(42);
406 let b = Wrapper(42);
407 let a_externalptr = ExternalPtr::new(a);
408 let b_externalptr = ExternalPtr::new(b);
409 assert_eq!(a_externalptr.as_ref(), b_externalptr.as_ref());
410
411 let a_externalptr = ExternalPtr::new(Wrapper(50));
413 let b_externalptr = ExternalPtr::new(Wrapper(60));
414 assert!(a_externalptr.as_ref() <= b_externalptr.as_ref());
415 assert_eq!(
416 a_externalptr.as_ref().max(b_externalptr.as_ref()),
417 &Wrapper(60)
418 );
419 Ok(())
420 })
421 }
422}