facet_poke/
lib.rs

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