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::from(());
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 .map(|x| x.downcast_ref::<T>().unwrap())
219 }
220 }
221
222 pub fn try_addr_mut(&mut self) -> Result<&mut T> {
229 unsafe {
230 R_ExternalPtrAddr(self.robj.get_mut())
231 .cast::<Box<dyn Any>>()
232 .as_mut()
233 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(self.robj.clone()))
234 .map(|x| x.downcast_mut::<T>().unwrap())
235 }
236 }
237}
238
239impl<T: 'static> TryFrom<&Robj> for &ExternalPtr<T> {
240 type Error = Error;
241
242 fn try_from(value: &Robj) -> Result<Self> {
243 if !value.is_external_pointer() {
244 return Err(Error::ExpectedExternalPtr(value.clone()));
245 }
246
247 let boxed_ptr = unsafe {
249 value
250 .external_ptr_addr::<Box<dyn Any>>()
251 .cast_const()
252 .as_ref()
253 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(value.clone()))?
254 };
255
256 if boxed_ptr.downcast_ref::<T>().is_none() {
257 return Err(Error::ExpectedExternalPtrType(
258 value.clone(),
259 std::any::type_name::<T>().to_string(),
260 ));
261 }
262
263 unsafe { Ok(std::mem::transmute::<&Robj, &ExternalPtr<T>>(value)) }
264 }
265}
266
267impl<T: 'static> TryFrom<&mut Robj> for &mut ExternalPtr<T> {
268 type Error = Error;
269
270 fn try_from(value: &mut Robj) -> Result<Self> {
271 if !value.is_external_pointer() {
272 return Err(Error::ExpectedExternalPtr(value.clone()));
273 }
274
275 let boxed_ptr = unsafe {
277 value
278 .external_ptr_addr::<Box<dyn Any>>()
279 .cast_const()
280 .as_ref()
281 .ok_or_else(|| Error::ExpectedExternalNonNullPtr(value.clone()))?
282 };
283
284 if boxed_ptr.downcast_ref::<T>().is_none() {
285 return Err(Error::ExpectedExternalPtrType(
286 value.clone(),
287 std::any::type_name::<T>().to_string(),
288 ));
289 }
290
291 unsafe { Ok(std::mem::transmute::<&mut Robj, &mut ExternalPtr<T>>(value)) }
292 }
293}
294
295impl<T: 'static> TryFrom<Robj> for &ExternalPtr<T> {
296 type Error = Error;
297
298 fn try_from(value: Robj) -> Result<Self> {
299 (&value).try_into()
300 }
301}
302
303impl<T: 'static> TryFrom<Robj> for &mut ExternalPtr<T> {
304 type Error = Error;
305
306 fn try_from(mut value: Robj) -> Result<Self> {
307 (&mut value).try_into()
308 }
309}
310
311impl<T: 'static> TryFrom<&Robj> for ExternalPtr<T> {
312 type Error = Error;
313
314 fn try_from(robj: &Robj) -> Result<Self> {
315 let result: &Self = robj.try_into()?;
316 Ok(result.clone())
317 }
318}
319
320impl<T: 'static> TryFrom<Robj> for ExternalPtr<T> {
321 type Error = Error;
322
323 fn try_from(robj: Robj) -> Result<Self> {
324 <ExternalPtr<T>>::try_from(&robj)
325 }
326}
327
328impl<T> From<ExternalPtr<T>> for Robj {
329 fn from(val: ExternalPtr<T>) -> Self {
330 val.robj
331 }
332}
333
334impl<T> From<Option<ExternalPtr<T>>> for Robj {
335 fn from(value: Option<ExternalPtr<T>>) -> Self {
336 match value {
337 None => nil_value(),
338 Some(value) => value.into(),
339 }
340 }
341}
342
343impl<T: Debug + 'static> std::fmt::Debug for ExternalPtr<T> {
344 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
345 (&**self as &T).fmt(f)
346 }
347}
348
349impl<T: 'static> AsRef<T> for ExternalPtr<T> {
350 fn as_ref(&self) -> &T {
351 self.addr()
352 }
353}
354
355impl<T: 'static> AsMut<T> for ExternalPtr<T> {
356 fn as_mut(&mut self) -> &mut T {
357 self.addr_mut()
358 }
359}
360
361#[cfg(test)]
362mod tests {
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() {
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 });
396 }
397
398 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
399 struct Wrapper(i32);
400
401 #[test]
402 fn compare_externalptr_pointee() {
403 with_r(|| {
404 let a = Wrapper(42);
405 let b = Wrapper(42);
406 let a_externalptr = ExternalPtr::new(a);
407 let b_externalptr = ExternalPtr::new(b);
408 assert_eq!(a_externalptr.as_ref(), b_externalptr.as_ref());
409
410 let a_externalptr = ExternalPtr::new(Wrapper(50));
412 let b_externalptr = ExternalPtr::new(Wrapper(60));
413 assert!(a_externalptr.as_ref() <= b_externalptr.as_ref());
414 assert_eq!(
415 a_externalptr.as_ref().max(b_externalptr.as_ref()),
416 &Wrapper(60)
417 )
418 });
419 }
420}