Skip to main content

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}