facet_reflect/partial/partial_api/fields.rs
1use super::*;
2use facet_path::PathStep;
3
4////////////////////////////////////////////////////////////////////////////////////////////////////
5// Field selection
6////////////////////////////////////////////////////////////////////////////////////////////////////
7impl<const BORROW: bool> Partial<'_, BORROW> {
8 /// Find the index of a field by name in the current struct
9 ///
10 /// If the current frame isn't a struct or an enum (with a selected variant)
11 /// then this returns `None` for sure.
12 pub fn field_index(&self, field_name: &str) -> Option<usize> {
13 let frame = self.frames().last()?;
14 let node_id = frame.type_plan;
15
16 // For structs: use StructPlan's field_lookup
17 if let Some(struct_plan) = self.root_plan.struct_plan_by_id(node_id) {
18 return struct_plan.field_lookup.find(field_name, &self.root_plan);
19 }
20
21 // For enums with selected variant: use variant's field_lookup
22 if let Some(enum_plan) = self.root_plan.enum_plan_by_id(node_id)
23 && let Tracker::Enum { variant_idx, .. } = &frame.tracker
24 {
25 let variants = self.root_plan.variants(enum_plan.variants);
26 return variants
27 .get(*variant_idx)?
28 .field_lookup
29 .find(field_name, &self.root_plan);
30 }
31
32 None
33 }
34
35 /// Check if a struct field at the given index has been set
36 pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
37 let frame = self
38 .frames()
39 .last()
40 .ok_or_else(|| self.err(ReflectErrorKind::NoActiveFrame))?;
41
42 // First check via ISet/tracker
43 let is_set_in_tracker = match &frame.tracker {
44 Tracker::Scalar => frame.is_init,
45 Tracker::Struct { iset, .. } => iset.get(index),
46 Tracker::Enum { data, variant, .. } => {
47 // Check if the field is already marked as set
48 if data.get(index) {
49 true
50 } else if let Some(field) = variant.data.fields.get(index)
51 && let Type::User(UserType::Struct(field_struct)) = field.shape().ty
52 && field_struct.fields.is_empty()
53 {
54 // For enum variant fields that are empty structs, they are always initialized
55 true
56 } else {
57 false
58 }
59 }
60 Tracker::Option { building_inner, .. } => {
61 if index == 0 {
62 !*building_inner
63 } else {
64 return Err(self.err(ReflectErrorKind::InvalidOperation {
65 operation: "is_field_set",
66 reason: "Option only has one field (index 0)",
67 }));
68 }
69 }
70 Tracker::Result { building_inner, .. } => {
71 if index == 0 {
72 !building_inner
73 } else {
74 return Err(self.err(ReflectErrorKind::InvalidOperation {
75 operation: "is_field_set",
76 reason: "Result only has one field (index 0)",
77 }));
78 }
79 }
80 _ => {
81 return Err(self.err(ReflectErrorKind::InvalidOperation {
82 operation: "is_field_set",
83 reason: "Current frame is not a struct, enum variant, option, or result",
84 }));
85 }
86 };
87
88 if is_set_in_tracker {
89 return Ok(true);
90 }
91
92 // In deferred mode, also check if there's a stored frame for this field.
93 // The ISet won't be updated when frames are stored, so we need to check
94 // stored_frames directly to know if a value exists.
95 if let FrameMode::Deferred { stored_frames, .. } = &self.mode {
96 // Construct the full path for this field by deriving current path
97 // and appending the field step
98 let mut check_path = self.derive_path();
99 check_path.push(PathStep::Field(index as u32));
100
101 // Check if this path exists in stored frames
102 if stored_frames.contains_key(&check_path) {
103 return Ok(true);
104 }
105 }
106
107 Ok(false)
108 }
109
110 /// Selects a field (by name) of a struct or enum data.
111 ///
112 /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
113 /// and friends.
114 pub fn begin_field(self, field_name: &str) -> Result<Self, ReflectError> {
115 let frame = self.frames().last().unwrap();
116 let fields = self.get_fields()?;
117 let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
118 return Err(self.err(ReflectErrorKind::FieldError {
119 shape: frame.allocated.shape(),
120 field_error: facet_core::FieldError::NoSuchField,
121 }));
122 };
123 self.begin_nth_field(idx)
124 }
125
126 /// Begins the nth field of a struct, enum variant, or array, by index.
127 ///
128 /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
129 pub fn begin_nth_field(mut self, idx: usize) -> Result<Self, ReflectError> {
130 // Handle deferred mode path tracking (rare path - only for partial deserialization)
131 if self.is_deferred() {
132 // Derive the current path and construct what the path WOULD be after entering this field
133 let mut check_path = self.derive_path();
134 check_path.push(PathStep::Field(idx as u32));
135
136 if let FrameMode::Deferred {
137 stack,
138 stored_frames,
139 ..
140 } = &mut self.mode
141 {
142 // Check if we have a stored frame for this path (re-entry)
143 if let Some(mut stored_frame) = stored_frames.remove(&check_path) {
144 trace!("begin_nth_field: Restoring stored frame for path {check_path:?}");
145
146 // Update parent's current_child tracking
147 let frame = stack.last_mut().unwrap();
148 frame.tracker.set_current_child(idx);
149
150 // Clear the restored frame's current_child - we haven't entered any of its
151 // children yet in this new traversal. Without this, derive_path() would
152 // include stale navigation state and compute incorrect paths.
153 stored_frame.tracker.clear_current_child();
154
155 // For Option frames, reset building_inner to false. When an Option frame
156 // is stored, it may have building_inner=true (if we were inside begin_some).
157 // When restored via begin_field, we're re-entering the Option container
158 // itself, not its inner value - so building_inner should be false.
159 // Without this, derive_path() would include an extra OptionSome step,
160 // causing path mismatches when we call begin_some() to find the stored
161 // inner frame.
162 if let Tracker::Option { building_inner, .. } = &mut stored_frame.tracker {
163 *building_inner = false;
164 }
165
166 stack.push(stored_frame);
167 return Ok(self);
168 }
169 }
170 }
171
172 // Get shape and parent NodeId first (NodeId is Copy, no borrow conflict)
173 let frame = self.frames().last().unwrap();
174 let shape = frame.allocated.shape();
175 let parent_node = frame.type_plan; // Copy the NodeId
176
177 let next_frame = match shape.ty {
178 Type::User(user_type) => match user_type {
179 UserType::Struct(struct_type) => {
180 // Check bounds first before looking up the type plan node
181 if idx >= struct_type.fields.len() {
182 return Err(self.err(ReflectErrorKind::OperationFailed {
183 shape,
184 operation: "field index out of bounds",
185 }));
186 }
187 // Compute child NodeId before mutable borrow
188 let child_plan_id = self
189 .root_plan
190 .struct_field_node_id(parent_node, idx)
191 .expect("TypePlan must have struct field node");
192 let frame = self.frames_mut().last_mut().unwrap();
193 Self::begin_nth_struct_field(frame, struct_type, idx, child_plan_id)
194 .map_err(|e| self.err(e))?
195 }
196 UserType::Enum(_) => {
197 // Check if we have a variant selected and get variant info
198 let frame = self.frames().last().unwrap();
199 let (variant, variant_idx) = match &frame.tracker {
200 Tracker::Enum {
201 variant,
202 variant_idx,
203 ..
204 } => (*variant, *variant_idx),
205 _ => {
206 return Err(self.err(ReflectErrorKind::OperationFailed {
207 shape,
208 operation: "must call select_variant before selecting enum fields",
209 }));
210 }
211 };
212 // Compute child NodeId using stored variant_idx (O(1) lookup, not O(n) search)
213 let child_plan_id = self
214 .root_plan
215 .enum_variant_field_node_id(parent_node, variant_idx, idx)
216 .expect("TypePlan must have enum variant field node");
217 let frame = self.frames_mut().last_mut().unwrap();
218 Self::begin_nth_enum_field(frame, variant, idx, child_plan_id)
219 .map_err(|e| self.err(e))?
220 }
221 UserType::Union(_) => {
222 return Err(self.err(ReflectErrorKind::OperationFailed {
223 shape,
224 operation: "cannot select a field from a union",
225 }));
226 }
227 UserType::Opaque => {
228 return Err(self.err(ReflectErrorKind::OperationFailed {
229 shape,
230 operation: "cannot select a field from an opaque type",
231 }));
232 }
233 },
234 Type::Sequence(sequence_type) => match sequence_type {
235 SequenceType::Array(array_type) => {
236 // Compute child NodeId before mutable borrow
237 let child_plan_id = self
238 .root_plan
239 .list_item_node_id(parent_node)
240 .expect("TypePlan must have array item node");
241 let frame = self.frames_mut().last_mut().unwrap();
242 Self::begin_nth_array_element(frame, array_type, idx, child_plan_id)
243 .map_err(|e| self.err(e))?
244 }
245 SequenceType::Slice(_) => {
246 return Err(self.err(ReflectErrorKind::OperationFailed {
247 shape,
248 operation: "cannot select a field from slices yet",
249 }));
250 }
251 },
252 _ => {
253 return Err(self.err(ReflectErrorKind::OperationFailed {
254 shape,
255 operation: "cannot select a field from this type",
256 }));
257 }
258 };
259
260 self.frames_mut().push(next_frame);
261 Ok(self)
262 }
263
264 /// Sets the given field to its default value, preferring:
265 ///
266 /// * A `default = some_fn()` function
267 /// * The field's `Default` implementation if any
268 ///
269 /// But without going all the way up to the parent struct's `Default` impl.
270 ///
271 /// Errors out if idx is out of bound, if the field has no default method or Default impl.
272 pub fn set_nth_field_to_default(mut self, idx: usize) -> Result<Self, ReflectError> {
273 let frame = self.frames().last().unwrap();
274 let fields = self.get_fields()?;
275
276 if idx >= fields.len() {
277 return Err(self.err(ReflectErrorKind::OperationFailed {
278 shape: frame.allocated.shape(),
279 operation: "field index out of bounds",
280 }));
281 }
282
283 let field = fields[idx];
284
285 // Check for field-level default first, then type-level default
286 if let Some(default_source) = field.default {
287 self = self.begin_nth_field(idx)?;
288 match default_source {
289 facet_core::DefaultSource::Custom(field_default_fn) => {
290 // Custom default function provided via #[facet(default = expr)]
291 self = unsafe {
292 self.set_from_function(|ptr| {
293 field_default_fn(ptr);
294 Ok(())
295 })?
296 };
297 }
298 facet_core::DefaultSource::FromTrait => {
299 // Use the type's Default trait via #[facet(default)]
300 self = self.set_default()?;
301 }
302 }
303 self.end()
304 } else if field.shape().is(Characteristic::Default) {
305 self = self.begin_nth_field(idx)?;
306 self = self.set_default()?;
307 self.end()
308 } else {
309 Err(self.err(ReflectErrorKind::DefaultAttrButNoDefaultImpl {
310 shape: field.shape(),
311 }))
312 }
313 }
314}