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