• 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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Misc.
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl<'facet> Partial<'facet> {
7
    /// Returns the current frame count (depth of nesting)
8
    ///
9
    /// The initial frame count is 1 — `begin_field` would push a new frame,
10
    /// bringing it to 2, then `end` would bring it back to `1`.
11
    ///
12
    /// This is an implementation detail of `Partial`, kinda, but deserializers
13
    /// might use this for debug assertions, to make sure the state is what
14
    /// they think it is.
15
    #[inline]
16
    pub fn frame_count(&self) -> usize {
28✔
17
        self.frames().len()
28✔
18
    }
28✔
19

20
    /// Returns the shape of the current frame.
21
    #[inline]
22
    pub fn shape(&self) -> &'static Shape {
13,662✔
23
        self.frames()
13,662✔
24
            .last()
13,662✔
25
            .expect("Partial always has at least one frame")
13,662✔
26
            .shape
13,662✔
27
    }
13,662✔
28

29
    /// Returns the current deferred resolution, if in deferred mode.
30
    #[inline]
31
    pub fn deferred_resolution(&self) -> Option<&Resolution> {
3✔
32
        self.resolution()
3✔
33
    }
3✔
34

35
    /// Returns the current path in deferred mode as a slice (for debugging/tracing).
36
    #[inline]
37
    pub fn current_path_slice(&self) -> Option<&[&'static str]> {
×
38
        self.current_path().map(|p| p.as_slice())
×
39
    }
×
40

41
    /// Enables deferred materialization mode with the given Resolution.
42
    ///
43
    /// When deferred mode is enabled:
44
    /// - `end()` stores frames instead of validating them
45
    /// - Re-entering a path restores the stored frame with its state intact
46
    /// - `finish_deferred()` performs final validation and materialization
47
    ///
48
    /// This allows deserializers to handle interleaved fields (e.g., TOML dotted
49
    /// keys, flattened structs) where nested fields aren't contiguous in the input.
50
    ///
51
    /// # Use Cases
52
    ///
53
    /// - TOML dotted keys: `inner.x = 1` followed by `count = 2` then `inner.y = 3`
54
    /// - Flattened structs where nested fields appear at the parent level
55
    /// - Any format where field order doesn't match struct nesting
56
    ///
57
    /// # Errors
58
    ///
59
    /// Returns an error if already in deferred mode.
60
    #[inline]
61
    pub fn begin_deferred(&mut self, resolution: Resolution) -> Result<&mut Self, ReflectError> {
431✔
62
        // Cannot enable deferred mode if already in deferred mode
63
        if self.is_deferred() {
431✔
64
            return Err(ReflectError::InvariantViolation {
4✔
65
                invariant: "begin_deferred() called but already in deferred mode",
4✔
66
            });
4✔
67
        }
427✔
68

69
        // Take the stack out of Strict mode and wrap in Deferred mode
70
        let FrameMode::Strict { stack } = core::mem::replace(
427✔
71
            &mut self.mode,
427✔
72
            FrameMode::Strict { stack: Vec::new() }, // temporary placeholder
427✔
73
        ) else {
427✔
74
            unreachable!("just checked we're not in deferred mode");
×
75
        };
76

77
        let start_depth = stack.len();
427✔
78
        self.mode = FrameMode::Deferred {
427✔
79
            stack,
427✔
80
            resolution,
427✔
81
            start_depth,
427✔
82
            current_path: Vec::new(),
427✔
83
            stored_frames: BTreeMap::new(),
427✔
84
        };
427✔
85
        Ok(self)
427✔
86
    }
431✔
87

88
    /// Finishes deferred mode: validates all stored frames and finalizes.
89
    ///
90
    /// This method:
91
    /// 1. Validates that all stored frames are fully initialized
92
    /// 2. Processes frames from deepest to shallowest, updating parent ISets
93
    /// 3. Validates the root frame
94
    ///
95
    /// # Errors
96
    ///
97
    /// Returns an error if any required fields are missing or if the partial is
98
    /// not in deferred mode.
99
    pub fn finish_deferred(&mut self) -> Result<&mut Self, ReflectError> {
341✔
100
        // Check if we're in deferred mode first, before extracting state
101
        if !self.is_deferred() {
341✔
102
            return Err(ReflectError::InvariantViolation {
2✔
103
                invariant: "finish_deferred() called but deferred mode is not enabled",
2✔
104
            });
2✔
105
        }
339✔
106

107
        // Extract deferred state, transitioning back to Strict mode
108
        let FrameMode::Deferred {
109
            stack,
339✔
110
            start_depth,
339✔
111
            mut stored_frames,
339✔
112
            ..
113
        } = core::mem::replace(&mut self.mode, FrameMode::Strict { stack: Vec::new() })
339✔
114
        else {
115
            unreachable!("just checked is_deferred()");
×
116
        };
117

118
        // Restore the stack to self.mode
119
        self.mode = FrameMode::Strict { stack };
339✔
120

121
        // Sort paths by depth (deepest first) so we process children before parents
122
        let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
339✔
123
        paths.sort_by_key(|b| core::cmp::Reverse(b.len()));
1,580✔
124

125
        trace!(
126
            "finish_deferred: Processing {} stored frames in order: {:?}",
127
            paths.len(),
128
            paths
129
        );
130

131
        // Process each stored frame from deepest to shallowest
132
        for path in paths {
1,081✔
133
            let mut frame = stored_frames.remove(&path).unwrap();
746✔
134

135
            trace!(
136
                "finish_deferred: Processing frame at {:?}, shape {}, tracker {:?}",
137
                path,
138
                frame.shape,
139
                frame.tracker.kind()
140
            );
141

142
            // Fill in defaults for unset fields that have defaults
143
            frame.fill_defaults();
746✔
144

145
            // Validate the frame is fully initialized
146
            if let Err(e) = frame.require_full_initialization() {
746✔
147
                // With the ownership transfer model:
148
                // - Parent's iset was cleared when we entered this field
149
                // - Parent won't drop it, so we must deinit it ourselves
150
                frame.deinit();
4✔
151

152
                // Clean up remaining stored frames before returning error.
153
                // All stored frames have their parent's iset cleared, so we must deinit them.
154
                // Note: we must call deinit() even for partially initialized frames, since
155
                // deinit() properly handles partial initialization via the tracker's iset.
156
                for (_, mut remaining_frame) in stored_frames {
7✔
157
                    remaining_frame.deinit();
3✔
158
                }
3✔
159
                return Err(e);
4✔
160
            }
742✔
161

162
            // Update parent's ISet to mark this field as initialized.
163
            // The parent could be:
164
            // 1. On the frames stack (if path.len() == 1, parent is at start_depth - 1)
165
            // 2. On the frames stack (if parent was pushed but never ended)
166
            // 3. In stored_frames (if parent was ended during deferred mode)
167
            if let Some(field_name) = path.last() {
742✔
168
                let parent_path: Vec<_> = path[..path.len() - 1].to_vec();
742✔
169

170
                if parent_path.is_empty() {
742✔
171
                    // Parent is the frame that was current when deferred mode started.
172
                    // It's at index (start_depth - 1) because deferred mode stores frames
173
                    // relative to the position at start_depth.
174
                    let parent_index = start_depth.saturating_sub(1);
485✔
175
                    if let Some(root_frame) = self.frames_mut().get_mut(parent_index) {
485✔
176
                        Self::mark_field_initialized(root_frame, field_name);
485✔
177
                    }
485✔
178
                } else {
179
                    // Try stored_frames first
180
                    if let Some(parent_frame) = stored_frames.get_mut(&parent_path) {
257✔
181
                        Self::mark_field_initialized(parent_frame, field_name);
257✔
182
                    } else {
257✔
183
                        // Parent might still be on the frames stack (never ended).
184
                        // The frame at index (start_depth + parent_path.len() - 1) should be the parent.
185
                        let parent_frame_index = start_depth + parent_path.len() - 1;
×
186
                        if let Some(parent_frame) = self.frames_mut().get_mut(parent_frame_index) {
×
187
                            Self::mark_field_initialized(parent_frame, field_name);
×
188
                        }
×
189
                    }
190
                }
191
            }
×
192

193
            // Frame is validated and parent is updated - frame is no longer needed
194
            // (The actual data is already in place in memory, pointed to by parent)
195
            drop(frame);
742✔
196
        }
197

198
        // Fill defaults and validate the root frame is fully initialized
199
        if let Some(frame) = self.frames_mut().last_mut() {
335✔
200
            frame.fill_defaults();
335✔
201
            frame.require_full_initialization()?;
335✔
202
        }
×
203

204
        Ok(self)
331✔
205
    }
341✔
206

207
    /// Mark a field as initialized in a frame's tracker
208
    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
742✔
209
        if let Some(idx) = Self::find_field_index(frame, field_name) {
742✔
210
            match &mut frame.tracker {
740✔
211
                Tracker::Struct { iset, .. } => {
649✔
212
                    iset.set(idx);
649✔
213
                }
649✔
214
                Tracker::Enum { data, .. } => {
91✔
215
                    data.set(idx);
91✔
216
                }
91✔
217
                Tracker::Array { iset, .. } => {
×
218
                    iset.set(idx);
×
219
                }
×
220
                _ => {}
×
221
            }
222
        }
2✔
223
    }
742✔
224

225
    /// Find the field index for a given field name in a frame
226
    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
742✔
227
        match frame.shape.ty {
742✔
228
            Type::User(UserType::Struct(struct_type)) => {
649✔
229
                struct_type.fields.iter().position(|f| f.name == field_name)
1,367✔
230
            }
231
            Type::User(UserType::Enum(_)) => {
232
                if let Tracker::Enum { variant, .. } = &frame.tracker {
93✔
233
                    variant
93✔
234
                        .data
93✔
235
                        .fields
93✔
236
                        .iter()
93✔
237
                        .position(|f| f.name == field_name)
112✔
238
                } else {
239
                    None
×
240
                }
241
            }
242
            _ => None,
×
243
        }
244
    }
742✔
245

246
    /// Pops the current frame off the stack, indicating we're done initializing the current field
247
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
3,287✔
248
        if let Some(_frame) = self.frames().last() {
3,287✔
249
            crate::trace!(
3,287✔
250
                "end() called: shape={}, tracker={:?}, is_init={}",
3,287✔
251
                _frame.shape,
3,287✔
252
                _frame.tracker.kind(),
3,287✔
253
                _frame.is_init
3,287✔
254
            );
3,287✔
255
        }
3,287✔
256
        self.require_active()?;
3,287✔
257

258
        // Special handling for SmartPointerSlice - convert builder to Arc
259
        if self.frames().len() == 1 {
3,287✔
260
            let frames = self.frames_mut();
18✔
261
            if let Tracker::SmartPointerSlice {
262
                vtable,
13✔
263
                building_item,
13✔
264
            } = &frames[0].tracker
18✔
265
            {
266
                if *building_item {
13✔
267
                    return Err(ReflectError::OperationFailed {
×
268
                        shape: frames[0].shape,
×
269
                        operation: "still building an item, finish it first",
×
270
                    });
×
271
                }
13✔
272

273
                // Convert the builder to Arc<[T]>
274
                let vtable = *vtable;
13✔
275
                let builder_ptr = unsafe { frames[0].data.assume_init() };
13✔
276
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
13✔
277

278
                // Update the frame to store the Arc
279
                frames[0].data = PtrUninit::new(unsafe {
13✔
280
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
13✔
281
                });
13✔
282
                frames[0].tracker = Tracker::Scalar;
13✔
283
                frames[0].is_init = true;
13✔
284
                // The builder memory has been consumed by convert_fn, so we no longer own it
285
                frames[0].ownership = FrameOwnership::ManagedElsewhere;
13✔
286

287
                return Ok(self);
13✔
288
            }
5✔
289
        }
3,269✔
290

291
        if self.frames().len() <= 1 {
3,274✔
292
            // Never pop the last/root frame.
293
            return Err(ReflectError::InvariantViolation {
5✔
294
                invariant: "Partial::end() called with only one frame on the stack",
5✔
295
            });
5✔
296
        }
3,269✔
297

298
        // In deferred mode, cannot pop below the start depth
299
        if let Some(start_depth) = self.start_depth() {
3,269✔
300
            if self.frames().len() <= start_depth {
1,188✔
301
                return Err(ReflectError::InvariantViolation {
×
302
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
303
                });
×
304
            }
1,188✔
305
        }
2,081✔
306

307
        // Require that the top frame is fully initialized before popping.
308
        // Skip this check in deferred mode - validation happens in finish_deferred().
309
        // EXCEPT for collection items (map, list, set, option) which must be fully
310
        // initialized before insertion/completion.
311
        let requires_full_init = if !self.is_deferred() {
3,269✔
312
            true
2,081✔
313
        } else {
314
            // In deferred mode, check if parent is a collection that requires
315
            // fully initialized items (map, list, set, option)
316
            if self.frames().len() >= 2 {
1,188✔
317
                let frame_len = self.frames().len();
1,188✔
318
                let parent_frame = &self.frames()[frame_len - 2];
1,188✔
319
                matches!(
931✔
320
                    parent_frame.tracker,
6✔
321
                    Tracker::Map { .. }
322
                        | Tracker::List { .. }
323
                        | Tracker::Set { .. }
324
                        | Tracker::Option { .. }
325
                        | Tracker::DynamicValue {
326
                            state: DynamicValueState::Array { .. }
327
                        }
328
                )
329
            } else {
330
                false
×
331
            }
332
        };
333

334
        if requires_full_init {
3,269✔
335
            let frame = self.frames().last().unwrap();
2,338✔
336
            crate::trace!(
337
                "end(): Checking full init for {}, tracker={:?}, is_init={}",
338
                frame.shape,
339
                frame.tracker.kind(),
340
                frame.is_init
341
            );
342
            let result = frame.require_full_initialization();
2,338✔
343
            crate::trace!(
344
                "end(): require_full_initialization result: {:?}",
345
                result.is_ok()
346
            );
347
            result?
2,338✔
348
        }
931✔
349

350
        // Pop the frame and save its data pointer for SmartPointer handling
351
        let mut popped_frame = self.frames_mut().pop().unwrap();
3,252✔
352

353
        // In deferred mode, store the frame for potential re-entry and skip
354
        // the normal parent-updating logic. The frame will be finalized later
355
        // in finish_deferred().
356
        //
357
        // We only store if the path depth matches the frame depth, meaning we're
358
        // ending a tracked struct/enum field, not something like begin_some()
359
        // or a field inside a collection item.
360
        if let FrameMode::Deferred {
361
            stack,
1,186✔
362
            start_depth,
1,186✔
363
            current_path,
1,186✔
364
            stored_frames,
1,186✔
365
            ..
366
        } = &mut self.mode
3,252✔
367
        {
368
            // Path depth should match the relative frame depth for a tracked field.
369
            // After popping: frames.len() - start_depth + 1 should equal path.len()
370
            // for fields entered via begin_field (not begin_some/begin_inner).
371
            let relative_depth = stack.len() - *start_depth + 1;
1,186✔
372
            let is_tracked_field = !current_path.is_empty() && current_path.len() == relative_depth;
1,186✔
373

374
            if is_tracked_field {
1,186✔
375
                trace!(
376
                    "end(): Storing frame for deferred path {:?}, shape {}",
377
                    current_path, popped_frame.shape
378
                );
379

380
                // Store the frame at the current path
381
                let path = current_path.clone();
830✔
382
                stored_frames.insert(path, popped_frame);
830✔
383

384
                // Pop from current_path
385
                current_path.pop();
830✔
386

387
                // Clear parent's current_child tracking
388
                if let Some(parent_frame) = stack.last_mut() {
830✔
389
                    parent_frame.tracker.clear_current_child();
830✔
390
                }
830✔
391

392
                return Ok(self);
830✔
393
            }
356✔
394
        }
2,066✔
395

396
        // check if this needs deserialization from a different shape
397
        if popped_frame.using_custom_deserialization {
2,422✔
398
            if let Some(deserialize_with) = self
19✔
399
                .parent_field()
19✔
400
                .and_then(|field| field.vtable.deserialize_with)
19✔
401
            {
402
                let parent_frame = self.frames_mut().last_mut().unwrap();
19✔
403

404
                trace!(
405
                    "Detected custom conversion needed from {} to {}",
406
                    popped_frame.shape, parent_frame.shape
407
                );
408

409
                unsafe {
410
                    let res = {
19✔
411
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
19✔
412
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
19✔
413
                    };
414
                    let popped_frame_shape = popped_frame.shape;
19✔
415

416
                    // we need to do this before any error handling to avoid leaks
417
                    popped_frame.deinit();
19✔
418
                    popped_frame.dealloc();
19✔
419
                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
19✔
420
                        message,
2✔
421
                        src_shape: popped_frame_shape,
2✔
422
                        dst_shape: parent_frame.shape,
2✔
423
                    })?;
2✔
424
                    if rptr.as_uninit() != parent_frame.data {
17✔
425
                        return Err(ReflectError::CustomDeserializationError {
×
426
                            message: "deserialize_with did not return the expected pointer".into(),
×
427
                            src_shape: popped_frame_shape,
×
428
                            dst_shape: parent_frame.shape,
×
429
                        });
×
430
                    }
17✔
431
                    parent_frame.mark_as_init();
17✔
432
                }
433
                return Ok(self);
17✔
434
            }
×
435
        }
2,403✔
436

437
        // Update parent frame's tracking when popping from a child
438
        let parent_frame = self.frames_mut().last_mut().unwrap();
2,403✔
439

440
        crate::trace!(
441
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
442
            popped_frame.shape,
443
            popped_frame.tracker.kind(),
444
            parent_frame.shape,
445
            parent_frame.tracker.kind()
446
        );
447

448
        // Check if we need to do a conversion - this happens when:
449
        // 1. The parent frame has an inner type that matches the popped frame's shape
450
        // 2. The parent frame has try_from
451
        // 3. The parent frame is not yet initialized
452
        // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
453
        //    This ensures we only do conversion when begin_inner was used, not begin_some
454
        let needs_conversion = !parent_frame.is_init
2,403✔
455
            && matches!(parent_frame.tracker, Tracker::Scalar)
1,554✔
456
            && parent_frame.shape.inner.is_some()
43✔
457
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
43✔
458
            && parent_frame.shape.vtable.try_from.is_some();
35✔
459

460
        if needs_conversion {
2,403✔
461
            trace!(
462
                "Detected implicit conversion needed from {} to {}",
463
                popped_frame.shape, parent_frame.shape
464
            );
465

466
            // The conversion requires the source frame to be fully initialized
467
            // (we're about to call assume_init() and pass to try_from)
468
            if let Err(e) = popped_frame.require_full_initialization() {
35✔
469
                // Deallocate the memory since the frame wasn't fully initialized
470
                if let FrameOwnership::Owned = popped_frame.ownership {
×
471
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
472
                        if layout.size() > 0 {
×
473
                            trace!(
474
                                "Deallocating uninitialized conversion frame memory: size={}, align={}",
475
                                layout.size(),
476
                                layout.align()
477
                            );
478
                            unsafe {
×
479
                                ::alloc::alloc::dealloc(
×
480
                                    popped_frame.data.as_mut_byte_ptr(),
×
481
                                    layout,
×
482
                                );
×
483
                            }
×
484
                        }
×
485
                    }
×
486
                }
×
487
                return Err(e);
×
488
            }
35✔
489

490
            // Perform the conversion
491
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
35✔
492
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
35✔
493
                let inner_shape = popped_frame.shape;
35✔
494

495
                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
496
                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
35✔
497

498
                if let Err(e) = result {
35✔
499
                    trace!("Conversion failed: {e:?}");
500

501
                    // Deallocate the inner value's memory since conversion failed
502
                    if let FrameOwnership::Owned = popped_frame.ownership {
2✔
503
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
2✔
504
                            if layout.size() > 0 {
2✔
505
                                trace!(
506
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
507
                                    layout.size(),
508
                                    layout.align()
509
                                );
510
                                unsafe {
2✔
511
                                    ::alloc::alloc::dealloc(
2✔
512
                                        popped_frame.data.as_mut_byte_ptr(),
2✔
513
                                        layout,
2✔
514
                                    );
2✔
515
                                }
2✔
516
                            }
×
517
                        }
×
518
                    }
×
519

520
                    return Err(ReflectError::TryFromError {
2✔
521
                        src_shape: inner_shape,
2✔
522
                        dst_shape: parent_frame.shape,
2✔
523
                        inner: e,
2✔
524
                    });
2✔
525
                }
33✔
526

527
                trace!("Conversion succeeded, marking parent as initialized");
528
                parent_frame.is_init = true;
33✔
529

530
                // Deallocate the inner value's memory since try_from consumed it
531
                if let FrameOwnership::Owned = popped_frame.ownership {
33✔
532
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
33✔
533
                        if layout.size() > 0 {
33✔
534
                            trace!(
535
                                "Deallocating conversion frame memory: size={}, align={}",
536
                                layout.size(),
537
                                layout.align()
538
                            );
539
                            unsafe {
33✔
540
                                ::alloc::alloc::dealloc(
33✔
541
                                    popped_frame.data.as_mut_byte_ptr(),
33✔
542
                                    layout,
33✔
543
                                );
33✔
544
                            }
33✔
545
                        }
×
546
                    }
×
547
                }
×
548

549
                return Ok(self);
33✔
550
            }
×
551
        }
2,368✔
552

553
        // For Field-owned frames, reclaim responsibility in parent's tracker
554
        if let FrameOwnership::Field { field_idx } = popped_frame.ownership {
2,368✔
555
            match &mut parent_frame.tracker {
1,340✔
556
                Tracker::Struct {
557
                    iset,
1,138✔
558
                    current_child,
1,138✔
559
                } => {
1,138✔
560
                    iset.set(field_idx); // Parent reclaims responsibility
1,138✔
561
                    *current_child = None;
1,138✔
562
                }
1,138✔
563
                Tracker::Array {
564
                    iset,
92✔
565
                    current_child,
92✔
566
                } => {
92✔
567
                    iset.set(field_idx); // Parent reclaims responsibility
92✔
568
                    *current_child = None;
92✔
569
                }
92✔
570
                Tracker::Enum {
571
                    data,
110✔
572
                    current_child,
110✔
573
                    ..
574
                } => {
110✔
575
                    data.set(field_idx); // Parent reclaims responsibility
110✔
576
                    *current_child = None;
110✔
577
                }
110✔
NEW
578
                _ => {}
×
579
            }
580
            return Ok(self);
1,340✔
581
        }
1,028✔
582

583
        match &mut parent_frame.tracker {
617✔
584
            Tracker::SmartPointer => {
585
                // We just popped the inner value frame, so now we need to create the smart pointer
586
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
26✔
587
                    // The inner value must be fully initialized before we can create the smart pointer
588
                    if let Err(e) = popped_frame.require_full_initialization() {
26✔
589
                        // Inner value wasn't initialized, deallocate and return error
NEW
590
                        popped_frame.deinit();
×
NEW
591
                        popped_frame.dealloc();
×
NEW
592
                        return Err(e);
×
593
                    }
26✔
594

595
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
26✔
NEW
596
                        popped_frame.deinit();
×
NEW
597
                        popped_frame.dealloc();
×
598
                        return Err(ReflectError::OperationFailed {
×
599
                            shape: parent_frame.shape,
×
600
                            operation: "SmartPointer missing new_into_fn",
×
601
                        });
×
602
                    };
603

604
                    // The child frame contained the inner value
605
                    let inner_ptr = PtrMut::new(unsafe {
26✔
606
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
26✔
607
                    });
608

609
                    // Use new_into_fn to create the Box
610
                    unsafe {
26✔
611
                        new_into_fn(parent_frame.data, inner_ptr);
26✔
612
                    }
26✔
613

614
                    // We just moved out of it
615
                    popped_frame.tracker = Tracker::Scalar;
26✔
616
                    popped_frame.is_init = false;
26✔
617

618
                    // Deallocate the inner value's memory since new_into_fn moved it
619
                    popped_frame.dealloc();
26✔
620

621
                    parent_frame.is_init = true;
26✔
622
                }
×
623
            }
624
            Tracker::List { current_child } if parent_frame.is_init => {
617✔
625
                if *current_child {
617✔
626
                    // We just popped an element frame, now push it to the list
627
                    if let Def::List(list_def) = parent_frame.shape.def {
617✔
628
                        let Some(push_fn) = list_def.vtable.push else {
617✔
629
                            return Err(ReflectError::OperationFailed {
×
630
                                shape: parent_frame.shape,
×
631
                                operation: "List missing push function",
×
632
                            });
×
633
                        };
634

635
                        // The child frame contained the element value
636
                        let element_ptr = PtrMut::new(unsafe {
617✔
637
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
617✔
638
                        });
639

640
                        // Use push to add element to the list
641
                        unsafe {
617✔
642
                            push_fn(
617✔
643
                                PtrMut::new(NonNull::new_unchecked(
617✔
644
                                    parent_frame.data.as_mut_byte_ptr(),
617✔
645
                                )),
617✔
646
                                element_ptr,
617✔
647
                            );
617✔
648
                        }
617✔
649

650
                        // Push moved out of popped_frame
651
                        popped_frame.tracker = Tracker::Scalar;
617✔
652
                        popped_frame.is_init = false;
617✔
653
                        popped_frame.dealloc();
617✔
654

655
                        *current_child = false;
617✔
656
                    }
×
657
                }
×
658
            }
659
            Tracker::Map { insert_state } if parent_frame.is_init => {
181✔
660
                match insert_state {
181✔
661
                    MapInsertState::PushingKey { key_ptr, .. } => {
94✔
662
                        // We just popped the key frame - mark key as initialized and transition
94✔
663
                        // to PushingValue state
94✔
664
                        *insert_state = MapInsertState::PushingValue {
94✔
665
                            key_ptr: *key_ptr,
94✔
666
                            value_ptr: None,
94✔
667
                            value_initialized: false,
94✔
668
                        };
94✔
669
                    }
94✔
670
                    MapInsertState::PushingValue {
671
                        key_ptr, value_ptr, ..
87✔
672
                    } => {
673
                        // We just popped the value frame, now insert the pair
674
                        if let (Some(value_ptr), Def::Map(map_def)) =
87✔
675
                            (value_ptr, parent_frame.shape.def)
87✔
676
                        {
677
                            let insert_fn = map_def.vtable.insert_fn;
87✔
678

679
                            // Use insert to add key-value pair to the map
680
                            unsafe {
87✔
681
                                insert_fn(
87✔
682
                                    PtrMut::new(NonNull::new_unchecked(
87✔
683
                                        parent_frame.data.as_mut_byte_ptr(),
87✔
684
                                    )),
87✔
685
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
87✔
686
                                    PtrMut::new(NonNull::new_unchecked(
87✔
687
                                        value_ptr.as_mut_byte_ptr(),
87✔
688
                                    )),
87✔
689
                                );
87✔
690
                            }
87✔
691

692
                            // Note: We don't deallocate the key and value memory here.
693
                            // The insert function has semantically moved the values into the map,
694
                            // but we still need to deallocate the temporary buffers.
695
                            // However, since we don't have frames for them anymore (they were popped),
696
                            // we need to handle deallocation here.
697
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
87✔
698
                                if key_shape.size() > 0 {
87✔
699
                                    unsafe {
87✔
700
                                        ::alloc::alloc::dealloc(
87✔
701
                                            key_ptr.as_mut_byte_ptr(),
87✔
702
                                            key_shape,
87✔
703
                                        );
87✔
704
                                    }
87✔
705
                                }
×
706
                            }
×
707
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
87✔
708
                                if value_shape.size() > 0 {
87✔
709
                                    unsafe {
87✔
710
                                        ::alloc::alloc::dealloc(
87✔
711
                                            value_ptr.as_mut_byte_ptr(),
87✔
712
                                            value_shape,
87✔
713
                                        );
87✔
714
                                    }
87✔
715
                                }
×
716
                            }
×
717

718
                            // Reset to idle state
719
                            *insert_state = MapInsertState::Idle;
87✔
720
                        }
×
721
                    }
722
                    MapInsertState::Idle => {
×
723
                        // Nothing to do
×
724
                    }
×
725
                }
726
            }
727
            Tracker::Set { current_child } if parent_frame.is_init => {
33✔
728
                if *current_child {
33✔
729
                    // We just popped an element frame, now insert it into the set
730
                    if let Def::Set(set_def) = parent_frame.shape.def {
33✔
731
                        let insert_fn = set_def.vtable.insert_fn;
33✔
732

33✔
733
                        // The child frame contained the element value
33✔
734
                        let element_ptr = PtrMut::new(unsafe {
33✔
735
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
736
                        });
33✔
737

33✔
738
                        // Use insert to add element to the set
33✔
739
                        unsafe {
33✔
740
                            insert_fn(
33✔
741
                                PtrMut::new(NonNull::new_unchecked(
33✔
742
                                    parent_frame.data.as_mut_byte_ptr(),
33✔
743
                                )),
33✔
744
                                element_ptr,
33✔
745
                            );
33✔
746
                        }
33✔
747

33✔
748
                        // Insert moved out of popped_frame
33✔
749
                        popped_frame.tracker = Tracker::Scalar;
33✔
750
                        popped_frame.is_init = false;
33✔
751
                        popped_frame.dealloc();
33✔
752

33✔
753
                        *current_child = false;
33✔
754
                    }
33✔
755
                }
×
756
            }
757
            Tracker::Option { building_inner } => {
112✔
758
                crate::trace!(
759
                    "end(): matched Tracker::Option, building_inner={}",
760
                    *building_inner
761
                );
762
                // We just popped the inner value frame for an Option's Some variant
763
                if *building_inner {
112✔
764
                    if let Def::Option(option_def) = parent_frame.shape.def {
112✔
765
                        // Use the Option vtable to initialize Some(inner_value)
766
                        let init_some_fn = option_def.vtable.init_some_fn;
112✔
767

768
                        // The popped frame contains the inner value
769
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
112✔
770

771
                        // Initialize the Option as Some(inner_value)
772
                        unsafe {
112✔
773
                            init_some_fn(parent_frame.data, inner_value_ptr);
112✔
774
                        }
112✔
775

776
                        // Deallocate the inner value's memory since init_some_fn moved it
777
                        if let FrameOwnership::Owned = popped_frame.ownership {
112✔
778
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
112✔
779
                                if layout.size() > 0 {
112✔
780
                                    unsafe {
112✔
781
                                        ::alloc::alloc::dealloc(
112✔
782
                                            popped_frame.data.as_mut_byte_ptr(),
112✔
783
                                            layout,
112✔
784
                                        );
112✔
785
                                    }
112✔
786
                                }
×
787
                            }
×
788
                        }
×
789

790
                        // Mark that we're no longer building the inner value
791
                        *building_inner = false;
112✔
792
                        crate::trace!("end(): set building_inner to false");
793
                        // Mark the Option as initialized
794
                        parent_frame.is_init = true;
112✔
795
                        crate::trace!("end(): set parent_frame.is_init to true");
796
                    } else {
797
                        return Err(ReflectError::OperationFailed {
×
798
                            shape: parent_frame.shape,
×
799
                            operation: "Option frame without Option definition",
×
800
                        });
×
801
                    }
802
                } else {
803
                    // building_inner is false - the Option was already initialized but
804
                    // begin_some was called again. The popped frame was not used to
805
                    // initialize the Option, so we need to clean it up.
806
                    popped_frame.deinit();
×
807
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
808
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
809
                            if layout.size() > 0 {
×
810
                                unsafe {
×
811
                                    ::alloc::alloc::dealloc(
×
812
                                        popped_frame.data.as_mut_byte_ptr(),
×
813
                                        layout,
×
814
                                    );
×
815
                                }
×
816
                            }
×
817
                        }
×
818
                    }
×
819
                }
820
            }
821
            Tracker::Scalar => {
822
                // the main case here is: the popped frame was a `String` and the
823
                // parent frame is an `Arc<str>`, `Box<str>` etc.
824
                match &parent_frame.shape.def {
8✔
825
                    Def::Pointer(smart_ptr_def) => {
8✔
826
                        let pointee =
8✔
827
                            smart_ptr_def
8✔
828
                                .pointee()
8✔
829
                                .ok_or(ReflectError::InvariantViolation {
8✔
830
                                    invariant: "pointer type doesn't have a pointee",
8✔
831
                                })?;
8✔
832

833
                        if !pointee.is_shape(str::SHAPE) {
8✔
834
                            return Err(ReflectError::InvariantViolation {
×
835
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
836
                            });
×
837
                        }
8✔
838

839
                        if !popped_frame.shape.is_shape(String::SHAPE) {
8✔
840
                            return Err(ReflectError::InvariantViolation {
×
841
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
842
                            });
×
843
                        }
8✔
844

845
                        popped_frame.require_full_initialization()?;
8✔
846

847
                        // if the just-popped frame was a SmartPointerStr, we have some conversion to do:
848
                        // Special-case: SmartPointer<str> (Box<str>, Arc<str>, Rc<str>) via SmartPointerStr tracker
849
                        // Here, popped_frame actually contains a value for String that should be moved into the smart pointer.
850
                        // We convert the String into Box<str>, Arc<str>, or Rc<str> as appropriate and write it to the parent frame.
851
                        use ::alloc::{rc::Rc, string::String, sync::Arc};
852
                        let parent_shape = parent_frame.shape;
8✔
853

854
                        let Some(known) = smart_ptr_def.known else {
8✔
855
                            return Err(ReflectError::OperationFailed {
×
856
                                shape: parent_shape,
×
857
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
858
                            });
×
859
                        };
860

861
                        parent_frame.deinit();
8✔
862

863
                        // Interpret the memory as a String, then convert and write.
864
                        let string_ptr = popped_frame.data.as_mut_byte_ptr() as *mut String;
8✔
865
                        let string_value = unsafe { core::ptr::read(string_ptr) };
8✔
866

867
                        match known {
8✔
868
                            KnownPointer::Box => {
869
                                let boxed: Box<str> = string_value.into_boxed_str();
2✔
870
                                unsafe {
2✔
871
                                    core::ptr::write(
2✔
872
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
2✔
873
                                        boxed,
2✔
874
                                    );
2✔
875
                                }
2✔
876
                            }
877
                            KnownPointer::Arc => {
878
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
2✔
879
                                unsafe {
2✔
880
                                    core::ptr::write(
2✔
881
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
2✔
882
                                        arc,
2✔
883
                                    );
2✔
884
                                }
2✔
885
                            }
886
                            KnownPointer::Rc => {
887
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
4✔
888
                                unsafe {
4✔
889
                                    core::ptr::write(
4✔
890
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
4✔
891
                                        rc,
4✔
892
                                    );
4✔
893
                                }
4✔
894
                            }
895
                            _ => {
896
                                return Err(ReflectError::OperationFailed {
×
897
                                    shape: parent_shape,
×
898
                                    operation: "Don't know how to build this pointer type",
×
899
                                });
×
900
                            }
901
                        }
902

903
                        parent_frame.is_init = true;
8✔
904

905
                        popped_frame.tracker = Tracker::Scalar;
8✔
906
                        popped_frame.is_init = false;
8✔
907
                        popped_frame.dealloc();
8✔
908
                    }
909
                    _ => {
910
                        // This can happen if begin_inner() was called on a type that
911
                        // has shape.inner but isn't a SmartPointer (e.g., Option).
912
                        // In this case, we can't complete the conversion, so return error.
913
                        return Err(ReflectError::OperationFailed {
×
914
                            shape: parent_frame.shape,
×
915
                            operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
×
916
                        });
×
917
                    }
918
                }
919
            }
920
            Tracker::SmartPointerSlice {
921
                vtable,
33✔
922
                building_item,
33✔
923
            } => {
924
                if *building_item {
33✔
925
                    // We just popped an element frame, now push it to the slice builder
926
                    let element_ptr = PtrMut::new(unsafe {
33✔
927
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
928
                    });
929

930
                    // Use the slice builder's push_fn to add the element
931
                    crate::trace!("Pushing element to slice builder");
932
                    unsafe {
33✔
933
                        let parent_ptr = parent_frame.data.assume_init();
33✔
934
                        (vtable.push_fn)(parent_ptr, element_ptr);
33✔
935
                    }
33✔
936

937
                    popped_frame.tracker = Tracker::Scalar;
33✔
938
                    popped_frame.is_init = false;
33✔
939
                    popped_frame.dealloc();
33✔
940

941
                    if let Tracker::SmartPointerSlice {
942
                        building_item: bi, ..
33✔
943
                    } = &mut parent_frame.tracker
33✔
944
                    {
33✔
945
                        *bi = false;
33✔
946
                    }
33✔
947
                }
×
948
            }
949
            Tracker::DynamicValue {
950
                state: DynamicValueState::Array { building_element },
18✔
951
            } => {
952
                if *building_element {
18✔
953
                    // We just popped an element frame, now push it to the dynamic array
954
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
18✔
955
                        // Get mutable pointers - both array and element need PtrMut
18✔
956
                        let array_ptr = unsafe { parent_frame.data.assume_init() };
18✔
957
                        let element_ptr = unsafe { popped_frame.data.assume_init() };
18✔
958

18✔
959
                        // Use push_array_element to add element to the array
18✔
960
                        unsafe {
18✔
961
                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
18✔
962
                        }
18✔
963

18✔
964
                        // Push moved out of popped_frame
18✔
965
                        popped_frame.tracker = Tracker::Scalar;
18✔
966
                        popped_frame.is_init = false;
18✔
967
                        popped_frame.dealloc();
18✔
968

18✔
969
                        *building_element = false;
18✔
970
                    }
18✔
NEW
971
                }
×
972
            }
UNCOV
973
            _ => {}
×
974
        }
975

976
        Ok(self)
1,028✔
977
    }
3,287✔
978

979
    /// Returns a human-readable path representing the current traversal in the builder,
980
    /// e.g., `RootStruct.fieldName[index].subfield`.
981
    pub fn path(&self) -> String {
364✔
982
        let mut out = String::new();
364✔
983

984
        let mut path_components = Vec::new();
364✔
985
        // The stack of enum/struct/sequence names currently in context.
986
        // Start from root and build upwards.
987
        for (i, frame) in self.frames().iter().enumerate() {
718✔
988
            match frame.shape.ty {
718✔
989
                Type::User(user_type) => match user_type {
600✔
990
                    UserType::Struct(struct_type) => {
351✔
991
                        // Try to get currently active field index
992
                        let mut field_str = None;
351✔
993
                        if let Tracker::Struct {
994
                            current_child: Some(idx),
216✔
995
                            ..
996
                        } = &frame.tracker
220✔
997
                        {
998
                            if let Some(field) = struct_type.fields.get(*idx) {
216✔
999
                                field_str = Some(field.name);
216✔
1000
                            }
216✔
1001
                        }
135✔
1002
                        if i == 0 {
351✔
1003
                            // Use Display for the root struct shape
272✔
1004
                            path_components.push(format!("{}", frame.shape));
272✔
1005
                        }
272✔
1006
                        if let Some(field_name) = field_str {
351✔
1007
                            path_components.push(format!(".{field_name}"));
216✔
1008
                        }
216✔
1009
                    }
1010
                    UserType::Enum(_enum_type) => {
15✔
1011
                        // Try to get currently active variant and field
1012
                        if let Tracker::Enum {
1013
                            variant,
4✔
1014
                            current_child,
4✔
1015
                            ..
1016
                        } = &frame.tracker
15✔
1017
                        {
1018
                            if i == 0 {
4✔
1019
                                // Use Display for the root enum shape
4✔
1020
                                path_components.push(format!("{}", frame.shape));
4✔
1021
                            }
4✔
1022
                            path_components.push(format!("::{}", variant.name));
4✔
1023
                            if let Some(idx) = *current_child {
4✔
1024
                                if let Some(field) = variant.data.fields.get(idx) {
4✔
1025
                                    path_components.push(format!(".{}", field.name));
4✔
1026
                                }
4✔
1027
                            }
×
1028
                        } else if i == 0 {
11✔
1029
                            // just the enum display
×
1030
                            path_components.push(format!("{}", frame.shape));
×
1031
                        }
11✔
1032
                    }
1033
                    UserType::Union(_union_type) => {
×
1034
                        path_components.push(format!("{}", frame.shape));
×
1035
                    }
×
1036
                    UserType::Opaque => {
234✔
1037
                        path_components.push("<opaque>".to_string());
234✔
1038
                    }
234✔
1039
                },
1040
                Type::Sequence(seq_type) => match seq_type {
×
1041
                    facet_core::SequenceType::Array(_array_def) => {
×
1042
                        // Try to show current element index
1043
                        if let Tracker::Array {
1044
                            current_child: Some(idx),
×
1045
                            ..
1046
                        } = &frame.tracker
×
1047
                        {
×
1048
                            path_components.push(format!("[{idx}]"));
×
1049
                        }
×
1050
                    }
1051
                    // You can add more for Slice, Vec, etc., if applicable
1052
                    _ => {
×
1053
                        // just indicate "[]" for sequence
×
1054
                        path_components.push("[]".to_string());
×
1055
                    }
×
1056
                },
1057
                Type::Pointer(_) => {
×
1058
                    // Indicate deref
×
1059
                    path_components.push("*".to_string());
×
1060
                }
×
1061
                _ => {
118✔
1062
                    // No structural path
118✔
1063
                }
118✔
1064
            }
1065
        }
1066
        // Merge the path_components into a single string
1067
        for component in path_components {
1,098✔
1068
            out.push_str(&component);
734✔
1069
        }
734✔
1070
        out
364✔
1071
    }
364✔
1072

1073
    /// Get the field for the parent frame
1074
    pub fn parent_field(&self) -> Option<&Field> {
145✔
1075
        self.frames()
145✔
1076
            .iter()
145✔
1077
            .rev()
145✔
1078
            .nth(1)
145✔
1079
            .and_then(|f| f.get_field())
145✔
1080
    }
145✔
1081

1082
    /// Gets the field for the current frame
1083
    pub fn current_field(&self) -> Option<&Field> {
×
1084
        self.frames().last().and_then(|f| f.get_field())
×
1085
    }
×
1086
}
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