facet_poke/
lib.rs

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