facet_core/types/
smartptr.rs

1use bitflags::bitflags;
2
3use crate::{PtrConst, PtrMut, PtrUninit};
4
5use super::Shape;
6
7/// Describes a smart pointer — including a vtable to query and alter its state,
8/// and the inner shape (the pointee type in the smart pointer).
9#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
10#[repr(C)]
11#[non_exhaustive]
12pub struct SmartPointerDef {
13    /// vtable for interacting with the smart pointer
14    pub vtable: &'static SmartPointerVTable,
15
16    /// shape of the inner type of the smart pointer, if not opaque
17    pub pointee: Option<&'static Shape>,
18
19    /// shape of the corresponding strong pointer, if this pointer is weak
20    pub weak: Option<fn() -> &'static Shape>,
21
22    /// shape of the corresponding non-atomic pointer, if this pointer is atomic
23    pub strong: Option<fn() -> &'static Shape>,
24
25    /// Flags representing various characteristics of the smart pointer
26    pub flags: SmartPointerFlags,
27
28    /// An optional field to identify the kind of smart pointer
29    pub known: Option<KnownSmartPointer>,
30}
31
32impl SmartPointerDef {
33    /// Creates a new `SmartPointerDefBuilder` with all fields set to `None`.
34    #[must_use]
35    pub const fn builder() -> SmartPointerDefBuilder {
36        SmartPointerDefBuilder {
37            vtable: None,
38            pointee: None,
39            flags: None,
40            known: None,
41            weak: None,
42            strong: None,
43        }
44    }
45}
46
47/// Builder for creating a `SmartPointerDef`.
48#[derive(Debug)]
49#[allow(clippy::new_without_default)]
50pub struct SmartPointerDefBuilder {
51    vtable: Option<&'static SmartPointerVTable>,
52    pointee: Option<&'static Shape>,
53    flags: Option<SmartPointerFlags>,
54    known: Option<KnownSmartPointer>,
55    weak: Option<fn() -> &'static Shape>,
56    strong: Option<fn() -> &'static Shape>,
57}
58
59impl SmartPointerDefBuilder {
60    /// Creates a new `SmartPointerDefBuilder` with all fields set to `None`.
61    #[must_use]
62    #[allow(clippy::new_without_default)]
63    pub const fn new() -> Self {
64        Self {
65            vtable: None,
66            pointee: None,
67            flags: None,
68            known: None,
69            weak: None,
70            strong: None,
71        }
72    }
73
74    /// Sets the vtable for the smart pointer.
75    #[must_use]
76    pub const fn vtable(mut self, vtable: &'static SmartPointerVTable) -> Self {
77        self.vtable = Some(vtable);
78        self
79    }
80
81    /// Sets the shape of the inner type of the smart pointer.
82    #[must_use]
83    pub const fn pointee(mut self, pointee: &'static Shape) -> Self {
84        self.pointee = Some(pointee);
85        self
86    }
87
88    /// Sets the flags for the smart pointer.
89    #[must_use]
90    pub const fn flags(mut self, flags: SmartPointerFlags) -> Self {
91        self.flags = Some(flags);
92        self
93    }
94
95    /// Sets the known smart pointer type.
96    #[must_use]
97    pub const fn known(mut self, known: KnownSmartPointer) -> Self {
98        self.known = Some(known);
99        self
100    }
101
102    /// Sets the shape of the corresponding strong pointer, if this pointer is weak.
103    #[must_use]
104    pub const fn weak(mut self, weak: fn() -> &'static Shape) -> Self {
105        self.weak = Some(weak);
106        self
107    }
108
109    /// Sets the shape of the corresponding non-atomic pointer, if this pointer is atomic.
110    #[must_use]
111    pub const fn strong(mut self, strong: fn() -> &'static Shape) -> Self {
112        self.strong = Some(strong);
113        self
114    }
115
116    /// Builds a `SmartPointerDef` from the provided configuration.
117    ///
118    /// # Panics
119    ///
120    /// Panics if any required field (vtable, pointee, flags) is not set.
121    #[must_use]
122    pub const fn build(self) -> SmartPointerDef {
123        SmartPointerDef {
124            vtable: self.vtable.unwrap(),
125            pointee: self.pointee,
126            weak: self.weak,
127            strong: self.strong,
128            flags: self.flags.unwrap(),
129            known: self.known,
130        }
131    }
132}
133
134bitflags! {
135    /// Flags to represent various characteristics of smart pointers
136    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
137    pub struct SmartPointerFlags: u8 {
138        /// An empty set of flags
139        const EMPTY = 0;
140
141        /// Whether the smart pointer is weak (like [`std::sync::Weak`])
142        const WEAK = 1 << 0;
143        /// Whether the smart pointer is atomic (like [`std::sync::Arc`])
144        const ATOMIC = 1 << 1;
145        /// Whether the pointer is a lock (like [`std::sync::Mutex`])
146        const LOCK = 1 << 2;
147    }
148}
149
150/// Tries to upgrade the weak pointer to a strong one.
151///
152/// # Safety
153///
154/// `weak` must be a valid weak smart pointer (like [`std::sync::Weak`] or [`std::rc::Weak`]).
155/// `strong` must be allocated, and of the right layout for the corresponding smart pointer.
156/// `strong` must not have been initialized yet.
157///
158/// `weak` is not moved out of — `Weak::upgrade(&self)` takes self by reference.
159/// If this fails, `strong` is not initialized.
160///
161/// `strong.assume_init()` is returned as part of the Option if the upgrade succeeds.
162/// `None` is returned if this is not a type of smart pointer that supports upgrades.
163pub type UpgradeIntoFn =
164    for<'ptr> unsafe fn(weak: PtrMut<'ptr>, strong: PtrUninit<'ptr>) -> Option<PtrMut<'ptr>>;
165
166/// Downgrades a strong pointer to a weak one.
167///
168/// Only strong pointers can be downgraded (like [`std::sync::Arc`] or [`std::rc::Rc`]).
169///
170/// # Safety
171///
172/// `strong` must be a valid strong smart pointer (like [`std::sync::Arc`] or [`std::rc::Rc`]).
173/// `weak` must be allocated, and of the right layout for the corresponding weak pointer.
174/// `weak` must not have been initialized yet.
175///
176/// `weak.assume_init()` is returned if the downgrade succeeds.
177pub type DowngradeIntoFn =
178    for<'ptr> unsafe fn(strong: PtrMut<'ptr>, weak: PtrUninit<'ptr>) -> PtrMut<'ptr>;
179
180/// Tries to obtain a reference to the inner value of the smart pointer.
181///
182/// Weak pointers don't even have that function in their vtable.
183pub type BorrowFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> PtrConst<'ptr>;
184
185/// Creates a new smart pointer wrapping the given value. Writes the smart pointer
186/// into the given `this`.
187///
188/// Weak pointers don't even have that function in their vtable.
189///
190/// # Safety
191///
192/// `this` must have the correct layout.
193///
194/// `ptr` must point to a value of type `T`.
195///
196/// After calling this, `ptr` has been moved out of, and must be
197/// deallocated (but not dropped).
198pub type NewIntoFn =
199    for<'ptr> unsafe fn(this: PtrUninit<'ptr>, ptr: PtrConst<'ptr>) -> PtrMut<'ptr>;
200
201/// Type-erased result of locking a mutex-like smart pointer
202pub struct LockResult<'ptr> {
203    /// The data that was locked
204    data: PtrMut<'ptr>,
205    /// The guard that protects the data
206    guard: PtrConst<'ptr>,
207    /// The vtable for the guard
208    guard_vtable: &'static LockGuardVTable,
209}
210
211impl<'ptr> LockResult<'ptr> {
212    /// Returns a reference to the locked data
213    pub fn data(&self) -> &PtrMut<'ptr> {
214        &self.data
215    }
216}
217
218impl Drop for LockResult<'_> {
219    fn drop(&mut self) {
220        unsafe {
221            (self.guard_vtable.drop_in_place)(self.guard);
222        }
223    }
224}
225
226/// Functions for manipulating a guard
227pub struct LockGuardVTable {
228    /// Drops the guard in place
229    pub drop_in_place: for<'ptr> unsafe fn(guard: PtrConst<'ptr>),
230}
231
232/// Acquires a lock on a mutex-like smart pointer
233pub type LockFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
234
235/// Acquires a read lock on a reader-writer lock-like smart pointer
236pub type ReadFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
237
238/// Acquires a write lock on a reader-writer lock-like smart pointer
239pub type WriteFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
240
241/// Functions for interacting with a smart pointer
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
243pub struct SmartPointerVTable {
244    /// See [`UpgradeIntoFn`]
245    pub upgrade_into_fn: Option<UpgradeIntoFn>,
246
247    /// See [`DowngradeIntoFn`]
248    pub downgrade_into_fn: Option<DowngradeIntoFn>,
249
250    /// See [`BorrowFn`]
251    pub borrow_fn: Option<BorrowFn>,
252
253    /// See [`NewIntoFn`]
254    pub new_into_fn: Option<NewIntoFn>,
255
256    /// See [`LockFn`]
257    pub lock_fn: Option<LockFn>,
258
259    /// See [`ReadFn`]
260    pub read_fn: Option<ReadFn>,
261
262    /// See [`WriteFn`]
263    pub write_fn: Option<WriteFn>,
264}
265
266impl SmartPointerVTable {
267    /// Creates a new `SmartPointerVTableBuilder` with all fields set to `None`.
268    #[must_use]
269    pub const fn builder() -> SmartPointerVTableBuilder {
270        SmartPointerVTableBuilder {
271            upgrade_into_fn: None,
272            downgrade_into_fn: None,
273            borrow_fn: None,
274            new_fn: None,
275            lock_fn: None,
276            read_fn: None,
277            write_fn: None,
278        }
279    }
280}
281
282/// Builder for creating a `SmartPointerVTable`.
283#[derive(Debug)]
284pub struct SmartPointerVTableBuilder {
285    upgrade_into_fn: Option<UpgradeIntoFn>,
286    downgrade_into_fn: Option<DowngradeIntoFn>,
287    borrow_fn: Option<BorrowFn>,
288    new_fn: Option<NewIntoFn>,
289    lock_fn: Option<LockFn>,
290    read_fn: Option<ReadFn>,
291    write_fn: Option<WriteFn>,
292}
293
294impl SmartPointerVTableBuilder {
295    /// Creates a new `SmartPointerVTableBuilder` with all fields set to `None`.
296    #[must_use]
297    #[allow(clippy::new_without_default)]
298    pub const fn new() -> Self {
299        Self {
300            upgrade_into_fn: None,
301            downgrade_into_fn: None,
302            borrow_fn: None,
303            new_fn: None,
304            lock_fn: None,
305            read_fn: None,
306            write_fn: None,
307        }
308    }
309
310    /// Sets the try_upgrade function.
311    #[must_use]
312    pub const fn upgrade_into_fn(mut self, upgrade_into_fn: UpgradeIntoFn) -> Self {
313        self.upgrade_into_fn = Some(upgrade_into_fn);
314        self
315    }
316
317    /// Sets the downgrade function.
318    #[must_use]
319    pub const fn downgrade_fn(mut self, downgrade_into_fn: DowngradeIntoFn) -> Self {
320        self.downgrade_into_fn = Some(downgrade_into_fn);
321        self
322    }
323
324    /// Sets the borrow function.
325    #[must_use]
326    pub const fn borrow_fn(mut self, borrow_fn: BorrowFn) -> Self {
327        self.borrow_fn = Some(borrow_fn);
328        self
329    }
330
331    /// Sets the new function.
332    #[must_use]
333    pub const fn new_into_fn(mut self, new_fn: NewIntoFn) -> Self {
334        self.new_fn = Some(new_fn);
335        self
336    }
337
338    /// Sets the lock function.
339    #[must_use]
340    pub const fn lock_fn(mut self, lock_fn: LockFn) -> Self {
341        self.lock_fn = Some(lock_fn);
342        self
343    }
344
345    /// Sets the read function.
346    #[must_use]
347    pub const fn read_fn(mut self, read_fn: ReadFn) -> Self {
348        self.read_fn = Some(read_fn);
349        self
350    }
351
352    /// Sets the write function.
353    #[must_use]
354    pub const fn write_fn(mut self, write_fn: WriteFn) -> Self {
355        self.write_fn = Some(write_fn);
356        self
357    }
358
359    /// Builds a `SmartPointerVTable` from the provided configuration.
360    #[must_use]
361    pub const fn build(self) -> SmartPointerVTable {
362        SmartPointerVTable {
363            upgrade_into_fn: self.upgrade_into_fn,
364            downgrade_into_fn: self.downgrade_into_fn,
365            borrow_fn: self.borrow_fn,
366            new_into_fn: self.new_fn,
367            lock_fn: self.lock_fn,
368            read_fn: self.read_fn,
369            write_fn: self.write_fn,
370        }
371    }
372}
373
374/// Represents common standard library smart pointer kinds
375#[non_exhaustive]
376#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
377pub enum KnownSmartPointer {
378    /// [`Box<T>`](std::boxed::Box), heap-allocated values with single ownership
379    Box,
380    /// [`Rc<T>`](std::rc::Rc), reference-counted values with multiple ownership
381    Rc,
382    /// [`Weak<T>`](std::rc::Weak), a weak reference to an `Rc`-managed value
383    RcWeak,
384    /// [`Arc<T>`](std::sync::Arc), thread-safe reference-counted values with multiple ownership
385    Arc,
386    /// [`Weak<T>`](std::sync::Weak), a weak reference to an `Arc`-managed value
387    ArcWeak,
388    /// [`Cow<'a, T>`](std::borrow::Cow), a clone-on-write smart pointer
389    Cow,
390    /// [`Pin<P>`](std::pin::Pin), a type that pins values behind a pointer
391    Pin,
392    /// [`Cell<T>`](std::cell::Cell), a mutable memory location with interior mutability
393    Cell,
394    /// [`RefCell<T>`](std::cell::RefCell), a mutable memory location with dynamic borrowing rules
395    RefCell,
396    /// [`OnceCell<T>`](std::cell::OnceCell), a cell that can be written to only once
397    OnceCell,
398    /// [`Mutex<T>`](std::sync::Mutex), a mutual exclusion primitive
399    Mutex,
400    /// [`RwLock<T>`](std::sync::RwLock), a reader-writer lock
401    RwLock,
402    /// [`NonNull<T>`](core::ptr::NonNull), a wrapper around a raw pointer that is not null
403    NonNull,
404}