Skip to main content

miniextendr_api/externalptr/
borrowed.rs

1//! Borrowed handles over ordinary or erased external-pointer storage.
2
3use super::{TypedExternal, borrow_value, borrow_value_mut};
4use crate::SEXP;
5use core::cell::{Ref, RefCell, RefMut};
6use core::fmt;
7use core::marker::PhantomData;
8use core::ops::{Deref, DerefMut};
9
10mod sealed {
11    pub trait Owner {}
12}
13
14/// A handle that reaches a concrete value together with its R object, for
15/// the sidecar accessors.
16///
17/// Implemented by [`ExternalPtr`](super::ExternalPtr), [`ExternalPtrRef`]
18/// and [`ExternalPtrMut`]. Generated sidecar getters accept any of these
19/// handles: an `ExternalPtr` borrows its value for the read, a view already
20/// holds the borrow. Implementations are sealed because the owner and data
21/// must describe the same allocation.
22pub trait SidecarOwner<T: TypedExternal + ?Sized>: sealed::Owner {
23    /// The value, borrowed shared, with its R object; or, for a [`Saved`]
24    /// handle, the restored pointer alone.
25    #[doc(hidden)]
26    fn __mx_read(&self) -> SidecarRead<'_, T>;
27}
28
29/// What a [`SidecarOwner`] gives the generated getters.
30#[doc(hidden)]
31pub enum SidecarRead<'a, T: TypedExternal + ?Sized> {
32    /// A live value, whose pending `Sidecar` values the getter flushes first.
33    Live(ExternalPtrRef<'a, T>),
34    /// A pointer restored from a saved session: its slots hold the saved
35    /// values, and there is no value yet.
36    Saved(SEXP),
37}
38
39/// What a save of a `T` kept, handed to the type's rebuild hook
40/// (`#[externalptr(rebuild = path)]`) when a pointer restored from a saved
41/// session is first used.
42///
43/// The type's generated `Sidecar` getters read the saved values through it,
44/// as through a live handle: `Self::keys(saved)`. Only `Sidecar` fields have
45/// a slot in the save; a struct field or a `Computed` field is gone with the
46/// Rust value, so a type whose rebuild needs one keeps it in a `Sidecar`.
47///
48/// The save names its slots after the fields' R names (the
49/// `#[r_data(name = "..")]` value, else the Rust field name), so a field is
50/// read by name whatever fields the version that saved it had (#2187,
51/// #2215). A field the save
52/// lacks (added since) reads as `None` through the generated
53/// `Self::try_keys(saved)`; the plain getter raises the classed error
54/// [`RESTORED_MISSING_SLOT_CLASS`](super::RESTORED_MISSING_SLOT_CLASS).
55pub struct Saved<'a, T: TypedExternal + ?Sized> {
56    sexp: SEXP,
57    _marker: PhantomData<&'a T>,
58}
59
60impl<T: TypedExternal + ?Sized> Saved<'_, T> {
61    /// The handle over `sexp`, a pointer for a `T` restored without its
62    /// value.
63    ///
64    /// # Safety
65    ///
66    /// `sexp` must be a live `EXTPTRSXP` built by `ExternalPtr` for a `T` by
67    /// some version of its crate, rooted for the handle's lifetime.
68    pub(crate) unsafe fn new(sexp: SEXP) -> Self {
69        Self {
70            sexp,
71            _marker: PhantomData,
72        }
73    }
74
75    /// The restored external pointer.
76    pub fn as_sexp(&self) -> SEXP {
77        self.sexp
78    }
79
80    /// Whether the save has a slot for the `Sidecar` field `field`, given by
81    /// its R name: the `#[r_data(name = "..")]` value, else the Rust field
82    /// name. The generated `Self::try_<field>(saved)` getters say the same
83    /// with the field's type, checked by the compiler.
84    ///
85    /// The R name is the save format (#2215): a save names each slot after
86    /// it. Renaming the Rust field keeps earlier saves readable; renaming the
87    /// R name orphans the field's slot in every earlier save, which then
88    /// reads as a field the save lacks.
89    pub fn has(&self, field: &str) -> bool {
90        // SAFETY: on R's main thread (a hook runs there); the pointer is live.
91        let prot = unsafe { crate::sys::R_ExternalPtrProtected(self.sexp) };
92        T::SIDECAR_NAMES
93            .iter()
94            .position(|name| *name == field)
95            .is_some_and(|index| super::sidecar::saved_slot(prot, index, field).is_some())
96    }
97
98    /// The version of the crate that saved the object, from the type ID the
99    /// save recorded: the current version for a save this version made, an
100    /// earlier (or later) one under `any_version`.
101    pub fn version(&self) -> Option<&'static str> {
102        // SAFETY: on R's main thread; the pointer is live.
103        let sym = unsafe { super::stored_type_id_symbol(self.sexp) }?;
104        super::split_type_id(super::symbol_name(sym)).1
105    }
106}
107
108impl<T: TypedExternal + ?Sized> fmt::Debug for Saved<'_, T> {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        f.debug_struct("Saved")
111            .field("type", &T::TYPE_NAME)
112            .finish()
113    }
114}
115
116/// A handle accepted by generated sidecar setters: an
117/// [`ExternalPtr`](super::ExternalPtr), which borrows its value exclusively
118/// for the write, or an [`ExternalPtrMut`].
119pub trait SidecarOwnerMut<T: TypedExternal + ?Sized>: SidecarOwner<T> {
120    /// The value, borrowed exclusively, with its R object.
121    #[doc(hidden)]
122    fn __mx_write(&mut self) -> ExternalPtrMut<'_, T>;
123}
124
125/// Where a shared view gets its value: the `RefCell` borrow it holds, or a
126/// view it was reborrowed from.
127enum Shared<'a, T: ?Sized> {
128    Guard(Ref<'a, T>),
129    Reborrow(&'a T),
130}
131
132/// Where an exclusive view gets its value, like [`Shared`].
133enum Exclusive<'a, T: ?Sized> {
134    Guard(RefMut<'a, T>),
135    Reborrow(&'a mut T),
136}
137
138/// A shared borrow of a Rust value together with its R object.
139///
140/// [`ExternalPtr::borrow`](super::ExternalPtr::borrow) makes one, and a
141/// `#[miniextendr]` function or method takes one as a parameter (or as
142/// `self: ExternalPtrRef<'_, Self>`) when it needs the R object as well as
143/// the value: the sidecar accessors, the object's identity
144/// ([`ExternalPtrRef::as_sexp`]). A body that needs only the value takes
145/// `&T`.
146///
147/// The view holds a shared borrow of the value's `RefCell` for its whole
148/// lifetime: a method of the same object that needs it mutably, a `&mut T`
149/// argument holding it, or [`ExternalPtr::borrow_mut`](super::ExternalPtr::borrow_mut)
150/// meanwhile raises the R error of class `miniextendr_borrow_conflict`. It
151/// never owns or consumes the value, can represent ordinary `Any` storage or
152/// erased trait-ABI storage, and cannot cross threads. Pass it on without
153/// moving it with [`rb`](Self::rb).
154///
155/// A borrowed handle cannot outlive its owner:
156/// ```compile_fail,E0515
157/// use miniextendr_api::{ExternalPtr, ExternalPtrRef, TypedExternal};
158/// fn escape<T: TypedExternal>(owner: ExternalPtr<T>) -> ExternalPtrRef<'static, T> {
159///     owner.borrow()
160/// }
161/// ```
162pub struct ExternalPtrRef<'a, T: TypedExternal + ?Sized> {
163    value: Shared<'a, T>,
164    owner: &'a SEXP,
165    _main_thread: PhantomData<*mut ()>,
166}
167
168/// An exclusive borrow of a Rust value together with its R object.
169///
170/// [`ExternalPtr::borrow_mut`](super::ExternalPtr::borrow_mut) makes one, and
171/// a `#[miniextendr]` function or method takes one as a parameter (or as
172/// `self: ExternalPtrMut<'_, Self>`) when it needs the R object as well as
173/// the value, like [`ExternalPtrRef`]. Dereferencing gives mutable access to
174/// the Rust fields; the sidecar setters use the R object. There is no
175/// consuming API.
176///
177/// The view holds an exclusive borrow of the value's `RefCell` for its whole
178/// lifetime: any other borrow of the value meanwhile raises the R error of
179/// class `miniextendr_borrow_conflict`. Pass it on without moving it with
180/// [`rb_mut`](Self::rb_mut), or as a shared view with [`rb`](Self::rb).
181///
182/// A view borrows its handle for as long as it lives:
183/// ```compile_fail,E0502
184/// use miniextendr_api::{ExternalPtr, ExternalPtrMut, ExternalPtrRef, TypedExternal};
185/// fn overlap<T: TypedExternal>(owner: &mut ExternalPtr<T>) {
186///     let mut first = owner.borrow_mut();
187///     let second = owner.borrow();
188///     let _ = (&mut *first, second);
189/// }
190/// ```
191///
192/// A reborrow ends before the view is used again:
193/// ```compile_fail,E0499
194/// use miniextendr_api::{ExternalPtrMut, TypedExternal};
195/// fn twice<T: TypedExternal>(view: &mut ExternalPtrMut<'_, T>) {
196///     let first = view.rb_mut();
197///     let second = view.rb_mut();
198///     let _ = (first, second);
199/// }
200/// ```
201pub struct ExternalPtrMut<'a, T: TypedExternal + ?Sized> {
202    value: Exclusive<'a, T>,
203    owner: &'a SEXP,
204    _main_thread: PhantomData<*mut ()>,
205}
206
207impl<'a, T: TypedExternal + ?Sized> ExternalPtrRef<'a, T> {
208    /// Hold `guard`, a borrow of the value of the R object `owner`.
209    #[inline]
210    pub(super) fn from_guard(owner: &'a SEXP, guard: Ref<'a, T>) -> Self {
211        Self {
212            value: Shared::Guard(guard),
213            owner,
214            _main_thread: PhantomData,
215        }
216    }
217
218    /// A shared view of the same value for a shorter lifetime, to pass on
219    /// without moving this one. The value stays borrowed until this view
220    /// drops.
221    #[inline]
222    pub fn rb(&self) -> ExternalPtrRef<'_, T> {
223        ExternalPtrRef {
224            value: Shared::Reborrow(&**self),
225            owner: self.owner,
226            _main_thread: PhantomData,
227        }
228    }
229
230    /// The R object (`EXTPTRSXP`) holding the value.
231    ///
232    /// An associated function, `ExternalPtrRef::as_sexp(&view)`, so that it
233    /// doesn't hide a method of `T` of the same name.
234    #[inline]
235    pub fn as_sexp(this: &Self) -> SEXP {
236        *this.owner
237    }
238}
239
240impl<'a, T: TypedExternal> ExternalPtrRef<'a, T> {
241    /// Borrow a receiver after its type and argument aliases have been checked.
242    ///
243    /// # Safety
244    /// R's main thread; `cell` must point to the live `RefCell<T>` owned by
245    /// `owner`, whose initialized sidecar slots use `T`'s layout. Its SEXP must
246    /// stay rooted for `'a`; the slot reference alone does not root it. The cell
247    /// must remain valid for `'a`.
248    #[doc(hidden)]
249    pub unsafe fn from_raw_parts(owner: &'a SEXP, cell: *const RefCell<T>) -> Self {
250        Self::from_guard(owner, borrow_value(unsafe { &*cell }))
251    }
252}
253
254impl<'a, T: TypedExternal + ?Sized> ExternalPtrMut<'a, T> {
255    /// Hold `guard`, an exclusive borrow of the value of the R object `owner`.
256    #[inline]
257    pub(super) fn from_guard(owner: &'a SEXP, guard: RefMut<'a, T>) -> Self {
258        Self {
259            value: Exclusive::Guard(guard),
260            owner,
261            _main_thread: PhantomData,
262        }
263    }
264
265    /// A shared view of the same value, for as long as this view isn't used
266    /// mutably.
267    #[inline]
268    pub fn rb(&self) -> ExternalPtrRef<'_, T> {
269        ExternalPtrRef {
270            value: Shared::Reborrow(&**self),
271            owner: self.owner,
272            _main_thread: PhantomData,
273        }
274    }
275
276    /// An exclusive view of the same value for a shorter lifetime, to pass on
277    /// without moving this one.
278    #[inline]
279    pub fn rb_mut(&mut self) -> ExternalPtrMut<'_, T> {
280        let owner = self.owner;
281        ExternalPtrMut {
282            value: Exclusive::Reborrow(&mut **self),
283            owner,
284            _main_thread: PhantomData,
285        }
286    }
287
288    /// The R object (`EXTPTRSXP`) holding the value.
289    ///
290    /// An associated function, `ExternalPtrMut::as_sexp(&view)`, so that it
291    /// doesn't hide a method of `T` of the same name.
292    #[inline]
293    pub fn as_sexp(this: &Self) -> SEXP {
294        *this.owner
295    }
296}
297
298impl<'a, T: TypedExternal> ExternalPtrMut<'a, T> {
299    /// Borrow a receiver after its type and argument aliases have been checked.
300    ///
301    /// # Safety
302    /// R's main thread; `cell` must point to the live `RefCell<T>` owned by
303    /// `owner`, whose initialized sidecar slots use `T`'s layout. Its SEXP must
304    /// stay rooted for `'a`; the slot reference alone does not root it. The cell
305    /// must remain valid for `'a`.
306    #[doc(hidden)]
307    pub unsafe fn from_raw_parts(owner: &'a SEXP, cell: *const RefCell<T>) -> Self {
308        Self::from_guard(owner, borrow_value_mut(unsafe { &*cell }))
309    }
310}
311
312impl<T: TypedExternal + ?Sized> Deref for ExternalPtrRef<'_, T> {
313    type Target = T;
314    #[inline]
315    fn deref(&self) -> &T {
316        match &self.value {
317            Shared::Guard(guard) => guard,
318            Shared::Reborrow(value) => value,
319        }
320    }
321}
322impl<T: TypedExternal + ?Sized> Deref for ExternalPtrMut<'_, T> {
323    type Target = T;
324    #[inline]
325    fn deref(&self) -> &T {
326        match &self.value {
327            Exclusive::Guard(guard) => guard,
328            Exclusive::Reborrow(value) => value,
329        }
330    }
331}
332impl<T: TypedExternal + ?Sized> DerefMut for ExternalPtrMut<'_, T> {
333    #[inline]
334    fn deref_mut(&mut self) -> &mut T {
335        match &mut self.value {
336            Exclusive::Guard(guard) => guard,
337            Exclusive::Reborrow(value) => value,
338        }
339    }
340}
341
342impl<T: TypedExternal + ?Sized + fmt::Debug> fmt::Debug for ExternalPtrRef<'_, T> {
343    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344        fmt::Debug::fmt(&**self, f)
345    }
346}
347impl<T: TypedExternal + ?Sized + fmt::Debug> fmt::Debug for ExternalPtrMut<'_, T> {
348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349        fmt::Debug::fmt(&**self, f)
350    }
351}
352impl<T: TypedExternal + ?Sized + fmt::Display> fmt::Display for ExternalPtrRef<'_, T> {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        fmt::Display::fmt(&**self, f)
355    }
356}
357impl<T: TypedExternal + ?Sized + fmt::Display> fmt::Display for ExternalPtrMut<'_, T> {
358    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359        fmt::Display::fmt(&**self, f)
360    }
361}
362
363impl<T: TypedExternal> sealed::Owner for super::ExternalPtr<T> {}
364impl<T: TypedExternal + ?Sized> sealed::Owner for ExternalPtrRef<'_, T> {}
365impl<T: TypedExternal + ?Sized> sealed::Owner for ExternalPtrMut<'_, T> {}
366
367impl<T: TypedExternal + ?Sized> sealed::Owner for Saved<'_, T> {}
368
369impl<T: TypedExternal> SidecarOwner<T> for super::ExternalPtr<T> {
370    fn __mx_read(&self) -> SidecarRead<'_, T> {
371        SidecarRead::Live(self.borrow())
372    }
373}
374impl<T: TypedExternal + ?Sized> SidecarOwner<T> for ExternalPtrRef<'_, T> {
375    fn __mx_read(&self) -> SidecarRead<'_, T> {
376        SidecarRead::Live(self.rb())
377    }
378}
379impl<T: TypedExternal + ?Sized> SidecarOwner<T> for ExternalPtrMut<'_, T> {
380    fn __mx_read(&self) -> SidecarRead<'_, T> {
381        SidecarRead::Live(self.rb())
382    }
383}
384impl<T: TypedExternal + ?Sized> SidecarOwner<T> for Saved<'_, T> {
385    fn __mx_read(&self) -> SidecarRead<'_, T> {
386        SidecarRead::Saved(self.sexp)
387    }
388}
389impl<T: TypedExternal> SidecarOwnerMut<T> for super::ExternalPtr<T> {
390    fn __mx_write(&mut self) -> ExternalPtrMut<'_, T> {
391        self.borrow_mut()
392    }
393}
394impl<T: TypedExternal + ?Sized> SidecarOwnerMut<T> for ExternalPtrMut<'_, T> {
395    fn __mx_write(&mut self) -> ExternalPtrMut<'_, T> {
396        self.rb_mut()
397    }
398}