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