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}