facet_reflect/peek/
enum_.rs1use facet_core::{EnumDef, EnumRepr, OpaqueConst, Shape, Variant, VariantKind};
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5#[cfg(feature = "alloc")]
6use alloc::boxed::Box;
7
8#[derive(Clone, Copy)]
10pub struct PeekEnum<'mem> {
11 value: crate::PeekValue<'mem>,
17 def: EnumDef,
18}
19
20pub fn peek_enum(shape: &'static Shape) -> Option<EnumDef> {
22 match shape.def {
23 facet_core::Def::Enum(enum_def) => Some(enum_def),
24 _ => None,
25 }
26}
27
28pub fn peek_enum_repr(shape: &'static Shape) -> Option<EnumRepr> {
30 peek_enum(shape).map(|enum_def| enum_def.repr)
31}
32
33pub fn peek_enum_variants(shape: &'static Shape) -> Option<&'static [Variant]> {
35 peek_enum(shape).map(|enum_def| enum_def.variants)
36}
37
38impl<'mem> core::ops::Deref for PeekEnum<'mem> {
39 type Target = crate::PeekValue<'mem>;
40
41 #[inline(always)]
42 fn deref(&self) -> &Self::Target {
43 &self.value
44 }
45}
46
47impl<'mem> PeekEnum<'mem> {
48 pub(crate) fn new(value: crate::PeekValue<'mem>, def: EnumDef) -> Self {
50 Self { value, def }
51 }
52
53 #[inline(always)]
55 pub fn def(self) -> EnumDef {
56 self.def
57 }
58
59 #[inline(always)]
61 pub fn repr(self) -> EnumRepr {
62 self.def.repr
63 }
64
65 #[inline(always)]
67 pub fn variants(self) -> &'static [Variant] {
68 self.def.variants
69 }
70
71 #[inline(always)]
73 pub fn variant_count(self) -> usize {
74 self.def.variants.len()
75 }
76
77 #[inline(always)]
79 pub fn variant_name(self, index: usize) -> Option<&'static str> {
80 self.def.variants.get(index).map(|variant| variant.name)
81 }
82
83 #[inline]
85 pub fn discriminant(self) -> i64 {
86 unsafe {
88 let data = self.value.data();
89 match self.def.repr {
90 EnumRepr::U8 => data.read::<u8>() as i64,
91 EnumRepr::U16 => data.read::<u16>() as i64,
92 EnumRepr::U32 => data.read::<u32>() as i64,
93 EnumRepr::U64 => data.read::<u64>() as i64,
94 EnumRepr::USize => data.read::<usize>() as i64,
95 EnumRepr::I8 => data.read::<i8>() as i64,
96 EnumRepr::I16 => data.read::<i16>() as i64,
97 EnumRepr::I32 => data.read::<i32>() as i64,
98 EnumRepr::I64 => data.read::<i64>(),
99 EnumRepr::ISize => data.read::<isize>() as i64,
100 _ => {
101 data.read::<u32>() as i64
103 }
104 }
105 }
106 }
107
108 #[inline]
110 pub fn variant_index(self) -> usize {
111 let discriminant = self.discriminant();
112
113 for (index, variant) in self.def.variants.iter().enumerate() {
115 let variant_discriminant = match variant.discriminant {
116 Some(value) => value,
117 None => index as i64,
118 };
119
120 if variant_discriminant == discriminant {
121 return index;
122 }
123 }
124
125 panic!("Invalid discriminant value for enum")
127 }
128
129 #[inline]
131 pub fn active_variant(self) -> &'static Variant {
132 let index = self.variant_index();
133 &self.def.variants[index]
134 }
135
136 #[inline]
138 pub fn variant_name_active(self) -> &'static str {
139 self.active_variant().name
140 }
141
142 #[inline]
144 pub fn variant_kind_active(self) -> &'static VariantKind {
145 &self.active_variant().kind
146 }
147
148 pub(crate) fn variant_data(self) -> OpaqueConst<'mem> {
150 let variant_offset = self.active_variant().offset;
151 unsafe { self.value.data().field(variant_offset) }
152 }
153
154 pub fn field(self, field_name: &str) -> Option<crate::Peek<'mem>> {
156 let variant = self.active_variant();
157
158 match &variant.kind {
159 VariantKind::Unit => None, VariantKind::Tuple { fields } => {
161 let field = fields.iter().find(|f| f.name == field_name)?;
163 let field_data = unsafe { self.variant_data().field(field.offset) };
164 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
165 }
166 VariantKind::Struct { fields } => {
167 let field = fields.iter().find(|f| f.name == field_name)?;
169 let field_data = unsafe { self.variant_data().field(field.offset) };
170 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
171 }
172 _ => None, }
174 }
175
176 pub fn tuple_field(self, index: usize) -> Option<crate::Peek<'mem>> {
178 let variant = self.active_variant();
179
180 match &variant.kind {
181 VariantKind::Tuple { fields } => {
182 if index >= fields.len() {
183 return None;
184 }
185
186 let field = &fields[index];
187 let field_data = unsafe { self.variant_data().field(field.offset) };
188 Some(unsafe { crate::Peek::unchecked_new(field_data, field.shape) })
189 }
190 _ => None, }
192 }
193
194 #[cfg(feature = "alloc")]
196 pub fn fields_with_metadata(
197 self,
198 ) -> Box<
199 dyn Iterator<
200 Item = (
201 usize,
202 &'static str,
203 crate::Peek<'mem>,
204 &'static facet_core::Field,
205 ),
206 > + 'mem,
207 > {
208 let variant = self.active_variant();
209 let data = self.variant_data();
210
211 match &variant.kind {
212 VariantKind::Struct { fields } => {
213 Box::new(fields.iter().enumerate().map(move |(i, field)| {
214 let field_data = unsafe { data.field(field.offset) };
215 let field_peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
216 (i, field.name, field_peek, field)
217 }))
218 }
219 VariantKind::Tuple { fields } => {
220 Box::new(fields.iter().enumerate().map(move |(i, field)| {
221 let field_data = unsafe { data.field(field.offset) };
222 let field_peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
223 (i, field.name, field_peek, field)
224 }))
225 }
226 _ => Box::new(core::iter::empty()),
227 }
228 }
229
230 #[cfg(feature = "alloc")]
232 pub fn fields(self) -> Box<dyn Iterator<Item = (&'static str, crate::Peek<'mem>)> + 'mem> {
233 let variant = self.active_variant();
234 let data = self.variant_data();
235
236 match &variant.kind {
237 VariantKind::Struct { fields } => Box::new(fields.iter().map(move |field| {
238 let field_data = unsafe { data.field(field.offset) };
239 let peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
240 (field.name, peek)
241 })),
242 VariantKind::Tuple { fields } => Box::new(fields.iter().map(move |field| {
243 let field_data = unsafe { data.field(field.offset) };
244 let peek = unsafe { crate::Peek::unchecked_new(field_data, field.shape) };
245 (field.name, peek)
246 })),
247 _ => Box::new(core::iter::empty()),
248 }
249 }
250}