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}