1use facet_core::{EnumDef, EnumRepr, Shape, Variant, VariantKind};
2
3#[derive(Clone, Copy)]
5pub struct PeekEnum<'mem> {
6 value: crate::PeekValue<'mem>,
7 def: EnumDef,
8}
9
10pub fn peek_enum(shape: &'static Shape) -> Option<EnumDef> {
12 match shape.def {
13 facet_core::Def::Enum(enum_def) => Some(enum_def),
14 _ => None,
15 }
16}
17
18pub fn peek_enum_repr(shape: &'static Shape) -> Option<EnumRepr> {
20 peek_enum(shape).map(|enum_def| enum_def.repr)
21}
22
23pub fn peek_enum_variants(shape: &'static Shape) -> Option<&'static [Variant]> {
25 peek_enum(shape).map(|enum_def| enum_def.variants)
26}
27
28impl<'mem> core::ops::Deref for PeekEnum<'mem> {
29 type Target = crate::PeekValue<'mem>;
30
31 #[inline(always)]
32 fn deref(&self) -> &Self::Target {
33 &self.value
34 }
35}
36
37impl<'mem> PeekEnum<'mem> {
38 pub(crate) fn new(value: crate::PeekValue<'mem>, def: EnumDef) -> Self {
40 Self { value, def }
41 }
42
43 #[inline(always)]
45 pub fn def(self) -> EnumDef {
46 self.def
47 }
48
49 #[inline(always)]
51 pub fn repr(self) -> EnumRepr {
52 self.def.repr
53 }
54
55 #[inline(always)]
57 pub fn variants(self) -> &'static [Variant] {
58 self.def.variants
59 }
60
61 #[inline(always)]
63 pub fn variant_count(self) -> usize {
64 self.def.variants.len()
65 }
66
67 #[inline(always)]
69 pub fn variant_name(self, index: usize) -> Option<&'static str> {
70 self.def.variants.get(index).map(|variant| variant.name)
71 }
72
73 #[inline]
75 pub fn discriminant(self) -> i64 {
76 unsafe {
78 let data = self.value.data();
79 match self.def.repr {
80 EnumRepr::U8 => data.read::<u8>() as i64,
81 EnumRepr::U16 => data.read::<u16>() as i64,
82 EnumRepr::U32 => data.read::<u32>() as i64,
83 EnumRepr::U64 => data.read::<u64>() as i64,
84 EnumRepr::USize => data.read::<usize>() as i64,
85 EnumRepr::I8 => data.read::<i8>() as i64,
86 EnumRepr::I16 => data.read::<i16>() as i64,
87 EnumRepr::I32 => data.read::<i32>() as i64,
88 EnumRepr::I64 => data.read::<i64>(),
89 EnumRepr::ISize => data.read::<isize>() as i64,
90 _ => {
91 data.read::<u32>() as i64
93 }
94 }
95 }
96 }
97
98 #[inline]
100 pub fn variant_index(self) -> usize {
101 let discriminant = self.discriminant();
102
103 for (index, variant) in self.def.variants.iter().enumerate() {
105 let variant_discriminant = match variant.discriminant {
106 Some(value) => value,
107 None => index as i64,
108 };
109
110 if variant_discriminant == discriminant {
111 return index;
112 }
113 }
114
115 panic!("Invalid discriminant value for enum")
117 }
118
119 #[inline]
121 pub fn active_variant(self) -> &'static Variant {
122 let index = self.variant_index();
123 &self.def.variants[index]
124 }
125
126 #[inline]
128 pub fn variant_name_active(self) -> &'static str {
129 self.active_variant().name
130 }
131
132 #[inline]
134 pub fn variant_kind_active(self) -> &'static VariantKind {
135 &self.active_variant().kind
136 }
137
138 pub fn field(self, field_name: &str) -> Option<crate::Peek<'mem>> {
140 let variant = self.active_variant();
141
142 match &variant.kind {
143 VariantKind::Unit => None, VariantKind::Tuple { fields } => {
145 let field = fields.iter().find(|f| f.name == field_name)?;
147 let field_data = unsafe { self.value.data().field(field.offset) };
148 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
149 }
150 VariantKind::Struct { fields } => {
151 let field = fields.iter().find(|f| f.name == field_name)?;
153 let field_data = unsafe { self.value.data().field(field.offset) };
154 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
155 }
156 _ => None, }
158 }
159
160 pub fn tuple_field(self, index: usize) -> Option<crate::Peek<'mem>> {
162 let variant = self.active_variant();
163
164 match &variant.kind {
165 VariantKind::Tuple { fields } => {
166 if index >= fields.len() {
167 return None;
168 }
169
170 let field = &fields[index];
171 let field_data = unsafe { self.value.data().field(field.offset) };
172 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
173 }
174 _ => None, }
176 }
177
178 #[cfg(feature = "alloc")]
180 pub fn fields_with_metadata(
181 self,
182 ) -> alloc::boxed::Box<
183 dyn Iterator<
184 Item = (
185 usize,
186 &'static str,
187 crate::Peek<'mem>,
188 &'static facet_core::Field,
189 ),
190 > + 'mem,
191 > {
192 let variant = self.active_variant();
193 let data = self.value.data();
194
195 match &variant.kind {
196 VariantKind::Struct { fields } => {
197 alloc::boxed::Box::new(fields.iter().enumerate().map(move |(i, field)| {
198 let field_data = unsafe { data.field(field.offset) };
199 let field_peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
200 (i, field.name, field_peek, field)
201 }))
202 }
203 VariantKind::Tuple { fields } => {
204 alloc::boxed::Box::new(fields.iter().enumerate().map(move |(i, field)| {
205 let field_data = unsafe { data.field(field.offset) };
206 let field_peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
207 (i, field.name, field_peek, field)
208 }))
209 }
210 _ => alloc::boxed::Box::new(core::iter::empty()),
211 }
212 }
213
214 #[cfg(feature = "alloc")]
216 pub fn fields(
217 self,
218 ) -> alloc::boxed::Box<dyn Iterator<Item = (&'static str, crate::Peek<'mem>)> + 'mem> {
219 let variant = self.active_variant();
220 let data = self.value.data();
221
222 match &variant.kind {
223 VariantKind::Struct { fields } => {
224 alloc::boxed::Box::new(fields.iter().map(move |field| {
225 let field_data = unsafe { data.field(field.offset) };
226 let peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
227 (field.name, peek)
228 }))
229 }
230 VariantKind::Tuple { fields } => {
231 alloc::boxed::Box::new(fields.iter().map(move |field| {
232 let field_data = unsafe { data.field(field.offset) };
233 let peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
234 (field.name, peek)
235 }))
236 }
237 _ => alloc::boxed::Box::new(core::iter::empty()),
238 }
239 }
240}