facet_reflect/peek/
enum_.rs1use facet_core::{EnumDef, EnumRepr, Field, FieldAttribute, Shape, Variant};
2
3use crate::Peek;
4
5#[derive(Clone, Copy)]
7pub struct PeekEnum<'mem> {
8 pub(crate) value: Peek<'mem>,
13
14 pub(crate) def: EnumDef,
16}
17
18pub fn peek_enum(shape: &'static Shape) -> Option<EnumDef> {
20 match shape.def {
21 facet_core::Def::Enum(enum_def) => Some(enum_def),
22 _ => None,
23 }
24}
25
26pub fn peek_enum_repr(shape: &'static Shape) -> Option<EnumRepr> {
28 peek_enum(shape).map(|enum_def| enum_def.repr)
29}
30
31pub fn peek_enum_variants(shape: &'static Shape) -> Option<&'static [Variant]> {
33 peek_enum(shape).map(|enum_def| enum_def.variants)
34}
35
36impl<'mem> core::ops::Deref for PeekEnum<'mem> {
37 type Target = Peek<'mem>;
38
39 #[inline(always)]
40 fn deref(&self) -> &Self::Target {
41 &self.value
42 }
43}
44
45impl<'mem> PeekEnum<'mem> {
46 #[inline(always)]
48 pub fn def(self) -> EnumDef {
49 self.def
50 }
51
52 #[inline(always)]
54 pub fn repr(self) -> EnumRepr {
55 self.def.repr
56 }
57
58 #[inline(always)]
60 pub fn variants(self) -> &'static [Variant] {
61 self.def.variants
62 }
63
64 #[inline(always)]
66 pub fn variant_count(self) -> usize {
67 self.def.variants.len()
68 }
69
70 #[inline(always)]
72 pub fn variant_name(self, index: usize) -> Option<&'static str> {
73 self.def.variants.get(index).map(|variant| variant.name)
74 }
75
76 #[inline]
78 pub fn discriminant(self) -> i64 {
79 unsafe {
81 let data = self.value.data();
82 match self.def.repr {
83 EnumRepr::U8 => data.read::<u8>() as i64,
84 EnumRepr::U16 => data.read::<u16>() as i64,
85 EnumRepr::U32 => data.read::<u32>() as i64,
86 EnumRepr::U64 => data.read::<u64>() as i64,
87 EnumRepr::USize => data.read::<usize>() as i64,
88 EnumRepr::I8 => data.read::<i8>() as i64,
89 EnumRepr::I16 => data.read::<i16>() as i64,
90 EnumRepr::I32 => data.read::<i32>() as i64,
91 EnumRepr::I64 => data.read::<i64>(),
92 EnumRepr::ISize => data.read::<isize>() as i64,
93 _ => {
94 data.read::<u32>() as i64
96 }
97 }
98 }
99 }
100
101 #[inline]
103 pub fn variant_index(self) -> usize {
104 let discriminant = self.discriminant();
105
106 self.def
108 .variants
109 .iter()
110 .position(|variant| variant.discriminant == discriminant)
111 .expect("No variant found with matching discriminant")
112 }
113
114 #[inline]
116 pub fn active_variant(self) -> &'static Variant {
117 let index = self.variant_index();
118 &self.def.variants[index]
119 }
120
121 #[inline]
123 pub fn variant_name_active(self) -> &'static str {
124 self.active_variant().name
125 }
126
127 pub fn field(self, index: usize) -> Option<Peek<'mem>> {
131 let variant = self.active_variant();
132 let fields = &variant.data.fields;
133
134 if index >= fields.len() {
135 return None;
136 }
137
138 let field = &fields[index];
139 let field_data = unsafe { self.value.data().field(field.offset) };
140 Some(Peek {
141 data: field_data,
142 shape: field.shape(),
143 })
144 }
145
146 pub fn field_index(self, field_name: &str) -> Option<usize> {
148 let variant = self.active_variant();
149 variant
150 .data
151 .fields
152 .iter()
153 .position(|f| f.name == field_name)
154 }
155
156 pub fn field_by_name(self, field_name: &str) -> Option<Peek<'mem>> {
158 let index = self.field_index(field_name)?;
159 self.field(index)
160 }
161
162 #[inline]
164 pub fn fields(self) -> impl Iterator<Item = (&'static Field, Peek<'mem>)> {
165 let variant = self.active_variant();
166 let fields = &variant.data.fields;
167
168 fields.iter().map(move |field| {
170 let field_data = unsafe { self.value.data().field(field.offset) };
171 let peek = Peek {
172 data: field_data,
173 shape: field.shape(),
174 };
175 (field, peek)
176 })
177 }
178
179 #[inline]
181 pub fn fields_for_serialize(&self) -> impl Iterator<Item = (&'static Field, Peek<'mem>)> + '_ {
182 self.fields().filter(|(field, peek)| {
183 for attr in field.attributes {
184 match attr {
185 FieldAttribute::SkipSerializingIf(fn_ptr) => {
186 if unsafe { fn_ptr(peek.data()) } {
187 return false;
188 }
189 }
190 FieldAttribute::SkipSerializing => {
191 return false;
192 }
193 _ => {}
194 }
195 }
196 true
197 })
198 }
199}