facet_reflect/poke/
smart_pointer.rs

1use facet_core::{
2    Facet, LockResult, Opaque, OpaqueConst, OpaqueUninit, Shape, SmartPointerDef,
3    SmartPointerFlags, SmartPointerVTable,
4};
5
6use crate::PeekValue;
7
8/// Allows initializing an uninitialized option
9pub struct PokeSmartPointerUninit<'mem> {
10    data: OpaqueUninit<'mem>,
11    shape: &'static Shape,
12    def: SmartPointerDef,
13}
14
15impl<'mem> PokeSmartPointerUninit<'mem> {
16    /// Creates a new uninitialized smart pointer poke
17    ///
18    /// # Safety
19    ///
20    /// `data` must be properly aligned and sized for this shape.
21    pub(crate) unsafe fn new(
22        data: OpaqueUninit<'mem>,
23        shape: &'static Shape,
24        def: SmartPointerDef,
25    ) -> Self {
26        Self { data, shape, def }
27    }
28
29    /// Returns the shape for this smart pointer.
30    pub fn shape(&self) -> &'static Shape {
31        self.shape
32    }
33
34    /// Returns the smart pointer definition.
35    pub fn def(&self) -> &SmartPointerDef {
36        &self.def
37    }
38
39    /// Returns the smart pointer vtable
40    pub fn vtable(&self) -> &'static SmartPointerVTable {
41        self.def.vtable
42    }
43
44    /// Get a reference to the underlying PokeValue
45    #[inline(always)]
46    pub fn into_value(self) -> crate::PokeValueUninit<'mem> {
47        unsafe { crate::PokeValueUninit::new(self.data, self.shape) }
48    }
49
50    /// Creates a new smart pointer around a given T
51    ///
52    /// Returns `None` if the smart pointer cannot be created directly
53    /// (like for weak pointers).
54    pub fn from_t<T>(self, value: T) -> Option<PokeSmartPointer<'mem>> {
55        let into_fn = self.def.vtable.new_into_fn?;
56
57        let value_opaque = OpaqueConst::new(&raw const value);
58        let opaque = unsafe { into_fn(self.data, value_opaque) };
59        core::mem::forget(value);
60        Some(PokeSmartPointer {
61            data: opaque,
62            shape: self.shape,
63            def: self.def,
64        })
65    }
66
67    /// Creates a new smart pointer from an existing [`PeekValue`].
68    ///
69    /// Note: The `PeekValue` is moved out of (consumed) during this operation.
70    /// It must be deallocated by the caller on success.
71    ///
72    /// Returns `None` if the smart pointer cannot be created directly
73    /// (like for weak pointers).
74    pub fn from_peek_value(self, value: PeekValue<'mem>) -> Option<PokeSmartPointer<'mem>> {
75        // Assert that the value's shape matches the expected inner type
76        assert_eq!(
77            value.shape(),
78            self.def.t,
79            "Inner value shape does not match expected smart pointer inner type"
80        );
81
82        let into_fn = self.def.vtable.new_into_fn?;
83
84        let opaque = unsafe { into_fn(self.data, value.data()) };
85        Some(PokeSmartPointer {
86            data: opaque,
87            shape: self.shape,
88            def: self.def,
89        })
90    }
91}
92
93pub struct PokeSmartPointer<'mem> {
94    data: Opaque<'mem>,
95    shape: &'static Shape,
96    def: SmartPointerDef,
97}
98
99impl<'mem> PokeSmartPointer<'mem> {
100    /// Creates a new smart pointer poke
101    ///
102    /// # Safety
103    ///
104    /// `data` must be properly aligned and sized for this shape.
105    pub(crate) unsafe fn new(
106        data: Opaque<'mem>,
107        shape: &'static Shape,
108        def: SmartPointerDef,
109    ) -> Self {
110        Self { data, shape, def }
111    }
112
113    /// Returns the shape for this smart pointer.
114    pub fn shape(&self) -> &'static Shape {
115        self.shape
116    }
117
118    /// Returns the smart pointer definition.
119    pub fn def(&self) -> &SmartPointerDef {
120        &self.def
121    }
122
123    /// Returns the smart pointer vtable
124    pub fn vtable(&self) -> &'static SmartPointerVTable {
125        self.def.vtable
126    }
127
128    /// Returns whether this smart pointer is weak (like [`std::sync::Weak`]).
129    pub fn is_weak(&self) -> bool {
130        self.def.flags.contains(SmartPointerFlags::WEAK)
131    }
132
133    /// Returns whether this smart pointer is atomic (like [`std::sync::Arc`]).
134    pub fn is_atomic(&self) -> bool {
135        self.def.flags.contains(SmartPointerFlags::ATOMIC)
136    }
137
138    /// Returns whether this pointer is a lock (like [`std::sync::Mutex`]).
139    pub fn is_lock(&self) -> bool {
140        self.def.flags.contains(SmartPointerFlags::LOCK)
141    }
142
143    /// Gets the known smart pointer type, if available.
144    pub fn known_type(&self) -> Option<facet_core::KnownSmartPointer> {
145        self.def.known
146    }
147
148    /// Returns the shape of the inner type of the smart pointer.
149    pub fn inner_type(&self) -> &'static Shape {
150        self.def.t
151    }
152
153    /// Attempts to borrow the inner value if the smart pointer supports it.
154    pub fn try_borrow(&self) -> Option<PeekValue<'_>> {
155        let borrow_fn = self.def.vtable.borrow_fn?;
156        let opaque = unsafe { borrow_fn(self.data.as_const()) };
157        Some(unsafe { PeekValue::unchecked_new(opaque, self.def.t) })
158    }
159
160    /// Attempts to upgrade this pointer if it's a weak reference.
161    pub fn try_upgrade(&self) -> Option<Self> {
162        let upgrade_fn = self.def.vtable.try_upgrade_fn?;
163        let opaque = unsafe { upgrade_fn(self.data)? };
164        Some(Self {
165            data: opaque,
166            shape: self.shape,
167            def: self.def,
168        })
169    }
170
171    /// Attempts to lock this pointer if it's a mutex-like smart pointer.
172    pub fn try_lock(&self) -> Option<Result<PokeSmartPointerWriteGuard<'_>, ()>> {
173        let lock_fn = self.def.vtable.lock_fn?;
174        Some(unsafe {
175            lock_fn(self.data.as_const())
176                .map(|result| PokeSmartPointerWriteGuard::from_lock_result(result, self.def.t))
177        })
178    }
179
180    /// Attempts to acquire a read lock on this pointer if it's a reader-writer lock.
181    pub fn try_read(&self) -> Option<Result<PokeSmartPointerReadGuard<'_>, ()>> {
182        let read_fn = self.def.vtable.read_fn?;
183        Some(unsafe {
184            read_fn(self.data.as_const())
185                .map(|result| PokeSmartPointerReadGuard::from_lock_result(result, self.def.t))
186        })
187    }
188
189    /// Attempts to acquire a write lock on this pointer if it's a reader-writer lock.
190    pub fn try_write(&self) -> Option<Result<PokeSmartPointerWriteGuard<'_>, ()>> {
191        let write_fn = self.def.vtable.write_fn?;
192        Some(unsafe {
193            write_fn(self.data.as_const())
194                .map(|result| PokeSmartPointerWriteGuard::from_lock_result(result, self.def.t))
195        })
196    }
197
198    /// Get a reference to the underlying PokeValue
199    #[inline(always)]
200    pub fn into_value(self) -> crate::PokeValue<'mem> {
201        unsafe { crate::PokeValue::new(self.data, self.shape) }
202    }
203
204    /// Moves `U` out of this `PokeSmartPointer`.
205    ///
206    /// Note that `U` should be something like `Arc<T>`, `Rc<T>`, etc.
207    pub fn build_in_place<U: Facet>(self) -> U {
208        // Ensure the shape matches the expected type
209        self.shape.assert_type::<U>();
210        unsafe { self.data.read::<U>() }
211    }
212}
213
214pub struct PokeSmartPointerWriteGuard<'mem> {
215    #[allow(dead_code)]
216    lr: LockResult<'mem>,
217    shape: &'static Shape,
218}
219
220impl<'mem> PokeSmartPointerWriteGuard<'mem> {
221    /// Creates a new write guard from a lock result
222    pub(crate) unsafe fn from_lock_result(lr: LockResult<'mem>, shape: &'static Shape) -> Self {
223        Self { lr, shape }
224    }
225
226    /// Returns the shape for this guard
227    pub fn shape(&self) -> &'static Shape {
228        self.shape
229    }
230}
231
232pub struct PokeSmartPointerReadGuard<'mem> {
233    #[allow(dead_code)]
234    lr: LockResult<'mem>,
235    shape: &'static Shape,
236}
237
238impl<'mem> PokeSmartPointerReadGuard<'mem> {
239    /// Creates a new read guard from a lock result
240    pub(crate) unsafe fn from_lock_result(lr: LockResult<'mem>, shape: &'static Shape) -> Self {
241        Self { lr, shape }
242    }
243
244    /// Returns the shape for this guard
245    pub fn shape(&self) -> &'static Shape {
246        self.shape
247    }
248}