1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use core::alloc::Layout;
7
8pub use facet_peek::*;
9
10use facet_trait::{Def, Facet, OpaqueUninit, Shape};
11
12mod value;
13pub use value::*;
14
15mod list;
16pub use list::*;
17
18mod map;
19pub use map::*;
20
21mod struct_;
22pub use struct_::*;
23
24mod enum_;
25pub use enum_::*;
26
27#[non_exhaustive]
29pub enum Poke<'mem> {
30 Scalar(PokeValue<'mem>),
32 List(PokeListUninit<'mem>),
34 Map(PokeMapUninit<'mem>),
36 Struct(PokeStruct<'mem>),
38 Enum(PokeEnumNoVariant<'mem>),
40}
41
42pub 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 unsafe {
52 std::alloc::dealloc(self.ptr, self.layout);
53 }
54 }
55}
56
57impl<'mem> Poke<'mem> {
58 pub fn alloc<S: Facet>() -> (Self, Guard) {
60 let data = S::SHAPE.allocate();
61 let layout = Layout::new::<S>();
62 let guard = Guard {
63 ptr: data.as_mut_ptr(),
64 layout,
65 shape: S::SHAPE,
66 };
67 let poke = unsafe { Self::unchecked_new(data, S::SHAPE) };
68 (poke, guard)
69 }
70
71 pub fn alloc_shape(shape: &'static Shape) -> (Self, Guard) {
73 let data = shape.allocate();
74 let layout = shape.layout;
75 let guard = Guard {
76 ptr: data.as_mut_ptr(),
77 layout,
78 shape,
79 };
80 let poke = unsafe { Self::unchecked_new(data, shape) };
81 (poke, guard)
82 }
83
84 pub unsafe fn unchecked_new(data: OpaqueUninit<'mem>, shape: &'static Shape) -> Self {
91 match shape.def {
92 Def::Struct(struct_def) => {
93 Poke::Struct(unsafe { PokeStruct::new(data, shape, struct_def) })
94 }
95 Def::Map(map_def) => {
96 let pmu = unsafe { PokeMapUninit::new(data, shape, map_def) };
97 Poke::Map(pmu)
98 }
99 Def::List(list_def) => {
100 let plu = unsafe { PokeListUninit::new(data, shape, list_def) };
101 Poke::List(plu)
102 }
103 Def::Scalar { .. } => Poke::Scalar(unsafe { PokeValue::new(data, shape) }),
104 Def::Enum(enum_def) => {
105 Poke::Enum(unsafe { PokeEnumNoVariant::new(data, shape, enum_def) })
106 }
107 _ => todo!("unsupported def: {:?}", shape.def),
108 }
109 }
110
111 pub fn into_struct(self) -> PokeStruct<'mem> {
113 match self {
114 Poke::Struct(s) => s,
115 _ => panic!("expected Struct variant"),
116 }
117 }
118
119 pub fn into_list(self) -> PokeListUninit<'mem> {
121 match self {
122 Poke::List(l) => l,
123 _ => panic!("expected List variant"),
124 }
125 }
126
127 pub fn into_map(self) -> PokeMapUninit<'mem> {
129 match self {
130 Poke::Map(m) => m,
131 _ => panic!("expected Map variant"),
132 }
133 }
134
135 pub fn into_scalar(self) -> PokeValue<'mem> {
137 match self {
138 Poke::Scalar(s) => s,
139 _ => panic!("expected Scalar variant"),
140 }
141 }
142
143 pub fn into_enum(self) -> PokeEnumNoVariant<'mem> {
145 match self {
146 Poke::Enum(e) => e,
147 _ => panic!("expected Enum variant"),
148 }
149 }
150
151 #[inline(always)]
153 pub fn into_value(self) -> PokeValue<'mem> {
154 match self {
155 Poke::Scalar(s) => s.into_value(),
156 Poke::List(l) => l.into_value(),
157 Poke::Map(m) => m.into_value(),
158 Poke::Struct(s) => s.into_value(),
159 Poke::Enum(e) => e.into_value(),
160 }
161 }
162
163 #[inline(always)]
165 pub fn shape(&self) -> &'static Shape {
166 match self {
167 Poke::Scalar(poke_value) => poke_value.shape(),
168 Poke::List(poke_list_uninit) => poke_list_uninit.shape(),
169 Poke::Map(poke_map_uninit) => poke_map_uninit.shape(),
170 Poke::Struct(poke_struct) => poke_struct.shape(),
171 Poke::Enum(poke_enum_no_variant) => poke_enum_no_variant.shape(),
172 }
173 }
174}
175
176#[derive(Clone, Copy, Default)]
178pub struct ISet(u64);
179
180impl ISet {
181 pub fn set(&mut self, index: usize) {
183 if index >= 64 {
184 panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
185 }
186 self.0 |= 1 << index;
187 }
188
189 pub fn unset(&mut self, index: usize) {
191 if index >= 64 {
192 panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
193 }
194 self.0 &= !(1 << index);
195 }
196
197 pub fn has(&self, index: usize) -> bool {
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)) != 0
203 }
204
205 pub fn all_set(&self, count: usize) -> bool {
207 if count > 64 {
208 panic!("ISet can only track up to 64 fields. Count {count} is out of bounds.");
209 }
210 let mask = (1 << count) - 1;
211 self.0 & mask == mask
212 }
213}