• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 19774894729

28 Nov 2025 10:22PM UTC coverage: 59.711% (-0.6%) from 60.346%
19774894729

push

github

fasterthanlime
Add DynamicValue support for deserializing into facet_value::Value

This adds support for deserializing JSON (and potentially other formats)
into facet_value::Value without format crates needing to depend on facet-value.

Key changes:
- Add Def::DynamicValue variant with vtable for building dynamic values
- Implement Facet trait for Value in facet-value
- Extend Partial to handle DynamicValue scalars via set_into_dynamic_value
- Add deserialize_dynamic_value handler in facet-json

Currently supports scalar values (null, bool, numbers, strings).
Arrays and objects are stubbed out with TODO errors.

451 of 922 new or added lines in 20 files covered. (48.92%)

29 existing lines in 3 files now uncovered.

16657 of 27896 relevant lines covered (59.71%)

153.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.67
/facet-reflect/src/partial/partial_api/fields.rs
1
use super::*;
2

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Field selection
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl Partial<'_> {
7
    /// Find the index of a field by name in the current struct
8
    ///
9
    /// If the current frame isn't a struct or an enum (with a selected variant)
10
    /// then this returns `None` for sure.
11
    pub fn field_index(&self, field_name: &str) -> Option<usize> {
97✔
12
        let frame = self.frames().last()?;
97✔
13

14
        match frame.shape.ty {
97✔
15
            Type::User(UserType::Struct(struct_def)) => {
94✔
16
                struct_def.fields.iter().position(|f| f.name == field_name)
146✔
17
            }
18
            Type::User(UserType::Enum(_)) => {
19
                // If we're in an enum variant, check its fields
20
                if let Tracker::Enum { variant, .. } = &frame.tracker {
3✔
21
                    variant
3✔
22
                        .data
3✔
23
                        .fields
3✔
24
                        .iter()
3✔
25
                        .position(|f| f.name == field_name)
6✔
26
                } else {
27
                    None
×
28
                }
29
            }
30
            _ => None,
×
31
        }
32
    }
97✔
33

34
    /// Check if a struct field at the given index has been set
35
    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
441✔
36
        let frame = self.frames().last().ok_or(ReflectError::NoActiveFrame)?;
441✔
37

38
        match &frame.tracker {
441✔
39
            Tracker::Scalar => Ok(frame.is_init),
108✔
40
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
326✔
41
            Tracker::Enum { data, variant, .. } => {
7✔
42
                // Check if the field is already marked as set
43
                if data.get(index) {
7✔
44
                    return Ok(true);
7✔
45
                }
×
46

47
                // For enum variant fields that are empty structs, they are always initialized
48
                if let Some(field) = variant.data.fields.get(index) {
×
49
                    if let Type::User(UserType::Struct(field_struct)) = field.shape().ty {
×
50
                        if field_struct.fields.is_empty() {
×
51
                            return Ok(true);
×
52
                        }
×
53
                    }
×
54
                }
×
55

56
                Ok(false)
×
57
            }
58
            Tracker::Option { building_inner } => {
×
59
                // For Options, index 0 represents the inner value
60
                if index == 0 {
×
61
                    Ok(!building_inner)
×
62
                } else {
63
                    Err(ReflectError::InvalidOperation {
×
64
                        operation: "is_field_set",
×
65
                        reason: "Option only has one field (index 0)",
×
66
                    })
×
67
                }
68
            }
69
            _ => Err(ReflectError::InvalidOperation {
×
70
                operation: "is_field_set",
×
71
                reason: "Current frame is not a struct, enum variant, or option",
×
72
            }),
×
73
        }
74
    }
441✔
75

76
    /// Selects a field (by name) of a struct or enum data.
77
    ///
78
    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
79
    /// and friends.
80
    pub fn begin_field(&mut self, field_name: &str) -> Result<&mut Self, ReflectError> {
1,880✔
81
        self.require_active()?;
1,880✔
82

83
        let frame = self.frames().last().unwrap();
1,880✔
84
        let fields = self.get_fields()?;
1,880✔
85
        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
3,132✔
86
            return Err(ReflectError::FieldError {
9✔
87
                shape: frame.shape,
9✔
88
                field_error: facet_core::FieldError::NoSuchField,
9✔
89
            });
9✔
90
        };
91
        self.begin_nth_field(idx)
1,867✔
92
    }
1,880✔
93

94
    /// Begins the nth field of a struct, enum variant, or array, by index.
95
    ///
96
    /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
97
    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
2,317✔
98
        self.require_active()?;
2,317✔
99

100
        // In deferred mode, get the field name for path tracking and check for stored frames.
101
        // Only track the path if we're at a "navigable" level - i.e., the path length matches
102
        // the expected depth (frames.len() - 1). If we're inside a collection item, the path
103
        // will be shorter than expected, so we shouldn't add to it.
104
        let field_name = self.get_field_name_for_path(idx);
2,317✔
105

106
        // Update current_path in deferred mode
107
        if let FrameMode::Deferred {
108
            stack,
1,009✔
109
            start_depth,
1,009✔
110
            current_path,
1,009✔
111
            stored_frames,
1,009✔
112
            ..
113
        } = &mut self.mode
2,317✔
114
        {
115
            // Only track path if we're at the expected navigable depth
116
            // Path should have (frames.len() - start_depth) entries before we add this field
117
            let relative_depth = stack.len() - *start_depth;
1,009✔
118
            let should_track = current_path.len() == relative_depth;
1,009✔
119

120
            if let Some(name) = field_name {
1,009✔
121
                if should_track {
996✔
122
                    current_path.push(name);
902✔
123

124
                    // Check if we have a stored frame for this path
125
                    if let Some(stored_frame) = stored_frames.remove(current_path) {
902✔
126
                        trace!("begin_nth_field: Restoring stored frame for path {current_path:?}");
127

128
                        // Update parent's current_child tracking
129
                        let frame = stack.last_mut().unwrap();
61✔
130
                        frame.tracker.set_current_child(idx);
61✔
131

132
                        stack.push(stored_frame);
61✔
133
                        return Ok(self);
61✔
134
                    }
841✔
135
                }
94✔
136
            }
13✔
137
        }
1,308✔
138

139
        let frame = self.frames_mut().last_mut().unwrap();
2,256✔
140

141
        let next_frame = match frame.shape.ty {
2,256✔
142
            Type::User(user_type) => match user_type {
2,163✔
143
                UserType::Struct(struct_type) => {
1,955✔
144
                    Self::begin_nth_struct_field(frame, struct_type, idx)?
1,955✔
145
                }
146
                UserType::Enum(_) => {
147
                    // Check if we have a variant selected
148
                    match &frame.tracker {
208✔
149
                        Tracker::Enum { variant, .. } => {
208✔
150
                            Self::begin_nth_enum_field(frame, variant, idx)?
208✔
151
                        }
152
                        _ => {
153
                            return Err(ReflectError::OperationFailed {
×
154
                                shape: frame.shape,
×
155
                                operation: "must call select_variant before selecting enum fields",
×
156
                            });
×
157
                        }
158
                    }
159
                }
160
                UserType::Union(_) => {
161
                    return Err(ReflectError::OperationFailed {
×
162
                        shape: frame.shape,
×
163
                        operation: "cannot select a field from a union",
×
164
                    });
×
165
                }
166
                UserType::Opaque => {
167
                    return Err(ReflectError::OperationFailed {
×
168
                        shape: frame.shape,
×
169
                        operation: "cannot select a field from an opaque type",
×
170
                    });
×
171
                }
172
            },
173
            Type::Sequence(sequence_type) => match sequence_type {
93✔
174
                SequenceType::Array(array_type) => {
93✔
175
                    Self::begin_nth_array_element(frame, array_type, idx)?
93✔
176
                }
177
                SequenceType::Slice(_) => {
178
                    return Err(ReflectError::OperationFailed {
×
179
                        shape: frame.shape,
×
180
                        operation: "cannot select a field from slices yet",
×
181
                    });
×
182
                }
183
            },
184
            _ => {
185
                return Err(ReflectError::OperationFailed {
×
186
                    shape: frame.shape,
×
187
                    operation: "cannot select a field from this type",
×
188
                });
×
189
            }
190
        };
191

192
        self.frames_mut().push(next_frame);
2,255✔
193
        Ok(self)
2,255✔
194
    }
2,317✔
195

196
    /// Get the field name for path tracking (used in deferred mode)
197
    fn get_field_name_for_path(&self, idx: usize) -> Option<&'static str> {
2,317✔
198
        let frame = self.frames().last()?;
2,317✔
199
        match frame.shape.ty {
2,224✔
200
            Type::User(UserType::Struct(struct_type)) => {
2,016✔
201
                struct_type.fields.get(idx).map(|f| f.name)
2,016✔
202
            }
203
            Type::User(UserType::Enum(_)) => {
204
                if let Tracker::Enum { variant, .. } = &frame.tracker {
208✔
205
                    variant.data.fields.get(idx).map(|f| f.name)
208✔
206
                } else {
207
                    None
×
208
                }
209
            }
210
            // For arrays, we could use index as string, but for now return None
211
            _ => None,
93✔
212
        }
213
    }
2,317✔
214

215
    /// Sets the given field to its default value, preferring:
216
    ///
217
    ///   * A `default = some_fn()` function
218
    ///   * The field's `Default` implementation if any
219
    ///
220
    /// But without going all the way up to the parent struct's `Default` impl.
221
    ///
222
    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
223
    pub fn set_nth_field_to_default(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
26✔
224
        self.require_active()?;
26✔
225

226
        let frame = self.frames().last().unwrap();
26✔
227
        let fields = self.get_fields()?;
26✔
228

229
        if idx >= fields.len() {
26✔
230
            return Err(ReflectError::OperationFailed {
×
231
                shape: frame.shape,
×
232
                operation: "field index out of bounds",
×
233
            });
×
234
        }
26✔
235

236
        let field = fields[idx];
26✔
237

238
        // Check for field-level default function first, then type-level default
239
        if let Some(field_default_fn) = field.vtable.default_fn {
26✔
240
            self.begin_nth_field(idx)?;
8✔
241
            // the field default fn should be well-behaved
242
            unsafe {
243
                self.set_from_function(|ptr| {
8✔
244
                    field_default_fn(ptr);
8✔
245
                    Ok(())
8✔
246
                })?;
8✔
247
            }
248
            self.end()
8✔
249
        } else if field.shape().is(Characteristic::Default) {
18✔
250
            self.begin_nth_field(idx)?;
18✔
251
            self.set_default()?;
18✔
252
            self.end()
18✔
253
        } else {
254
            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
255
                shape: field.shape(),
×
256
            });
×
257
        }
258
    }
26✔
259

260
    /// Given a `Partial` for the same shape, and assuming that partial has the nth
261
    /// field initialized, move the value from `src` to `self`, marking it as deinitialized
262
    /// in `src`.
263
    pub fn steal_nth_field(
2✔
264
        &mut self,
2✔
265
        src: &mut Partial,
2✔
266
        field_index: usize,
2✔
267
    ) -> Result<&mut Self, ReflectError> {
2✔
268
        let dst_shape = self.shape();
2✔
269
        let src_shape = src.shape();
2✔
270
        if dst_shape != src_shape {
2✔
271
            return Err(ReflectError::HeistCancelledDifferentShapes {
×
272
                src_shape,
×
273
                dst_shape,
×
274
            });
×
275
        }
2✔
276

277
        // FIXME: what about enums? we don't check that the right variant is
278
        // selected here.
279
        if !src.is_field_set(field_index)? {
2✔
280
            return Err(ReflectError::InvariantViolation {
×
281
                invariant: "stolen field must be initialized",
×
282
            });
×
283
        }
2✔
284

285
        let maybe_fields = match src_shape.ty {
2✔
286
            Type::Primitive(_primitive_type) => None,
×
287
            Type::Sequence(_sequence_type) => None,
×
288
            Type::User(user_type) => match user_type {
2✔
289
                UserType::Struct(struct_type) => Some(struct_type.fields),
2✔
290
                UserType::Enum(_enum_type) => match self.selected_variant() {
×
291
                    Some(variant) => Some(variant.data.fields),
×
292
                    None => {
293
                        return Err(ReflectError::InvariantViolation {
×
294
                            invariant: "enum field thief must have variant selected",
×
295
                        });
×
296
                    }
297
                },
298
                UserType::Union(_union_type) => None,
×
299
                UserType::Opaque => None,
×
300
            },
301
            Type::Pointer(_pointer_type) => None,
×
302
        };
303

304
        let Some(fields) = maybe_fields else {
2✔
305
            return Err(ReflectError::OperationFailed {
×
306
                shape: src_shape,
×
307
                operation: "fetching field list for steal_nth_field",
×
308
            });
×
309
        };
310

311
        if field_index >= fields.len() {
2✔
312
            return Err(ReflectError::OperationFailed {
×
313
                shape: src_shape,
×
314
                operation: "field index out of bounds",
×
315
            });
×
316
        }
2✔
317
        let field = fields[field_index];
2✔
318

319
        let src_frame = src.frames_mut().last_mut().unwrap();
2✔
320

321
        self.begin_nth_field(field_index)?;
2✔
322
        unsafe {
323
            self.set_from_function(|dst_field_ptr| {
2✔
324
                let src_field_ptr = src_frame.data.field_init_at(field.offset).as_const();
2✔
325
                dst_field_ptr
2✔
326
                    .copy_from(src_field_ptr, field.shape())
2✔
327
                    .unwrap();
2✔
328
                Ok(())
2✔
329
            })?;
2✔
330
        }
331
        self.end()?;
2✔
332

333
        // now mark field as uninitialized in `src`
334
        match &mut src_frame.tracker {
2✔
335
            Tracker::Scalar => {
336
                if !src_frame.is_init {
1✔
NEW
337
                    unreachable!(
×
338
                        "we just stole a field from src, it couldn't have been fully uninit"
339
                    )
340
                }
1✔
341
                // all struct fields were init so we don't even have a struct tracker,
342
                // let's make one!
343
                let mut iset = ISet::new(fields.len());
1✔
344
                iset.set_all();
1✔
345
                iset.unset(field_index);
1✔
346
                src_frame.tracker = Tracker::Struct {
1✔
347
                    iset,
1✔
348
                    current_child: None,
1✔
349
                };
1✔
350
                src_frame.is_init = false; // no longer fully initialized
1✔
351
            }
352
            Tracker::Array { .. } => unreachable!("can't steal fields from arrays"),
×
353
            Tracker::Struct { iset, .. } => {
1✔
354
                iset.unset(field_index);
1✔
355
            }
1✔
356
            Tracker::SmartPointer => {
357
                unreachable!("can't steal fields from smart pointers")
×
358
            }
359
            Tracker::SmartPointerSlice { .. } => {
360
                unreachable!("can't steal fields from smart pointer slices")
×
361
            }
362
            Tracker::Enum { data, .. } => {
×
363
                data.unset(field_index);
×
364
            }
×
365
            Tracker::List { .. } => {
366
                unreachable!("can't steal fields from lists")
×
367
            }
368
            Tracker::Map { .. } => {
369
                unreachable!("can't steal fields from maps")
×
370
            }
371
            Tracker::Set { .. } => {
372
                unreachable!("can't steal fields from sets")
×
373
            }
374
            Tracker::Option { .. } => {
375
                unreachable!("can't steal fields from options")
×
376
            }
377
            Tracker::DynamicValue { .. } => {
NEW
378
                unreachable!("can't steal fields from dynamic values")
×
379
            }
380
        }
381

382
        Ok(self)
2✔
383
    }
2✔
384
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc