facet_reflect/poke/
mod.rs

1extern crate alloc;
2
3use core::alloc::Layout;
4
5use facet_core::{Def, Facet, Opaque, OpaqueUninit, Shape};
6
7mod value;
8pub use value::*;
9
10mod list;
11pub use list::*;
12
13mod map;
14pub use map::*;
15
16mod struct_;
17pub use struct_::*;
18
19mod enum_;
20pub use enum_::*;
21
22mod option;
23pub use option::*;
24
25mod smart_pointer;
26pub use smart_pointer::*;
27
28/// Allows initializing values of different kinds.
29#[non_exhaustive]
30pub enum PokeUninit<'mem> {
31    /// A scalar value. See [`PokeValue`].
32    Scalar(PokeValueUninit<'mem>),
33    /// A list (array/vec/etc). See [`PokeList`].
34    List(PokeListUninit<'mem>),
35    /// A map (HashMap/BTreeMap/etc). See [`PokeMap`].
36    Map(PokeMapUninit<'mem>),
37    /// A struct, tuple struct, or tuple. See [`PokeStruct`].
38    Struct(PokeStruct<'mem>),
39    /// An enum variant. See [`PokeEnum`].
40    Enum(PokeEnumNoVariant<'mem>),
41    /// An option value. See [`PokeOption`].
42    Option(PokeOptionUninit<'mem>),
43    /// A smart pointer. See [`PokeSmartPointer`].
44    SmartPointer(PokeSmartPointerUninit<'mem>),
45}
46
47/// Ensures a value is dropped when the guard is dropped.
48pub struct Guard {
49    ptr: *mut u8,
50    layout: Layout,
51    shape: &'static Shape,
52}
53
54impl Drop for Guard {
55    fn drop(&mut self) {
56        if self.layout.size() == 0 {
57            return;
58        }
59        // SAFETY: `ptr` has been allocated via the global allocator with the given layout
60        unsafe { alloc::alloc::dealloc(self.ptr, self.layout) };
61    }
62}
63
64impl<'mem> PokeUninit<'mem> {
65    /// Allocates a new poke of a type that implements facet
66    pub fn alloc<S: Facet>() -> (Self, Guard) {
67        let data = S::SHAPE.allocate();
68        let layout = Layout::new::<S>();
69        let guard = Guard {
70            ptr: data.as_mut_bytes(),
71            layout,
72            shape: S::SHAPE,
73        };
74        let poke = unsafe { Self::unchecked_new(data, S::SHAPE) };
75        (poke, guard)
76    }
77
78    /// Allocates a new poke from a given shape
79    pub fn alloc_shape(shape: &'static Shape) -> (Self, Guard) {
80        let data = shape.allocate();
81        let layout = shape.layout;
82        let guard = Guard {
83            ptr: data.as_mut_bytes(),
84            layout,
85            shape,
86        };
87        let poke = unsafe { Self::unchecked_new(data, shape) };
88        (poke, guard)
89    }
90
91    /// Creates a new peek, for easy manipulation of some opaque data.
92    ///
93    /// # Safety
94    ///
95    /// `data` must be initialized and well-aligned, and point to a value
96    /// of the type described by `shape`.
97    pub unsafe fn unchecked_new(data: OpaqueUninit<'mem>, shape: &'static Shape) -> Self {
98        match shape.def {
99            Def::Struct(struct_def) => {
100                PokeUninit::Struct(unsafe { PokeStruct::new(data, shape, struct_def) })
101            }
102            Def::Map(map_def) => {
103                let pmu = unsafe { PokeMapUninit::new(data, shape, map_def) };
104                PokeUninit::Map(pmu)
105            }
106            Def::List(list_def) => {
107                let plu = unsafe { PokeListUninit::new(data, shape, list_def) };
108                PokeUninit::List(plu)
109            }
110            Def::Scalar { .. } => PokeUninit::Scalar(unsafe { PokeValueUninit::new(data, shape) }),
111            Def::Enum(enum_def) => {
112                PokeUninit::Enum(unsafe { PokeEnumNoVariant::new(data, shape, enum_def) })
113            }
114            Def::Option(option_def) => {
115                let pou = unsafe { PokeOptionUninit::new(data, shape, option_def) };
116                PokeUninit::Option(pou)
117            }
118            Def::SmartPointer(smart_pointer_def) => {
119                let psu = unsafe { PokeSmartPointerUninit::new(data, shape, smart_pointer_def) };
120                PokeUninit::SmartPointer(psu)
121            }
122            _ => todo!("unsupported def: {:?}", shape.def),
123        }
124    }
125
126    /// Converts this Poke into a PokeStruct, panicking if it's not a Struct variant
127    pub fn into_struct(self) -> PokeStruct<'mem> {
128        match self {
129            PokeUninit::Struct(s) => s,
130            _ => panic!("expected Struct variant"),
131        }
132    }
133
134    /// Converts this Poke into a PokeList, panicking if it's not a List variant
135    pub fn into_list(self) -> PokeListUninit<'mem> {
136        match self {
137            PokeUninit::List(l) => l,
138            _ => panic!("expected List variant"),
139        }
140    }
141
142    /// Converts this Poke into a PokeMap, panicking if it's not a Map variant
143    pub fn into_map(self) -> PokeMapUninit<'mem> {
144        match self {
145            PokeUninit::Map(m) => m,
146            _ => panic!("expected Map variant"),
147        }
148    }
149
150    /// Converts this Poke into a PokeSmartPointer, panicking if it's not a SmartPointer variant
151    pub fn into_smart_pointer(self) -> PokeSmartPointerUninit<'mem> {
152        match self {
153            PokeUninit::SmartPointer(s) => s,
154            _ => panic!("expected SmartPointer variant"),
155        }
156    }
157
158    /// Converts this Poke into a PokeValue, panicking if it's not a Scalar variant
159    pub fn into_scalar(self) -> PokeValueUninit<'mem> {
160        match self {
161            PokeUninit::Scalar(s) => s,
162            _ => panic!("expected Scalar variant"),
163        }
164    }
165
166    /// Converts this Poke into a PokeEnum, panicking if it's not an Enum variant
167    pub fn into_enum(self) -> PokeEnumNoVariant<'mem> {
168        match self {
169            PokeUninit::Enum(e) => e,
170            _ => panic!("expected Enum variant"),
171        }
172    }
173
174    /// Converts this Poke into a PokeOption, panicking if it's not an Option variant
175    pub fn into_option(self) -> PokeOptionUninit<'mem> {
176        match self {
177            PokeUninit::Option(o) => o,
178            _ => panic!("expected Option variant"),
179        }
180    }
181
182    /// Converts into a value, so we can manipulate it
183    #[inline(always)]
184    pub fn into_value(self) -> PokeValueUninit<'mem> {
185        match self {
186            PokeUninit::Scalar(s) => s.into_value(),
187            PokeUninit::List(l) => l.into_value(),
188            PokeUninit::Map(m) => m.into_value(),
189            PokeUninit::Struct(s) => s.into_value(),
190            PokeUninit::Enum(e) => e.into_value(),
191            PokeUninit::Option(o) => o.into_value(),
192            PokeUninit::SmartPointer(s) => s.into_value(),
193        }
194    }
195
196    /// Get the shape of this Poke.
197    #[inline(always)]
198    pub fn shape(&self) -> &'static Shape {
199        match self {
200            PokeUninit::Scalar(poke_value) => poke_value.shape(),
201            PokeUninit::List(poke_list_uninit) => poke_list_uninit.shape(),
202            PokeUninit::Map(poke_map_uninit) => poke_map_uninit.shape(),
203            PokeUninit::Struct(poke_struct) => poke_struct.shape(),
204            PokeUninit::Enum(poke_enum_no_variant) => poke_enum_no_variant.shape(),
205            PokeUninit::Option(poke_option_uninit) => poke_option_uninit.shape(),
206            PokeUninit::SmartPointer(poke_smart_pointer_uninit) => {
207                poke_smart_pointer_uninit.shape()
208            }
209        }
210    }
211}
212
213/// Keeps track of which fields were initialized, up to 64 fields
214#[derive(Clone, Copy, Default)]
215pub struct ISet(u64);
216
217impl ISet {
218    /// Sets the bit at the given index.
219    pub fn set(&mut self, index: usize) {
220        if index >= 64 {
221            panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
222        }
223        self.0 |= 1 << index;
224    }
225
226    /// Unsets the bit at the given index.
227    pub fn unset(&mut self, index: usize) {
228        if index >= 64 {
229            panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
230        }
231        self.0 &= !(1 << index);
232    }
233
234    /// Checks if the bit at the given index is set.
235    pub fn has(&self, index: usize) -> bool {
236        if index >= 64 {
237            panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
238        }
239        (self.0 & (1 << index)) != 0
240    }
241
242    /// Checks if all bits up to the given count are set.
243    pub fn all_set(&self, count: usize) -> bool {
244        if count > 64 {
245            panic!("ISet can only track up to 64 fields. Count {count} is out of bounds.");
246        }
247        let mask = (1 << count) - 1;
248        self.0 & mask == mask
249    }
250}
251
252/// Allows manipulating already-initialized values of different kinds.
253#[non_exhaustive]
254pub enum Poke<'mem> {
255    /// A scalar value. See [`PokeValue`].
256    Scalar(PokeValue<'mem>),
257    /// A list (array/vec/etc). See [`PokeList`].
258    List(PokeList<'mem>),
259    /// A map (HashMap/BTreeMap/etc). See [`PokeMap`].
260    Map(PokeMap<'mem>),
261    /// A struct, tuple struct, or tuple. See [`PokeStruct`].
262    Struct(PokeStruct<'mem>),
263    /// An enum variant. See [`PokeEnum`].
264    Enum(PokeEnum<'mem>),
265    /// An option value. See [`PokeOption`].
266    Option(PokeOption<'mem>),
267    /// A smart pointer. See [`PokeSmartPointer`].
268    SmartPointer(PokeSmartPointer<'mem>),
269}
270
271impl<'mem> Poke<'mem> {
272    /// Creates a new peek, for easy manipulation of some opaque data.
273    ///
274    /// # Safety
275    ///
276    /// `data` must be initialized and well-aligned, and point to a value
277    /// of the type described by `shape`.
278    pub unsafe fn unchecked_new(data: Opaque<'mem>, shape: &'static Shape) -> Self {
279        match shape.def {
280            Def::Struct(struct_def) => Poke::Struct(unsafe {
281                let mut ps =
282                    PokeStruct::new(OpaqueUninit::new(data.as_mut_byte_ptr()), shape, struct_def);
283                for (i, _f) in ps.def().fields.iter().enumerate() {
284                    ps.mark_initialized(i);
285                }
286                ps
287            }),
288            Def::Map(map_def) => {
289                let pm = unsafe { PokeMap::new(data, shape, map_def) };
290                Poke::Map(pm)
291            }
292            Def::List(list_def) => {
293                let pl = unsafe { PokeList::new(data, shape, list_def) };
294                Poke::List(pl)
295            }
296            Def::Scalar { .. } => Poke::Scalar(unsafe { PokeValue::new(data, shape) }),
297            Def::Enum(_enum_def) => {
298                todo!("we need to get the active variant somehow")
299            }
300            Def::Option(option_def) => {
301                let po = unsafe { PokeOption::new(data, shape, option_def) };
302                Poke::Option(po)
303            }
304            Def::SmartPointer(smart_pointer_def) => {
305                let ps = unsafe { PokeSmartPointer::new(data, shape, smart_pointer_def) };
306                Poke::SmartPointer(ps)
307            }
308            _ => todo!("unsupported def: {:?}", shape.def),
309        }
310    }
311
312    /// Borrows the value for a different kind of inspection.
313    #[inline(always)]
314    pub fn borrow<T: Facet>(data: &'mem mut T) -> Poke<'mem> {
315        let shape = T::SHAPE;
316        let data = Opaque::new(data);
317        unsafe { Poke::unchecked_new(data, shape) }
318    }
319
320    /// Converts this Poke into a PokeSmartPointer, panicking if it's not a SmartPointer variant
321    pub fn into_smart_pointer(self) -> PokeSmartPointer<'mem> {
322        match self {
323            Poke::SmartPointer(s) => s,
324            _ => panic!("expected SmartPointer variant"),
325        }
326    }
327
328    /// Converts this Poke into a PokeValue, panicking if it's not a Scalar variant
329    pub fn into_scalar(self) -> PokeValue<'mem> {
330        match self {
331            Poke::Scalar(s) => s,
332            _ => panic!("expected Scalar variant"),
333        }
334    }
335
336    /// Converts this Poke into a PokeList, panicking if it's not a List variant
337    pub fn into_list(self) -> PokeList<'mem> {
338        match self {
339            Poke::List(l) => l,
340            _ => panic!("expected List variant"),
341        }
342    }
343
344    /// Converts this Poke into a PokeMap, panicking if it's not a Map variant
345    pub fn into_map(self) -> PokeMap<'mem> {
346        match self {
347            Poke::Map(m) => m,
348            _ => panic!("expected Map variant"),
349        }
350    }
351
352    /// Converts this Poke into a PokeStruct, panicking if it's not a Struct variant
353    pub fn into_struct(self) -> PokeStruct<'mem> {
354        match self {
355            Poke::Struct(s) => s,
356            _ => panic!("expected Struct variant"),
357        }
358    }
359
360    /// Converts this Poke into a PokeEnum, panicking if it's not an Enum variant
361    pub fn into_enum(self) -> PokeEnum<'mem> {
362        match self {
363            Poke::Enum(e) => e,
364            _ => panic!("expected Enum variant"),
365        }
366    }
367
368    /// Converts this Poke into a PokeOption, panicking if it's not an Option variant
369    pub fn into_option(self) -> PokeOption<'mem> {
370        match self {
371            Poke::Option(o) => o,
372            _ => panic!("expected Option variant"),
373        }
374    }
375
376    /// Get the shape of this Poke.
377    #[inline(always)]
378    pub fn shape(&self) -> &'static Shape {
379        match self {
380            Poke::Scalar(poke_value) => poke_value.shape(),
381            Poke::List(poke_list) => poke_list.shape(),
382            Poke::Map(poke_map) => poke_map.shape(),
383            Poke::Struct(poke_struct) => poke_struct.shape(),
384            Poke::Enum(poke_enum) => poke_enum.shape(),
385            Poke::Option(poke_option) => poke_option.shape(),
386            Poke::SmartPointer(poke_smart_pointer) => poke_smart_pointer.shape(),
387        }
388    }
389}