facet_core/types/def/
smartptr.rs

1use bitflags::bitflags;
2
3use crate::{GenericPtr, 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, Debug)]
10#[repr(C)]
11pub struct SmartPointerDef<'shape> {
12    /// vtable for interacting with the smart pointer
13    pub vtable: &'shape SmartPointerVTable<'shape>,
14
15    /// shape of the inner type of the smart pointer, if not opaque
16    pub pointee: Option<fn() -> &'shape Shape<'shape>>,
17
18    /// shape of the corresponding strong pointer, if this pointer is weak
19    pub weak: Option<fn() -> &'shape Shape<'shape>>,
20
21    /// shape of the corresponding weak pointer, if this pointer is strong
22    pub strong: Option<fn() -> &'shape Shape<'shape>>,
23
24    /// Flags representing various characteristics of the smart pointer
25    pub flags: SmartPointerFlags,
26
27    /// An optional field to identify the kind of smart pointer
28    pub known: Option<KnownSmartPointer>,
29}
30
31impl<'shape> SmartPointerDef<'shape> {
32    /// Creates a new `SmartPointerDefBuilder` with all fields set to `None`.
33    #[must_use]
34    pub const fn builder() -> SmartPointerDefBuilder<'shape> {
35        SmartPointerDefBuilder {
36            vtable: None,
37            pointee: None,
38            flags: None,
39            known: None,
40            weak: None,
41            strong: None,
42        }
43    }
44
45    /// Returns shape of the inner type of the smart pointer, if not opaque
46    pub fn pointee(&self) -> Option<&'shape Shape<'shape>> {
47        self.pointee.map(|v| v())
48    }
49
50    /// Returns shape of the corresponding strong pointer, if this pointer is weak
51    pub fn weak(&self) -> Option<&'shape Shape<'shape>> {
52        self.weak.map(|v| v())
53    }
54
55    /// Returns shape of the corresponding weak pointer, if this pointer is strong
56    pub fn strong(&self) -> Option<&'shape Shape<'shape>> {
57        self.strong.map(|v| v())
58    }
59}
60
61/// Builder for creating a `SmartPointerDef`.
62#[derive(Debug)]
63pub struct SmartPointerDefBuilder<'shape> {
64    vtable: Option<&'shape SmartPointerVTable<'shape>>,
65    pointee: Option<fn() -> &'shape Shape<'shape>>,
66    flags: Option<SmartPointerFlags>,
67    known: Option<KnownSmartPointer>,
68    weak: Option<fn() -> &'shape Shape<'shape>>,
69    strong: Option<fn() -> &'shape Shape<'shape>>,
70}
71
72impl<'shape> SmartPointerDefBuilder<'shape> {
73    /// Creates a new `SmartPointerDefBuilder` with all fields set to `None`.
74    #[must_use]
75    #[expect(clippy::new_without_default)]
76    pub const fn new() -> Self {
77        Self {
78            vtable: None,
79            pointee: None,
80            flags: None,
81            known: None,
82            weak: None,
83            strong: None,
84        }
85    }
86
87    /// Sets the vtable for the smart pointer.
88    #[must_use]
89    pub const fn vtable(mut self, vtable: &'shape SmartPointerVTable) -> Self {
90        self.vtable = Some(vtable);
91        self
92    }
93
94    /// Sets the shape of the inner type of the smart pointer.
95    #[must_use]
96    pub const fn pointee(mut self, pointee: fn() -> &'shape Shape<'shape>) -> Self {
97        self.pointee = Some(pointee);
98        self
99    }
100
101    /// Sets the flags for the smart pointer.
102    #[must_use]
103    pub const fn flags(mut self, flags: SmartPointerFlags) -> Self {
104        self.flags = Some(flags);
105        self
106    }
107
108    /// Sets the known smart pointer type.
109    #[must_use]
110    pub const fn known(mut self, known: KnownSmartPointer) -> Self {
111        self.known = Some(known);
112        self
113    }
114
115    /// Sets the shape of the corresponding weak pointer, if this pointer is strong.
116    #[must_use]
117    pub const fn weak(mut self, weak: fn() -> &'shape Shape<'shape>) -> Self {
118        self.weak = Some(weak);
119        self
120    }
121
122    /// Sets the shape of the corresponding strong pointer, if this pointer is weak
123    #[must_use]
124    pub const fn strong(mut self, strong: fn() -> &'shape Shape<'shape>) -> Self {
125        self.strong = Some(strong);
126        self
127    }
128
129    /// Builds a `SmartPointerDef` from the provided configuration.
130    ///
131    /// # Panics
132    ///
133    /// Panics if any required field (vtable, flags) is not set.
134    #[must_use]
135    pub const fn build(self) -> SmartPointerDef<'shape> {
136        SmartPointerDef {
137            vtable: self.vtable.unwrap(),
138            pointee: self.pointee,
139            weak: self.weak,
140            strong: self.strong,
141            flags: self.flags.unwrap(),
142            known: self.known,
143        }
144    }
145}
146
147bitflags! {
148    /// Flags to represent various characteristics of smart pointers
149    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
150    pub struct SmartPointerFlags: u8 {
151        /// An empty set of flags
152        const EMPTY = 0;
153
154        /// Whether the smart pointer is weak (like [`std::sync::Weak`])
155        const WEAK = 1 << 0;
156        /// Whether the smart pointer is atomic (like [`std::sync::Arc`])
157        const ATOMIC = 1 << 1;
158        /// Whether the pointer is a lock (like [`std::sync::Mutex`])
159        const LOCK = 1 << 2;
160    }
161}
162
163/// Tries to upgrade the weak pointer to a strong one.
164///
165/// If the upgrade succeeds, initializes the smart pointer into the given `strong`, and returns a
166/// copy of `strong`, which has been guaranteed to be initialized. If the upgrade fails, `None` is
167/// returned and `strong` is not initialized.
168///
169/// `weak` is not moved out of.
170///
171/// # Safety
172///
173/// `weak` must be a valid weak smart pointer (like [`std::sync::Weak`] or [`std::rc::Weak`]).
174///
175/// `strong` must be allocated, and of the right layout for the corresponding smart pointer.
176///
177/// `strong` must not have been initialized yet.
178pub type UpgradeIntoFn =
179    for<'ptr> unsafe fn(weak: PtrMut<'ptr>, strong: PtrUninit<'ptr>) -> Option<PtrMut<'ptr>>;
180
181/// Downgrades a strong pointer to a weak one.
182///
183/// Initializes the smart pointer into the given `weak`, and returns a copy of `weak`, which has
184/// been guaranteed to be initialized.
185///
186/// Only strong pointers can be downgraded (like [`std::sync::Arc`] or [`std::rc::Rc`]).
187///
188/// # Safety
189///
190/// `strong` must be a valid strong smart pointer (like [`std::sync::Arc`] or [`std::rc::Rc`]).
191///
192/// `weak` must be allocated, and of the right layout for the corresponding weak pointer.
193///
194/// `weak` must not have been initialized yet.
195pub type DowngradeIntoFn =
196    for<'ptr> unsafe fn(strong: PtrMut<'ptr>, weak: PtrUninit<'ptr>) -> PtrMut<'ptr>;
197
198/// Tries to obtain a reference to the inner value of the smart pointer.
199///
200/// This can only be used with strong pointers (like [`std::sync::Arc`] or [`std::rc::Rc`]).
201///
202/// # Safety
203///
204/// `this` must be a valid strong smart pointer (like [`std::sync::Arc`] or [`std::rc::Rc`]).
205pub type BorrowFn = for<'ptr> unsafe fn(this: PtrConst<'ptr>) -> GenericPtr<'ptr>;
206
207/// Creates a new smart pointer wrapping the given value.
208///
209/// Initializes the smart pointer into the given `this`, and returns a copy of `this`, which has
210/// been guaranteed to be initialized.
211///
212/// This can only be used with strong pointers (like [`std::sync::Arc`] or [`std::rc::Rc`]).
213///
214/// # Safety
215///
216/// `this` must be allocated, and of the right layout for the corresponding smart pointer.
217///
218/// `this` must not have been initialized yet.
219///
220/// `ptr` must point to a value of type `T`.
221///
222/// `ptr` is moved out of (with [`core::ptr::read`]) — it should be deallocated afterwards (e.g.
223/// with [`core::mem::forget`]) but NOT dropped).
224pub type NewIntoFn = for<'ptr> unsafe fn(this: PtrUninit<'ptr>, ptr: PtrMut<'ptr>) -> PtrMut<'ptr>;
225
226/// Type-erased result of locking a mutex-like smart pointer
227pub struct LockResult<'ptr> {
228    /// The data that was locked
229    data: PtrMut<'ptr>,
230    /// The guard that protects the data
231    guard: PtrConst<'ptr>,
232    /// The vtable for the guard
233    guard_vtable: &'static LockGuardVTable,
234}
235
236impl<'ptr> LockResult<'ptr> {
237    /// Returns a reference to the locked data
238    #[must_use]
239    pub fn data(&self) -> &PtrMut<'ptr> {
240        &self.data
241    }
242}
243
244impl Drop for LockResult<'_> {
245    fn drop(&mut self) {
246        unsafe {
247            (self.guard_vtable.drop_in_place)(self.guard);
248        }
249    }
250}
251
252/// Functions for manipulating a guard
253pub struct LockGuardVTable {
254    /// Drops the guard in place
255    pub drop_in_place: for<'ptr> unsafe fn(guard: PtrConst<'ptr>),
256}
257
258/// Acquires a lock on a mutex-like smart pointer
259pub type LockFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
260
261/// Acquires a read lock on a reader-writer lock-like smart pointer
262pub type ReadFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
263
264/// Acquires a write lock on a reader-writer lock-like smart pointer
265pub type WriteFn = for<'ptr> unsafe fn(opaque: PtrConst<'ptr>) -> Result<LockResult<'ptr>, ()>;
266
267/// Creates a new slice builder for a smart pointer: ie. for `Arc<[u8]>`, it builds a
268/// `Vec<u8>` internally, to which you can push, and then turn into an `Arc<[u8]>` at
269/// the last stage.
270///
271/// This works for any `U` in `Arc<[U]>` because those have separate concrete implementations, and
272/// thus, separate concrete vtables.
273pub type SliceBuilderNewFn = fn() -> PtrMut<'static>;
274
275/// Pushes a value into a slice builder.
276///
277/// # Safety
278///
279/// Item must point to a valid value of type `U` and must be initialized.
280/// Function is infallible as it uses the global allocator.
281pub type SliceBuilderPushFn = unsafe fn(builder: PtrMut, item: PtrMut);
282
283/// Converts a slice builder into a smart pointer. This takes ownership of the builder
284/// and frees the backing storage.
285///
286/// # Safety
287///
288/// The builder must be valid and must not be used after this function is called.
289/// Function is infallible as it uses the global allocator.
290pub type SliceBuilderConvertFn = unsafe fn(builder: PtrMut<'static>) -> PtrConst<'static>;
291
292/// Frees a slice builder without converting it into a smart pointer
293///
294/// # Safety
295///
296/// The builder must be valid and must not be used after this function is called.
297pub type SliceBuilderFreeFn = unsafe fn(builder: PtrMut<'static>);
298
299/// Functions for creating and manipulating slice builders.
300#[derive(Debug, Clone, Copy)]
301pub struct SliceBuilderVTable {
302    /// See [`SliceBuilderNewFn`]
303    pub new_fn: SliceBuilderNewFn,
304    /// See [`SliceBuilderPushFn`]
305    pub push_fn: SliceBuilderPushFn,
306    /// See [`SliceBuilderConvertFn`]
307    pub convert_fn: SliceBuilderConvertFn,
308    /// See [`SliceBuilderFreeFn`]
309    pub free_fn: SliceBuilderFreeFn,
310}
311
312impl SliceBuilderVTable {
313    /// Creates a new `SliceBuilderVTableBuilder` with all fields set to `None`.
314    #[must_use]
315    pub const fn builder() -> SliceBuilderVTableBuilder {
316        SliceBuilderVTableBuilder {
317            new_fn: None,
318            push_fn: None,
319            convert_fn: None,
320            free_fn: None,
321        }
322    }
323}
324
325/// Builder for creating a `SliceBuilderVTable`.
326#[derive(Debug)]
327pub struct SliceBuilderVTableBuilder {
328    new_fn: Option<SliceBuilderNewFn>,
329    push_fn: Option<SliceBuilderPushFn>,
330    convert_fn: Option<SliceBuilderConvertFn>,
331    free_fn: Option<SliceBuilderFreeFn>,
332}
333
334impl SliceBuilderVTableBuilder {
335    /// Creates a new `SliceBuilderVTableBuilder` with all fields set to `None`.
336    #[must_use]
337    #[expect(clippy::new_without_default)]
338    pub const fn new() -> Self {
339        Self {
340            new_fn: None,
341            push_fn: None,
342            convert_fn: None,
343            free_fn: None,
344        }
345    }
346
347    /// Sets the `new` function for the slice builder.
348    #[must_use]
349    pub const fn new_fn(mut self, new_fn: SliceBuilderNewFn) -> Self {
350        self.new_fn = Some(new_fn);
351        self
352    }
353
354    /// Sets the `push` function for the slice builder.
355    #[must_use]
356    pub const fn push_fn(mut self, push_fn: SliceBuilderPushFn) -> Self {
357        self.push_fn = Some(push_fn);
358        self
359    }
360
361    /// Sets the `convert` function for the slice builder.
362    #[must_use]
363    pub const fn convert_fn(mut self, convert_fn: SliceBuilderConvertFn) -> Self {
364        self.convert_fn = Some(convert_fn);
365        self
366    }
367
368    /// Sets the `free` function for the slice builder.
369    #[must_use]
370    pub const fn free_fn(mut self, free_fn: SliceBuilderFreeFn) -> Self {
371        self.free_fn = Some(free_fn);
372        self
373    }
374
375    /// Builds a `SliceBuilderVTable` from the provided configuration.
376    #[must_use]
377    pub const fn build(self) -> SliceBuilderVTable {
378        SliceBuilderVTable {
379            new_fn: self.new_fn.expect("new_fn must be set"),
380            push_fn: self.push_fn.expect("push_fn must be set"),
381            convert_fn: self.convert_fn.expect("convert_fn must be set"),
382            free_fn: self.free_fn.expect("free_fn must be set"),
383        }
384    }
385}
386
387/// Functions for interacting with a smart pointer
388#[derive(Debug, Clone, Copy)]
389pub struct SmartPointerVTable<'shape> {
390    /// See [`UpgradeIntoFn`]
391    pub upgrade_into_fn: Option<UpgradeIntoFn>,
392
393    /// See [`DowngradeIntoFn`]
394    pub downgrade_into_fn: Option<DowngradeIntoFn>,
395
396    /// See [`BorrowFn`]
397    pub borrow_fn: Option<BorrowFn>,
398
399    /// See [`NewIntoFn`]
400    pub new_into_fn: Option<NewIntoFn>,
401
402    /// See [`LockFn`]
403    pub lock_fn: Option<LockFn>,
404
405    /// See [`ReadFn`]
406    pub read_fn: Option<ReadFn>,
407
408    /// See [`WriteFn`]
409    pub write_fn: Option<WriteFn>,
410
411    /// See [`SliceBuilderVTable`]
412    pub slice_builder_vtable: Option<&'shape SliceBuilderVTable>,
413}
414
415impl<'shape> SmartPointerVTable<'shape> {
416    /// Creates a new `SmartPointerVTableBuilder` with all fields set to `None`.
417    #[must_use]
418    pub const fn builder() -> SmartPointerVTableBuilder<'shape> {
419        SmartPointerVTableBuilder {
420            upgrade_into_fn: None,
421            downgrade_into_fn: None,
422            borrow_fn: None,
423            new_into_fn: None,
424            lock_fn: None,
425            read_fn: None,
426            write_fn: None,
427            slice_builder_vtable: None,
428        }
429    }
430}
431
432/// Builder for creating a `SmartPointerVTable`.
433#[derive(Debug)]
434pub struct SmartPointerVTableBuilder<'shape> {
435    upgrade_into_fn: Option<UpgradeIntoFn>,
436    downgrade_into_fn: Option<DowngradeIntoFn>,
437    borrow_fn: Option<BorrowFn>,
438    new_into_fn: Option<NewIntoFn>,
439    lock_fn: Option<LockFn>,
440    read_fn: Option<ReadFn>,
441    write_fn: Option<WriteFn>,
442    slice_builder_vtable: Option<&'shape SliceBuilderVTable>,
443}
444
445impl<'shape> SmartPointerVTableBuilder<'shape> {
446    /// Creates a new `SmartPointerVTableBuilder` with all fields set to `None`.
447    #[must_use]
448    #[expect(clippy::new_without_default)]
449    pub const fn new() -> Self {
450        Self {
451            upgrade_into_fn: None,
452            downgrade_into_fn: None,
453            borrow_fn: None,
454            new_into_fn: None,
455            lock_fn: None,
456            read_fn: None,
457            write_fn: None,
458            slice_builder_vtable: None,
459        }
460    }
461
462    /// Sets the `try_upgrade` function.
463    #[must_use]
464    pub const fn upgrade_into_fn(mut self, upgrade_into_fn: UpgradeIntoFn) -> Self {
465        self.upgrade_into_fn = Some(upgrade_into_fn);
466        self
467    }
468
469    /// Sets the `downgrade` function.
470    #[must_use]
471    pub const fn downgrade_into_fn(mut self, downgrade_into_fn: DowngradeIntoFn) -> Self {
472        self.downgrade_into_fn = Some(downgrade_into_fn);
473        self
474    }
475
476    /// Sets the `borrow` function.
477    #[must_use]
478    pub const fn borrow_fn(mut self, borrow_fn: BorrowFn) -> Self {
479        self.borrow_fn = Some(borrow_fn);
480        self
481    }
482
483    /// Sets the `new_into` function.
484    #[must_use]
485    pub const fn new_into_fn(mut self, new_into_fn: NewIntoFn) -> Self {
486        self.new_into_fn = Some(new_into_fn);
487        self
488    }
489
490    /// Sets the `lock` function.
491    #[must_use]
492    pub const fn lock_fn(mut self, lock_fn: LockFn) -> Self {
493        self.lock_fn = Some(lock_fn);
494        self
495    }
496
497    /// Sets the `read` function.
498    #[must_use]
499    pub const fn read_fn(mut self, read_fn: ReadFn) -> Self {
500        self.read_fn = Some(read_fn);
501        self
502    }
503
504    /// Sets the `write` function.
505    #[must_use]
506    pub const fn write_fn(mut self, write_fn: WriteFn) -> Self {
507        self.write_fn = Some(write_fn);
508        self
509    }
510
511    /// Sets the `slice_builder_vtable` function.
512    #[must_use]
513    pub const fn slice_builder_vtable(
514        mut self,
515        slice_builder_vtable: &'shape SliceBuilderVTable,
516    ) -> Self {
517        self.slice_builder_vtable = Some(slice_builder_vtable);
518        self
519    }
520
521    /// Builds a `SmartPointerVTable` from the provided configuration.
522    #[must_use]
523    pub const fn build(self) -> SmartPointerVTable<'shape> {
524        SmartPointerVTable {
525            upgrade_into_fn: self.upgrade_into_fn,
526            downgrade_into_fn: self.downgrade_into_fn,
527            borrow_fn: self.borrow_fn,
528            new_into_fn: self.new_into_fn,
529            lock_fn: self.lock_fn,
530            read_fn: self.read_fn,
531            write_fn: self.write_fn,
532            slice_builder_vtable: self.slice_builder_vtable,
533        }
534    }
535}
536
537/// Represents common standard library smart pointer kinds
538#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
539pub enum KnownSmartPointer {
540    /// [`Box<T>`](std::boxed::Box), heap-allocated values with single ownership
541    Box,
542    /// [`Rc<T>`](std::rc::Rc), reference-counted values with multiple ownership
543    Rc,
544    /// [`Weak<T>`](std::rc::Weak), a weak reference to an `Rc`-managed value
545    RcWeak,
546    /// [`Arc<T>`](std::sync::Arc), thread-safe reference-counted values with multiple ownership
547    Arc,
548    /// [`Weak<T>`](std::sync::Weak), a weak reference to an `Arc`-managed value
549    ArcWeak,
550    /// [`Cow<'a, T>`](std::borrow::Cow), a clone-on-write smart pointer
551    Cow,
552    /// [`Pin<P>`](std::pin::Pin), a type that pins values behind a pointer
553    Pin,
554    /// [`Cell<T>`](std::cell::Cell), a mutable memory location with interior mutability
555    Cell,
556    /// [`RefCell<T>`](std::cell::RefCell), a mutable memory location with dynamic borrowing rules
557    RefCell,
558    /// [`OnceCell<T>`](std::cell::OnceCell), a cell that can be written to only once
559    OnceCell,
560    /// [`Mutex<T>`](std::sync::Mutex), a mutual exclusion primitive
561    Mutex,
562    /// [`RwLock<T>`](std::sync::RwLock), a reader-writer lock
563    RwLock,
564    /// [`NonNull<T>`](core::ptr::NonNull), a wrapper around a raw pointer that is not null
565    NonNull,
566}