1use core::ops::Range;
2
3use facet_core::{Field, FieldFlags};
4
5use crate::Peek;
6use alloc::{vec, vec::Vec};
7
8use super::{PeekEnum, PeekStruct, PeekTuple};
9
10pub trait HasFields<'mem, 'facet, 'shape> {
15 fn fields(&self) -> FieldIter<'mem, 'facet, 'shape>;
17
18 fn fields_for_serialize(&self) -> FieldsForSerializeIter<'mem, 'facet, 'shape> {
20 FieldsForSerializeIter {
21 stack: vec![self.fields()],
22 }
23 }
24}
25
26pub struct FieldIter<'mem, 'facet, 'shape> {
28 state: FieldIterState<'mem, 'facet, 'shape>,
29 range: Range<usize>,
30}
31
32enum FieldIterState<'mem, 'facet, 'shape> {
33 Struct(PeekStruct<'mem, 'facet, 'shape>),
34 Tuple(PeekTuple<'mem, 'facet, 'shape>),
35 Enum {
36 peek_enum: PeekEnum<'mem, 'facet, 'shape>,
37 fields: &'shape [Field<'shape>],
38 },
39 FlattenedEnum {
40 field: Field<'shape>,
41 value: Peek<'mem, 'facet, 'shape>,
42 },
43}
44
45impl<'mem, 'facet, 'shape> FieldIter<'mem, 'facet, 'shape> {
46 pub(crate) fn new_struct(struct_: PeekStruct<'mem, 'facet, 'shape>) -> Self {
47 Self {
48 range: 0..struct_.ty.fields.len(),
49 state: FieldIterState::Struct(struct_),
50 }
51 }
52
53 pub(crate) fn new_enum(enum_: PeekEnum<'mem, 'facet, 'shape>) -> Self {
54 let variant = match enum_.active_variant() {
56 Ok(v) => v,
57 Err(e) => panic!("Cannot get active variant: {:?}", e),
58 };
59 let fields = &variant.data.fields;
60
61 Self {
62 range: 0..fields.len(),
63 state: FieldIterState::Enum {
64 peek_enum: enum_,
65 fields,
66 },
67 }
68 }
69
70 pub(crate) fn new_tuple(tuple: PeekTuple<'mem, 'facet, 'shape>) -> Self {
71 Self {
72 range: 0..tuple.len(),
73 state: FieldIterState::Tuple(tuple),
74 }
75 }
76
77 fn get_field_by_index(
78 &self,
79 index: usize,
80 ) -> Option<(Field<'shape>, Peek<'mem, 'facet, 'shape>)> {
81 match self.state {
82 FieldIterState::Struct(peek_struct) => {
83 let field = peek_struct.ty.fields.get(index).copied()?;
84 let value = peek_struct.field(index).ok()?;
85 Some((field, value))
86 }
87 FieldIterState::Tuple(peek_tuple) => {
88 let field = peek_tuple.ty.fields.get(index).copied()?;
89 let value = peek_tuple.field(index)?;
90 Some((field, value))
91 }
92 FieldIterState::Enum { peek_enum, fields } => {
93 let field = fields[index];
95 let field_value = match peek_enum.field(index) {
97 Ok(Some(v)) => v,
98 Ok(None) => return None,
99 Err(e) => panic!("Cannot get field: {:?}", e),
100 };
101 Some((field, field_value))
103 }
104 FieldIterState::FlattenedEnum { field, value } => {
105 if index == 0 {
106 Some((field, value))
107 } else {
108 None
109 }
110 }
111 }
112 }
113}
114
115impl<'mem, 'facet, 'shape> Iterator for FieldIter<'mem, 'facet, 'shape> {
116 type Item = (Field<'shape>, Peek<'mem, 'facet, 'shape>);
117
118 fn next(&mut self) -> Option<Self::Item> {
119 loop {
120 let index = self.range.next()?;
121
122 let Some(field) = self.get_field_by_index(index) else {
123 continue;
124 };
125
126 return Some(field);
127 }
128 }
129
130 fn size_hint(&self) -> (usize, Option<usize>) {
131 self.range.size_hint()
132 }
133}
134
135impl DoubleEndedIterator for FieldIter<'_, '_, '_> {
136 fn next_back(&mut self) -> Option<Self::Item> {
137 loop {
138 let index = self.range.next_back()?;
139
140 let Some(field) = self.get_field_by_index(index) else {
141 continue;
142 };
143
144 return Some(field);
145 }
146 }
147}
148
149impl ExactSizeIterator for FieldIter<'_, '_, '_> {}
150
151pub struct FieldsForSerializeIter<'mem, 'facet, 'shape> {
153 stack: Vec<FieldIter<'mem, 'facet, 'shape>>,
154}
155
156impl<'mem, 'facet, 'shape> Iterator for FieldsForSerializeIter<'mem, 'facet, 'shape> {
157 type Item = (Field<'shape>, Peek<'mem, 'facet, 'shape>);
158
159 fn next(&mut self) -> Option<Self::Item> {
160 loop {
161 let mut fields = self.stack.pop()?;
162 let Some((mut field, peek)) = fields.next() else {
163 continue;
164 };
165 self.stack.push(fields);
166
167 let Some(data) = peek.data().thin() else {
168 continue;
169 };
170 let should_skip = unsafe { field.should_skip_serializing(data) };
171
172 if should_skip {
173 continue;
174 }
175
176 if field.flags.contains(FieldFlags::FLATTEN) && !field.flattened {
177 if let Ok(struct_peek) = peek.into_struct() {
178 self.stack.push(FieldIter::new_struct(struct_peek))
179 } else if let Ok(enum_peek) = peek.into_enum() {
180 field.name = enum_peek
194 .active_variant()
195 .expect("Failed to get active variant")
196 .name;
197 field.flattened = true;
198 self.stack.push(FieldIter {
199 range: 0..1,
200 state: FieldIterState::FlattenedEnum { field, value: peek },
201 });
202 } else {
203 panic!("cannot flatten a {}", field.shape())
205 }
206 } else {
207 return Some((field, peek));
208 }
209 }
210 }
211}