Skip to main content

facet_core/types/def/
pointer.rs

1use crate::{PtrConst, PtrMut, PtrUninit, Shape, bitflags};
2
3/// Describes a pointer — including a vtable to query and alter its state,
4/// and the inner shape (the pointee type in the pointer).
5#[derive(Clone, Copy, Debug)]
6#[repr(C)]
7pub struct PointerDef {
8    /// vtable for interacting with the pointer
9    pub vtable: &'static PointerVTable,
10
11    /// shape of the inner type of the pointer, if not opaque
12    pub pointee: Option<&'static Shape>,
13
14    /// shape of the corresponding strong pointer, if this pointer is weak
15    ///
16    /// the layer of indirection is to break the strong <-> weak reference cycle,
17    /// since consts may not have cycles in their definitions.
18    pub weak: Option<fn() -> &'static Shape>,
19
20    /// shape of the corresponding weak pointer, if this pointer is strong
21    pub strong: Option<&'static Shape>,
22
23    /// Flags representing various characteristics of the pointer
24    pub flags: PointerFlags,
25
26    /// An optional field to identify the kind of pointer
27    pub known: Option<KnownPointer>,
28}
29
30impl PointerDef {
31    /// Returns shape of the inner type of the pointer, if not opaque
32    pub const fn pointee(&self) -> Option<&'static Shape> {
33        self.pointee
34    }
35
36    /// Returns shape of the corresponding strong pointer, if this pointer is weak
37    pub fn weak(&self) -> Option<&'static Shape> {
38        self.weak.map(|f| f())
39    }
40
41    /// Returns shape of the corresponding weak pointer, if this pointer is strong
42    pub const fn strong(&self) -> Option<&'static Shape> {
43        self.strong
44    }
45
46    /// Whether a new pointer can be constructed from an owned value of its pointee type.
47    pub const fn constructible_from_pointee(&self) -> bool {
48        self.vtable.new_into_fn.is_some()
49            || matches!(
50                self.known,
51                Some(KnownPointer::Box | KnownPointer::Rc | KnownPointer::Arc)
52            )
53    }
54}
55
56bitflags! {
57    /// Flags to represent various characteristics of pointers
58    pub struct PointerFlags: u8 {
59        /// An empty set of flags
60        const EMPTY = 0;
61
62        /// Whether the pointer is weak (like `std::sync::Weak`)
63        const WEAK = 1 << 0;
64        /// Whether the pointer is atomic (like `std::sync::Arc`)
65        const ATOMIC = 1 << 1;
66        /// Whether the pointer is a lock (like `std::sync::Mutex`)
67        const LOCK = 1 << 2;
68    }
69}
70
71/// Tries to upgrade the weak pointer to a strong one.
72///
73/// If the upgrade succeeds, initializes the pointer into the given `strong`, and returns a
74/// copy of `strong`, which has been guaranteed to be initialized. If the upgrade fails, `None` is
75/// returned and `strong` is not initialized.
76///
77/// `weak` is not moved out of.
78///
79/// # Safety
80///
81/// `weak` must be a valid weak pointer (like [`alloc::sync::Weak`] or [`alloc::rc::Weak`]).
82///
83/// `strong` must be allocated, and of the right layout for the corresponding pointer.
84///
85/// `strong` must not have been initialized yet.
86pub type UpgradeIntoFn = unsafe fn(weak: PtrMut, strong: PtrUninit) -> Option<PtrMut>;
87
88/// Downgrades a strong pointer to a weak one.
89///
90/// Initializes the pointer into the given `weak`, and returns a copy of `weak`, which has
91/// been guaranteed to be initialized.
92///
93/// Only strong pointers can be downgraded (like [`alloc::sync::Arc`] or [`alloc::rc::Rc`]).
94///
95/// # Safety
96///
97/// `strong` must be a valid strong pointer (like [`alloc::sync::Arc`] or [`alloc::rc::Rc`]).
98///
99/// `weak` must be allocated, and of the right layout for the corresponding weak pointer.
100///
101/// `weak` must not have been initialized yet.
102pub type DowngradeIntoFn = unsafe fn(strong: PtrMut, weak: PtrUninit) -> PtrMut;
103
104/// Tries to obtain a reference to the inner value of the pointer.
105///
106/// This can only be used with strong pointers (like [`alloc::sync::Arc`] or [`alloc::rc::Rc`]).
107///
108/// # Safety
109///
110/// `this` must be a valid strong pointer (like [`alloc::sync::Arc`] or [`alloc::rc::Rc`]).
111pub type BorrowFn = unsafe fn(this: PtrConst) -> PtrConst;
112
113/// Creates a new pointer wrapping the given value.
114///
115/// Initializes the pointer into the given `this`, and returns a copy of `this`, which has
116/// been guaranteed to be initialized.
117///
118/// This can only be used with strong pointers (like [`alloc::sync::Arc`] or [`alloc::rc::Rc`]).
119///
120/// # Safety
121///
122/// `this` must be allocated, and of the right layout for the corresponding pointer.
123///
124/// `this` must not have been initialized yet.
125///
126/// `ptr` must point to a value of type `T`.
127///
128/// `ptr` is moved out of (with [`core::ptr::read`]) — it should be deallocated afterwards (e.g.
129/// with [`core::mem::forget`]) but NOT dropped).
130pub type NewIntoFn = unsafe fn(this: PtrUninit, ptr: PtrMut) -> PtrMut;
131
132/// Type-erased result of locking a mutex-like or reader-writer lock pointer.
133///
134/// The type parameter `P` determines the capability of the returned pointer:
135/// - `PtrConst` for read locks (shared access)
136/// - `PtrMut` for write/mutex locks (exclusive access)
137pub struct LockResult<P> {
138    /// The data that was locked
139    data: P,
140    /// The guard that protects the data
141    guard: PtrConst,
142    /// The vtable for the guard
143    guard_vtable: &'static LockGuardVTable,
144}
145
146/// Result of acquiring a read lock (shared access) - data is immutable
147pub type ReadLockResult = LockResult<PtrConst>;
148
149/// Result of acquiring a write/mutex lock (exclusive access) - data is mutable
150pub type WriteLockResult = LockResult<PtrMut>;
151
152impl<P> LockResult<P> {
153    /// Creates a new `LockResult` from its components.
154    ///
155    /// # Safety
156    ///
157    /// - `data` must point to valid data protected by the guard
158    /// - `guard` must point to a valid guard that, when dropped via `guard_vtable.drop_in_place`,
159    ///   will release the lock
160    /// - The guard must outlive any use of `data`
161    #[must_use]
162    pub const unsafe fn new(data: P, guard: PtrConst, guard_vtable: &'static LockGuardVTable) -> Self {
163        Self {
164            data,
165            guard,
166            guard_vtable,
167        }
168    }
169
170    /// Returns a reference to the locked data
171    #[must_use]
172    pub const fn data(&self) -> &P {
173        &self.data
174    }
175}
176
177impl WriteLockResult {
178    /// Returns a const pointer to the locked data (convenience for write locks)
179    #[must_use]
180    pub const fn data_const(&self) -> PtrConst {
181        self.data.as_const()
182    }
183}
184
185impl<P> Drop for LockResult<P> {
186    fn drop(&mut self) {
187        unsafe {
188            (self.guard_vtable.drop_in_place)(self.guard);
189        }
190    }
191}
192
193/// Functions for manipulating a guard
194pub struct LockGuardVTable {
195    /// Drops the guard in place
196    pub drop_in_place: unsafe fn(guard: PtrConst),
197}
198
199/// Acquires a lock on a mutex-like pointer (exclusive access)
200pub type LockFn = unsafe fn(opaque: PtrConst) -> Result<WriteLockResult, ()>;
201
202/// Acquires a read lock on a reader-writer lock-like pointer (shared access)
203pub type ReadFn = unsafe fn(opaque: PtrConst) -> Result<ReadLockResult, ()>;
204
205/// Acquires a write lock on a reader-writer lock-like pointer (exclusive access)
206pub type WriteFn = unsafe fn(opaque: PtrConst) -> Result<WriteLockResult, ()>;
207
208/// Creates a new slice builder for a pointer: ie. for `Arc<[u8]>`, it builds a
209/// `Vec<u8>` internally, to which you can push, and then turn into an `Arc<[u8]>` at
210/// the last stage.
211///
212/// This works for any `U` in `Arc<[U]>` because those have separate concrete implementations, and
213/// thus, separate concrete vtables.
214pub type SliceBuilderNewFn = fn() -> PtrMut;
215
216/// Pushes a value into a slice builder.
217///
218/// # Safety
219///
220/// Item must point to a valid value of type `U` and must be initialized.
221/// Function is infallible as it uses the global allocator.
222pub type SliceBuilderPushFn = unsafe fn(builder: PtrMut, item: PtrMut);
223
224/// Converts a slice builder into a pointer. This takes ownership of the builder
225/// and frees the backing storage.
226///
227/// # Safety
228///
229/// The builder must be valid and must not be used after this function is called.
230/// Function is infallible as it uses the global allocator.
231pub type SliceBuilderConvertFn = unsafe fn(builder: PtrMut) -> PtrConst;
232
233/// Frees a slice builder without converting it into a pointer
234///
235/// # Safety
236///
237/// The builder must be valid and must not be used after this function is called.
238pub type SliceBuilderFreeFn = unsafe fn(builder: PtrMut);
239
240/// Functions for creating and manipulating slice builders.
241#[derive(Debug, Clone, Copy)]
242pub struct SliceBuilderVTable {
243    /// See [`SliceBuilderNewFn`]
244    pub new_fn: SliceBuilderNewFn,
245    /// See [`SliceBuilderPushFn`]
246    pub push_fn: SliceBuilderPushFn,
247    /// See [`SliceBuilderConvertFn`]
248    pub convert_fn: SliceBuilderConvertFn,
249    /// See [`SliceBuilderFreeFn`]
250    pub free_fn: SliceBuilderFreeFn,
251}
252
253impl SliceBuilderVTable {
254    /// Const ctor for slice builder vtable; all hooks required.
255    #[must_use]
256    pub const fn new(
257        new_fn: SliceBuilderNewFn,
258        push_fn: SliceBuilderPushFn,
259        convert_fn: SliceBuilderConvertFn,
260        free_fn: SliceBuilderFreeFn,
261    ) -> Self {
262        Self {
263            new_fn,
264            push_fn,
265            convert_fn,
266            free_fn,
267        }
268    }
269}
270
271/// Functions for interacting with a pointer
272#[derive(Debug, Clone, Copy)]
273pub struct PointerVTable {
274    /// See [`UpgradeIntoFn`]
275    pub upgrade_into_fn: Option<UpgradeIntoFn>,
276
277    /// See [`DowngradeIntoFn`]
278    pub downgrade_into_fn: Option<DowngradeIntoFn>,
279
280    /// See [`BorrowFn`]
281    pub borrow_fn: Option<BorrowFn>,
282
283    /// See [`NewIntoFn`]
284    pub new_into_fn: Option<NewIntoFn>,
285
286    /// See [`LockFn`]
287    pub lock_fn: Option<LockFn>,
288
289    /// See [`ReadFn`]
290    pub read_fn: Option<ReadFn>,
291
292    /// See [`WriteFn`]
293    pub write_fn: Option<WriteFn>,
294
295    /// See [`SliceBuilderVTable`]
296    pub slice_builder_vtable: Option<&'static SliceBuilderVTable>,
297}
298
299impl Default for PointerVTable {
300    fn default() -> Self {
301        Self::new()
302    }
303}
304
305impl PointerVTable {
306    /// Const ctor with all entries set to `None`.
307    #[must_use]
308    pub const fn new() -> Self {
309        Self {
310            upgrade_into_fn: None,
311            downgrade_into_fn: None,
312            borrow_fn: None,
313            new_into_fn: None,
314            lock_fn: None,
315            read_fn: None,
316            write_fn: None,
317            slice_builder_vtable: None,
318        }
319    }
320}
321
322/// Represents common standard library pointer kinds
323#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
324pub enum KnownPointer {
325    /// [`Box<T>`](alloc::boxed::Box), heap-allocated values with single ownership
326    Box,
327    /// [`Rc<T>`](alloc::rc::Rc), reference-counted values with multiple ownership
328    Rc,
329    /// [`Weak<T>`](alloc::rc::Weak), a weak reference to an `Rc`-managed value
330    RcWeak,
331    /// [`Arc<T>`](alloc::sync::Arc), thread-safe reference-counted values with multiple ownership
332    Arc,
333    /// [`Weak<T>`](alloc::sync::Weak), a weak reference to an `Arc`-managed value
334    ArcWeak,
335    /// [`Cow<'a, T>`](alloc::borrow::Cow), a clone-on-write smart pointer
336    Cow,
337    /// [`Pin<P>`](core::pin::Pin), a type that pins values behind a pointer
338    Pin,
339    /// [`Cell<T>`](core::cell::Cell), a mutable memory location with interior mutability
340    Cell,
341    /// [`RefCell<T>`](core::cell::RefCell), a mutable memory location with dynamic borrowing rules
342    RefCell,
343    /// [`OnceCell<T>`](core::cell::OnceCell), a cell that can be written to only once
344    OnceCell,
345    /// `Mutex<T>`, a mutual exclusion primitive (requires std)
346    Mutex,
347    /// `RwLock<T>`, a reader-writer lock (requires std)
348    RwLock,
349    /// `OnceLock<T>`, a cell that can be written to only once (requires std)
350    OnceLock,
351    /// `LazyLock<T, F>`, a lazy-initialized value (requires std)
352    LazyLock,
353    /// [`NonNull<T>`](core::ptr::NonNull), a wrapper around a raw pointer that is not null
354    NonNull,
355    /// `&T`
356    SharedReference,
357    /// `&mut T`
358    ExclusiveReference,
359}