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

facet-rs / facet / 19946513925

04 Dec 2025 10:50PM UTC coverage: 58.281% (+0.6%) from 57.702%
19946513925

Pull #1078

github

web-flow
Merge 8a209769f into 35c6fc680
Pull Request #1078: feat(facet-json): streaming JSON deserializer

1253 of 1541 new or added lines in 6 files covered. (81.31%)

905 existing lines in 10 files now uncovered.

23542 of 40394 relevant lines covered (58.28%)

499.2 hits per line

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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Misc.
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
7
    /// Returns true if the Partial is in an active state (not built or poisoned).
8
    ///
9
    /// After `build()` succeeds or after an error causes poisoning, the Partial
10
    /// becomes inactive and most operations will fail.
11
    #[inline]
12
    pub fn is_active(&self) -> bool {
×
13
        self.state == PartialState::Active
×
14
    }
×
15

16
    /// Returns the current frame count (depth of nesting)
17
    ///
18
    /// The initial frame count is 1 — `begin_field` would push a new frame,
19
    /// bringing it to 2, then `end` would bring it back to `1`.
20
    ///
21
    /// This is an implementation detail of `Partial`, kinda, but deserializers
22
    /// might use this for debug assertions, to make sure the state is what
23
    /// they think it is.
24
    #[inline]
25
    pub fn frame_count(&self) -> usize {
4✔
26
        self.frames().len()
4✔
27
    }
4✔
28

29
    /// Returns the shape of the current frame.
30
    ///
31
    /// # Panics
32
    ///
33
    /// Panics if the Partial has been poisoned or built, or if there are no frames
34
    /// (which indicates a bug in the Partial implementation).
35
    #[inline]
36
    pub fn shape(&self) -> &'static Shape {
32,266✔
37
        if self.state != PartialState::Active {
32,266✔
38
            panic!(
×
39
                "Partial::shape() called on non-active Partial (state: {:?})",
40
                self.state
41
            );
42
        }
32,266✔
43
        self.frames()
32,266✔
44
            .last()
32,266✔
45
            .expect("Partial::shape() called but no frames exist - this is a bug")
32,266✔
46
            .shape
32,266✔
47
    }
32,266✔
48

49
    /// Returns the shape of the current frame, or `None` if the Partial is
50
    /// inactive (poisoned or built) or has no frames.
51
    ///
52
    /// This is useful for debugging/logging where you want to inspect the state
53
    /// without risking a panic.
54
    #[inline]
55
    pub fn try_shape(&self) -> Option<&'static Shape> {
×
56
        if self.state != PartialState::Active {
×
57
            return None;
×
58
        }
×
59
        self.frames().last().map(|f| f.shape)
×
60
    }
×
61

62
    /// Returns the current deferred resolution, if in deferred mode.
63
    #[inline]
64
    pub fn deferred_resolution(&self) -> Option<&Resolution> {
3✔
65
        self.resolution()
3✔
66
    }
3✔
67

68
    /// Returns the current path in deferred mode as a slice (for debugging/tracing).
69
    #[inline]
70
    pub fn current_path_slice(&self) -> Option<&[&'static str]> {
×
71
        self.current_path().map(|p| p.as_slice())
×
72
    }
×
73

74
    /// Enables deferred materialization mode with the given Resolution.
75
    ///
76
    /// When deferred mode is enabled:
77
    /// - `end()` stores frames instead of validating them
78
    /// - Re-entering a path restores the stored frame with its state intact
79
    /// - `finish_deferred()` performs final validation and materialization
80
    ///
81
    /// This allows deserializers to handle interleaved fields (e.g., TOML dotted
82
    /// keys, flattened structs) where nested fields aren't contiguous in the input.
83
    ///
84
    /// # Use Cases
85
    ///
86
    /// - TOML dotted keys: `inner.x = 1` followed by `count = 2` then `inner.y = 3`
87
    /// - Flattened structs where nested fields appear at the parent level
88
    /// - Any format where field order doesn't match struct nesting
89
    ///
90
    /// # Errors
91
    ///
92
    /// Returns an error if already in deferred mode.
93
    #[inline]
94
    pub fn begin_deferred(mut self, resolution: Resolution) -> Result<Self, ReflectError> {
432✔
95
        // Cannot enable deferred mode if already in deferred mode
96
        if self.is_deferred() {
432✔
97
            return Err(ReflectError::InvariantViolation {
1✔
98
                invariant: "begin_deferred() called but already in deferred mode",
1✔
99
            });
1✔
100
        }
431✔
101

102
        // Take the stack out of Strict mode and wrap in Deferred mode
103
        let FrameMode::Strict { stack } = core::mem::replace(
431✔
104
            &mut self.mode,
431✔
105
            FrameMode::Strict { stack: Vec::new() }, // temporary placeholder
431✔
106
        ) else {
431✔
107
            unreachable!("just checked we're not in deferred mode");
×
108
        };
109

110
        let start_depth = stack.len();
431✔
111
        self.mode = FrameMode::Deferred {
431✔
112
            stack,
431✔
113
            resolution,
431✔
114
            start_depth,
431✔
115
            current_path: Vec::new(),
431✔
116
            stored_frames: BTreeMap::new(),
431✔
117
        };
431✔
118
        Ok(self)
431✔
119
    }
432✔
120

121
    /// Finishes deferred mode: validates all stored frames and finalizes.
122
    ///
123
    /// This method:
124
    /// 1. Validates that all stored frames are fully initialized
125
    /// 2. Processes frames from deepest to shallowest, updating parent ISets
126
    /// 3. Validates the root frame
127
    ///
128
    /// # Errors
129
    ///
130
    /// Returns an error if any required fields are missing or if the partial is
131
    /// not in deferred mode.
132
    pub fn finish_deferred(mut self) -> Result<Self, ReflectError> {
350✔
133
        // Check if we're in deferred mode first, before extracting state
134
        if !self.is_deferred() {
350✔
135
            return Err(ReflectError::InvariantViolation {
2✔
136
                invariant: "finish_deferred() called but deferred mode is not enabled",
2✔
137
            });
2✔
138
        }
348✔
139

140
        // Extract deferred state, transitioning back to Strict mode
141
        let FrameMode::Deferred {
142
            stack,
348✔
143
            start_depth,
348✔
144
            mut stored_frames,
348✔
145
            ..
146
        } = core::mem::replace(&mut self.mode, FrameMode::Strict { stack: Vec::new() })
348✔
147
        else {
148
            unreachable!("just checked is_deferred()");
×
149
        };
150

151
        // Restore the stack to self.mode
152
        self.mode = FrameMode::Strict { stack };
348✔
153

154
        // Sort paths by depth (deepest first) so we process children before parents
155
        let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
348✔
156
        paths.sort_by_key(|b| core::cmp::Reverse(b.len()));
1,594✔
157

158
        trace!(
159
            "finish_deferred: Processing {} stored frames in order: {:?}",
160
            paths.len(),
161
            paths
162
        );
163

164
        // Process each stored frame from deepest to shallowest
165
        for path in paths {
750✔
166
            let mut frame = stored_frames.remove(&path).unwrap();
750✔
167

168
            trace!(
169
                "finish_deferred: Processing frame at {:?}, shape {}, tracker {:?}",
170
                path,
171
                frame.shape,
172
                frame.tracker.kind()
173
            );
174

175
            // Fill in defaults for unset fields that have defaults
176
            if let Err(e) = frame.fill_defaults() {
750✔
177
                // Couldn't fill defaults (e.g., opaque field with #[facet(default)] but no default impl)
UNCOV
178
                frame.deinit();
×
UNCOV
179
                for (_, mut remaining_frame) in stored_frames {
×
UNCOV
180
                    remaining_frame.deinit();
×
UNCOV
181
                }
×
UNCOV
182
                return Err(e);
×
183
            }
750✔
184

185
            // Validate the frame is fully initialized
186
            if let Err(e) = frame.require_full_initialization() {
750✔
187
                // With the ownership transfer model:
188
                // - Parent's iset was cleared when we entered this field
189
                // - Parent won't drop it, so we must deinit it ourselves
190
                frame.deinit();
4✔
191

192
                // Clean up remaining stored frames before returning error.
193
                // All stored frames have their parent's iset cleared, so we must deinit them.
194
                // Note: we must call deinit() even for partially initialized frames, since
195
                // deinit() properly handles partial initialization via the tracker's iset.
196
                for (_, mut remaining_frame) in stored_frames {
4✔
197
                    remaining_frame.deinit();
3✔
198
                }
3✔
199

200
                // No need to poison - returning Err consumes self, Drop will handle cleanup
201
                return Err(e);
4✔
202
            }
746✔
203

204
            // Update parent's ISet to mark this field as initialized.
205
            // The parent could be:
206
            // 1. On the frames stack (if path.len() == 1, parent is at start_depth - 1)
207
            // 2. On the frames stack (if parent was pushed but never ended)
208
            // 3. In stored_frames (if parent was ended during deferred mode)
209
            if let Some(field_name) = path.last() {
746✔
210
                let parent_path: Vec<_> = path[..path.len() - 1].to_vec();
746✔
211

212
                if parent_path.is_empty() {
746✔
213
                    // Parent is the frame that was current when deferred mode started.
214
                    // It's at index (start_depth - 1) because deferred mode stores frames
215
                    // relative to the position at start_depth.
216
                    let parent_index = start_depth.saturating_sub(1);
486✔
217
                    if let Some(root_frame) = self.frames_mut().get_mut(parent_index) {
486✔
218
                        Self::mark_field_initialized(root_frame, field_name);
486✔
219
                    }
486✔
220
                } else {
221
                    // Try stored_frames first
222
                    if let Some(parent_frame) = stored_frames.get_mut(&parent_path) {
260✔
223
                        Self::mark_field_initialized(parent_frame, field_name);
260✔
224
                    } else {
260✔
225
                        // Parent might still be on the frames stack (never ended).
226
                        // The frame at index (start_depth + parent_path.len() - 1) should be the parent.
UNCOV
227
                        let parent_frame_index = start_depth + parent_path.len() - 1;
×
UNCOV
228
                        if let Some(parent_frame) = self.frames_mut().get_mut(parent_frame_index) {
×
UNCOV
229
                            Self::mark_field_initialized(parent_frame, field_name);
×
UNCOV
230
                        }
×
231
                    }
232
                }
UNCOV
233
            }
×
234

235
            // Frame is validated and parent is updated - frame is no longer needed
236
            // (The actual data is already in place in memory, pointed to by parent)
237
            drop(frame);
746✔
238
        }
239

240
        // Invariant check: we must have at least one frame after finish_deferred
241
        if self.frames().is_empty() {
344✔
242
            // No need to poison - returning Err consumes self, Drop will handle cleanup
UNCOV
243
            return Err(ReflectError::InvariantViolation {
×
UNCOV
244
                invariant: "finish_deferred() left Partial with no frames",
×
UNCOV
245
            });
×
246
        }
344✔
247

248
        // Fill defaults and validate the root frame is fully initialized
249
        if let Some(frame) = self.frames_mut().last_mut() {
344✔
250
            // Fill defaults - this can fail if a field has #[facet(default)] but no default impl
251
            frame.fill_defaults()?;
344✔
252
            // Root validation failed. At this point, all stored frames have been
253
            // processed and their parent isets updated.
254
            // No need to poison - returning Err consumes self, Drop will handle cleanup
255
            frame.require_full_initialization()?;
344✔
UNCOV
256
        }
×
257

258
        Ok(self)
340✔
259
    }
350✔
260

261
    /// Mark a field as initialized in a frame's tracker
262
    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
746✔
263
        if let Some(idx) = Self::find_field_index(frame, field_name) {
746✔
264
            // If the tracker is Scalar but this is a struct type, upgrade to Struct tracker.
265
            // This can happen if the frame was deinit'd (e.g., by a failed set_default)
266
            // which resets the tracker to Scalar.
267
            if matches!(frame.tracker, Tracker::Scalar) {
744✔
UNCOV
268
                if let Type::User(UserType::Struct(struct_type)) = frame.shape.ty {
×
UNCOV
269
                    frame.tracker = Tracker::Struct {
×
UNCOV
270
                        iset: ISet::new(struct_type.fields.len()),
×
UNCOV
271
                        current_child: None,
×
UNCOV
272
                    };
×
UNCOV
273
                }
×
274
            }
744✔
275

276
            match &mut frame.tracker {
744✔
277
                Tracker::Struct { iset, .. } => {
653✔
278
                    iset.set(idx);
653✔
279
                }
653✔
280
                Tracker::Enum { data, .. } => {
91✔
281
                    data.set(idx);
91✔
282
                }
91✔
UNCOV
283
                Tracker::Array { iset, .. } => {
×
UNCOV
284
                    iset.set(idx);
×
UNCOV
285
                }
×
UNCOV
286
                _ => {}
×
287
            }
288
        }
2✔
289
    }
746✔
290

291
    /// Find the field index for a given field name in a frame
292
    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
746✔
293
        match frame.shape.ty {
746✔
294
            Type::User(UserType::Struct(struct_type)) => {
653✔
295
                struct_type.fields.iter().position(|f| f.name == field_name)
1,373✔
296
            }
297
            Type::User(UserType::Enum(_)) => {
298
                if let Tracker::Enum { variant, .. } = &frame.tracker {
93✔
299
                    variant
93✔
300
                        .data
93✔
301
                        .fields
93✔
302
                        .iter()
93✔
303
                        .position(|f| f.name == field_name)
112✔
304
                } else {
UNCOV
305
                    None
×
306
                }
307
            }
UNCOV
308
            _ => None,
×
309
        }
310
    }
746✔
311

312
    /// Pops the current frame off the stack, indicating we're done initializing the current field
313
    pub fn end(mut self) -> Result<Self, ReflectError> {
18,776✔
314
        if let Some(_frame) = self.frames().last() {
18,776✔
315
            crate::trace!(
18,776✔
316
                "end() called: shape={}, tracker={:?}, is_init={}",
18,776✔
317
                _frame.shape,
18,776✔
318
                _frame.tracker.kind(),
18,776✔
319
                _frame.is_init
18,776✔
320
            );
18,776✔
321
        }
18,776✔
322

323
        // Special handling for SmartPointerSlice - convert builder to Arc
324
        if self.frames().len() == 1 {
18,776✔
325
            let frames = self.frames_mut();
14✔
326
            if let Tracker::SmartPointerSlice {
327
                vtable,
13✔
328
                building_item,
13✔
329
            } = &frames[0].tracker
14✔
330
            {
331
                if *building_item {
13✔
UNCOV
332
                    return Err(ReflectError::OperationFailed {
×
UNCOV
333
                        shape: frames[0].shape,
×
UNCOV
334
                        operation: "still building an item, finish it first",
×
UNCOV
335
                    });
×
336
                }
13✔
337

338
                // Convert the builder to Arc<[T]>
339
                let vtable = *vtable;
13✔
340
                let builder_ptr = unsafe { frames[0].data.assume_init() };
13✔
341
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
13✔
342

343
                // Update the frame to store the Arc
344
                frames[0].data = PtrUninit::new(unsafe {
13✔
345
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
13✔
346
                });
13✔
347
                frames[0].tracker = Tracker::Scalar;
13✔
348
                frames[0].is_init = true;
13✔
349
                // The builder memory has been consumed by convert_fn, so we no longer own it
350
                frames[0].ownership = FrameOwnership::ManagedElsewhere;
13✔
351

352
                return Ok(self);
13✔
353
            }
1✔
354
        }
18,762✔
355

356
        if self.frames().len() <= 1 {
18,763✔
357
            // Never pop the last/root frame - this indicates a broken state machine
358
            // No need to poison - returning Err consumes self, Drop will handle cleanup
359
            return Err(ReflectError::InvariantViolation {
1✔
360
                invariant: "Partial::end() called with only one frame on the stack",
1✔
361
            });
1✔
362
        }
18,762✔
363

364
        // In deferred mode, cannot pop below the start depth
365
        if let Some(start_depth) = self.start_depth() {
18,762✔
366
            if self.frames().len() <= start_depth {
1,221✔
367
                // No need to poison - returning Err consumes self, Drop will handle cleanup
UNCOV
368
                return Err(ReflectError::InvariantViolation {
×
UNCOV
369
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
UNCOV
370
                });
×
371
            }
1,221✔
372
        }
17,541✔
373

374
        // Require that the top frame is fully initialized before popping.
375
        // Skip this check in deferred mode - validation happens in finish_deferred().
376
        // EXCEPT for collection items (map, list, set, option) which must be fully
377
        // initialized before insertion/completion.
378
        let requires_full_init = if !self.is_deferred() {
18,762✔
379
            true
17,541✔
380
        } else {
381
            // In deferred mode, check if parent is a collection that requires
382
            // fully initialized items (map, list, set, option)
383
            if self.frames().len() >= 2 {
1,221✔
384
                let frame_len = self.frames().len();
1,221✔
385
                let parent_frame = &self.frames()[frame_len - 2];
1,221✔
386
                matches!(
961✔
387
                    parent_frame.tracker,
35✔
388
                    Tracker::Map { .. }
389
                        | Tracker::List { .. }
390
                        | Tracker::Set { .. }
391
                        | Tracker::Option { .. }
392
                        | Tracker::Result { .. }
393
                        | Tracker::DynamicValue {
394
                            state: DynamicValueState::Array { .. }
395
                        }
396
                )
397
            } else {
UNCOV
398
                false
×
399
            }
400
        };
401

402
        if requires_full_init {
18,762✔
403
            let frame = self.frames().last().unwrap();
17,801✔
404
            crate::trace!(
405
                "end(): Checking full init for {}, tracker={:?}, is_init={}",
406
                frame.shape,
407
                frame.tracker.kind(),
408
                frame.is_init
409
            );
410
            let result = frame.require_full_initialization();
17,801✔
411
            crate::trace!(
412
                "end(): require_full_initialization result: {:?}",
413
                result.is_ok()
414
            );
415
            result?
17,801✔
416
        }
961✔
417

418
        // Pop the frame and save its data pointer for SmartPointer handling
419
        let mut popped_frame = self.frames_mut().pop().unwrap();
18,757✔
420

421
        // In deferred mode, store the frame for potential re-entry and skip
422
        // the normal parent-updating logic. The frame will be finalized later
423
        // in finish_deferred().
424
        //
425
        // We only store if the path depth matches the frame depth, meaning we're
426
        // ending a tracked struct/enum field, not something like begin_some()
427
        // or a field inside a collection item.
428
        if let FrameMode::Deferred {
429
            stack,
1,221✔
430
            start_depth,
1,221✔
431
            current_path,
1,221✔
432
            stored_frames,
1,221✔
433
            ..
434
        } = &mut self.mode
18,757✔
435
        {
436
            // Path depth should match the relative frame depth for a tracked field.
437
            // After popping: frames.len() - start_depth + 1 should equal path.len()
438
            // for fields entered via begin_field (not begin_some/begin_inner).
439
            let relative_depth = stack.len() - *start_depth + 1;
1,221✔
440
            let is_tracked_field = !current_path.is_empty() && current_path.len() == relative_depth;
1,221✔
441

442
            if is_tracked_field {
1,221✔
443
                trace!(
444
                    "end(): Storing frame for deferred path {:?}, shape {}",
445
                    current_path, popped_frame.shape
446
                );
447

448
                // Store the frame at the current path
449
                let path = current_path.clone();
833✔
450
                stored_frames.insert(path, popped_frame);
833✔
451

452
                // Pop from current_path
453
                current_path.pop();
833✔
454

455
                // Clear parent's current_child tracking
456
                if let Some(parent_frame) = stack.last_mut() {
833✔
457
                    parent_frame.tracker.clear_current_child();
833✔
458
                }
833✔
459

460
                return Ok(self);
833✔
461
            }
388✔
462
        }
17,536✔
463

464
        // check if this needs deserialization from a different shape
465
        if popped_frame.using_custom_deserialization {
17,924✔
466
            if let Some(deserialize_with) = self
22✔
467
                .parent_field()
22✔
468
                .and_then(|field| field.proxy_convert_in_fn())
22✔
469
            {
470
                let parent_frame = self.frames_mut().last_mut().unwrap();
22✔
471

472
                trace!(
473
                    "Detected custom conversion needed from {} to {}",
474
                    popped_frame.shape, parent_frame.shape
475
                );
476

477
                unsafe {
478
                    let res = {
22✔
479
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
22✔
480
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
22✔
481
                    };
482
                    let popped_frame_shape = popped_frame.shape;
22✔
483

484
                    // Note: We do NOT call deinit() here because deserialize_with uses
485
                    // ptr::read to take ownership of the source value. Calling deinit()
486
                    // would cause a double-free. We mark is_init as false to satisfy
487
                    // dealloc()'s assertion, then deallocate the memory.
488
                    popped_frame.is_init = false;
22✔
489
                    popped_frame.dealloc();
22✔
490
                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
22✔
491
                        message,
3✔
492
                        src_shape: popped_frame_shape,
3✔
493
                        dst_shape: parent_frame.shape,
3✔
494
                    })?;
3✔
495
                    if rptr.as_uninit() != parent_frame.data {
19✔
UNCOV
496
                        return Err(ReflectError::CustomDeserializationError {
×
497
                            message: "deserialize_with did not return the expected pointer".into(),
×
UNCOV
498
                            src_shape: popped_frame_shape,
×
UNCOV
499
                            dst_shape: parent_frame.shape,
×
UNCOV
500
                        });
×
501
                    }
19✔
502
                    parent_frame.mark_as_init();
19✔
503
                }
504
                return Ok(self);
19✔
UNCOV
505
            }
×
506
        }
17,902✔
507

508
        // Update parent frame's tracking when popping from a child
509
        let parent_frame = self.frames_mut().last_mut().unwrap();
17,902✔
510

511
        crate::trace!(
512
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
513
            popped_frame.shape,
514
            popped_frame.tracker.kind(),
515
            parent_frame.shape,
516
            parent_frame.tracker.kind()
517
        );
518

519
        // Check if we need to do a conversion - this happens when:
520
        // 1. The parent frame has an inner type that matches the popped frame's shape
521
        // 2. The parent frame has try_from
522
        // 3. The parent frame is not yet initialized
523
        // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
524
        //    This ensures we only do conversion when begin_inner was used, not begin_some
525
        let needs_conversion = !parent_frame.is_init
17,902✔
526
            && matches!(parent_frame.tracker, Tracker::Scalar)
2,825✔
527
            && parent_frame.shape.inner.is_some()
73✔
528
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
73✔
529
            && parent_frame.shape.vtable.try_from.is_some();
65✔
530

531
        if needs_conversion {
17,902✔
532
            trace!(
533
                "Detected implicit conversion needed from {} to {}",
534
                popped_frame.shape, parent_frame.shape
535
            );
536

537
            // The conversion requires the source frame to be fully initialized
538
            // (we're about to call assume_init() and pass to try_from)
539
            if let Err(e) = popped_frame.require_full_initialization() {
65✔
540
                // Deallocate the memory since the frame wasn't fully initialized
541
                if let FrameOwnership::Owned = popped_frame.ownership {
×
542
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
543
                        if layout.size() > 0 {
×
544
                            trace!(
545
                                "Deallocating uninitialized conversion frame memory: size={}, align={}",
546
                                layout.size(),
547
                                layout.align()
548
                            );
549
                            unsafe {
×
550
                                ::alloc::alloc::dealloc(
×
UNCOV
551
                                    popped_frame.data.as_mut_byte_ptr(),
×
UNCOV
552
                                    layout,
×
UNCOV
553
                                );
×
UNCOV
554
                            }
×
UNCOV
555
                        }
×
UNCOV
556
                    }
×
UNCOV
557
                }
×
UNCOV
558
                return Err(e);
×
559
            }
65✔
560

561
            // Perform the conversion
562
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
65✔
563
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
65✔
564
                let inner_shape = popped_frame.shape;
65✔
565

566
                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
567
                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
65✔
568

569
                if let Err(e) = result {
65✔
570
                    trace!("Conversion failed: {e:?}");
571

572
                    // Deallocate the inner value's memory since conversion failed
573
                    if let FrameOwnership::Owned = popped_frame.ownership {
2✔
574
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
2✔
575
                            if layout.size() > 0 {
2✔
576
                                trace!(
577
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
578
                                    layout.size(),
579
                                    layout.align()
580
                                );
581
                                unsafe {
2✔
582
                                    ::alloc::alloc::dealloc(
2✔
583
                                        popped_frame.data.as_mut_byte_ptr(),
2✔
584
                                        layout,
2✔
585
                                    );
2✔
586
                                }
2✔
UNCOV
587
                            }
×
UNCOV
588
                        }
×
UNCOV
589
                    }
×
590

591
                    return Err(ReflectError::TryFromError {
2✔
592
                        src_shape: inner_shape,
2✔
593
                        dst_shape: parent_frame.shape,
2✔
594
                        inner: e,
2✔
595
                    });
2✔
596
                }
63✔
597

598
                trace!("Conversion succeeded, marking parent as initialized");
599
                parent_frame.is_init = true;
63✔
600

601
                // Deallocate the inner value's memory since try_from consumed it
602
                if let FrameOwnership::Owned = popped_frame.ownership {
63✔
603
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
63✔
604
                        if layout.size() > 0 {
63✔
605
                            trace!(
606
                                "Deallocating conversion frame memory: size={}, align={}",
607
                                layout.size(),
608
                                layout.align()
609
                            );
610
                            unsafe {
63✔
611
                                ::alloc::alloc::dealloc(
63✔
612
                                    popped_frame.data.as_mut_byte_ptr(),
63✔
613
                                    layout,
63✔
614
                                );
63✔
615
                            }
63✔
UNCOV
616
                        }
×
UNCOV
617
                    }
×
UNCOV
618
                }
×
619

620
                return Ok(self);
63✔
UNCOV
621
            }
×
622
        }
17,837✔
623

624
        // For Field-owned frames, reclaim responsibility in parent's tracker
625
        // Only mark as initialized if the child frame was actually initialized.
626
        // This prevents double-free when begin_inner/begin_some drops a value via
627
        // prepare_for_reinitialization but then fails, leaving the child uninitialized.
628
        //
629
        // We use require_full_initialization() rather than just is_init because:
630
        // - Scalar frames use is_init as the source of truth
631
        // - Struct/Array/Enum frames use their iset/data as the source of truth
632
        //   (is_init may never be set to true for these tracker types)
633
        if let FrameOwnership::Field { field_idx } = popped_frame.ownership {
17,837✔
634
            let child_is_initialized = popped_frame.require_full_initialization().is_ok();
2,444✔
635
            match &mut parent_frame.tracker {
2,444✔
636
                Tracker::Struct {
637
                    iset,
2,120✔
638
                    current_child,
2,120✔
639
                } => {
640
                    if child_is_initialized {
2,120✔
641
                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
2,120✔
642
                    }
2,120✔
643
                    *current_child = None;
2,120✔
644
                }
645
                Tracker::Array {
646
                    iset,
145✔
647
                    current_child,
145✔
648
                } => {
649
                    if child_is_initialized {
145✔
650
                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
145✔
651
                    }
145✔
652
                    *current_child = None;
145✔
653
                }
654
                Tracker::Enum {
655
                    data,
179✔
656
                    current_child,
179✔
657
                    ..
658
                } => {
659
                    if child_is_initialized {
179✔
660
                        data.set(field_idx); // Parent reclaims responsibility only if child was init
179✔
661
                    }
179✔
662
                    *current_child = None;
179✔
663
                }
UNCOV
664
                _ => {}
×
665
            }
666
            return Ok(self);
2,444✔
667
        }
15,393✔
668

669
        match &mut parent_frame.tracker {
12,767✔
670
            Tracker::SmartPointer => {
671
                // We just popped the inner value frame, so now we need to create the smart pointer
672
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
27✔
673
                    // The inner value must be fully initialized before we can create the smart pointer
674
                    if let Err(e) = popped_frame.require_full_initialization() {
27✔
675
                        // Inner value wasn't initialized, deallocate and return error
676
                        popped_frame.deinit();
×
677
                        popped_frame.dealloc();
×
678
                        return Err(e);
×
679
                    }
27✔
680

681
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
27✔
UNCOV
682
                        popped_frame.deinit();
×
UNCOV
683
                        popped_frame.dealloc();
×
UNCOV
684
                        return Err(ReflectError::OperationFailed {
×
UNCOV
685
                            shape: parent_frame.shape,
×
UNCOV
686
                            operation: "SmartPointer missing new_into_fn",
×
UNCOV
687
                        });
×
688
                    };
689

690
                    // The child frame contained the inner value
691
                    let inner_ptr = PtrMut::new(unsafe {
27✔
692
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
27✔
693
                    });
694

695
                    // Use new_into_fn to create the Box
696
                    unsafe {
27✔
697
                        new_into_fn(parent_frame.data, inner_ptr);
27✔
698
                    }
27✔
699

700
                    // We just moved out of it
701
                    popped_frame.tracker = Tracker::Scalar;
27✔
702
                    popped_frame.is_init = false;
27✔
703

704
                    // Deallocate the inner value's memory since new_into_fn moved it
705
                    popped_frame.dealloc();
27✔
706

707
                    parent_frame.is_init = true;
27✔
708
                }
×
709
            }
710
            Tracker::List { current_child } if parent_frame.is_init => {
12,767✔
711
                if *current_child {
12,767✔
712
                    // We just popped an element frame, now push it to the list
713
                    if let Def::List(list_def) = parent_frame.shape.def {
12,767✔
714
                        let Some(push_fn) = list_def.vtable.push else {
12,767✔
UNCOV
715
                            return Err(ReflectError::OperationFailed {
×
UNCOV
716
                                shape: parent_frame.shape,
×
UNCOV
717
                                operation: "List missing push function",
×
UNCOV
718
                            });
×
719
                        };
720

721
                        // The child frame contained the element value
722
                        let element_ptr = PtrMut::new(unsafe {
12,767✔
723
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
12,767✔
724
                        });
725

726
                        // Use push to add element to the list
727
                        unsafe {
12,767✔
728
                            push_fn(
12,767✔
729
                                PtrMut::new(NonNull::new_unchecked(
12,767✔
730
                                    parent_frame.data.as_mut_byte_ptr(),
12,767✔
731
                                )),
12,767✔
732
                                element_ptr,
12,767✔
733
                            );
12,767✔
734
                        }
12,767✔
735

736
                        // Push moved out of popped_frame
737
                        popped_frame.tracker = Tracker::Scalar;
12,767✔
738
                        popped_frame.is_init = false;
12,767✔
739
                        popped_frame.dealloc();
12,767✔
740

741
                        *current_child = false;
12,767✔
UNCOV
742
                    }
×
UNCOV
743
                }
×
744
            }
745
            Tracker::Map { insert_state } if parent_frame.is_init => {
2,220✔
746
                match insert_state {
2,220✔
747
                    MapInsertState::PushingKey { key_ptr, .. } => {
1,113✔
748
                        // We just popped the key frame - mark key as initialized and transition
1,113✔
749
                        // to PushingValue state
1,113✔
750
                        *insert_state = MapInsertState::PushingValue {
1,113✔
751
                            key_ptr: *key_ptr,
1,113✔
752
                            value_ptr: None,
1,113✔
753
                            value_initialized: false,
1,113✔
754
                        };
1,113✔
755
                    }
1,113✔
756
                    MapInsertState::PushingValue {
757
                        key_ptr, value_ptr, ..
1,107✔
758
                    } => {
759
                        // We just popped the value frame, now insert the pair
760
                        if let (Some(value_ptr), Def::Map(map_def)) =
1,107✔
761
                            (value_ptr, parent_frame.shape.def)
1,107✔
762
                        {
763
                            let insert_fn = map_def.vtable.insert_fn;
1,107✔
764

765
                            // Use insert to add key-value pair to the map
766
                            unsafe {
1,107✔
767
                                insert_fn(
1,107✔
768
                                    PtrMut::new(NonNull::new_unchecked(
1,107✔
769
                                        parent_frame.data.as_mut_byte_ptr(),
1,107✔
770
                                    )),
1,107✔
771
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
1,107✔
772
                                    PtrMut::new(NonNull::new_unchecked(
1,107✔
773
                                        value_ptr.as_mut_byte_ptr(),
1,107✔
774
                                    )),
1,107✔
775
                                );
1,107✔
776
                            }
1,107✔
777

778
                            // Note: We don't deallocate the key and value memory here.
779
                            // The insert function has semantically moved the values into the map,
780
                            // but we still need to deallocate the temporary buffers.
781
                            // However, since we don't have frames for them anymore (they were popped),
782
                            // we need to handle deallocation here.
783
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
1,107✔
784
                                if key_shape.size() > 0 {
1,107✔
785
                                    unsafe {
1,107✔
786
                                        ::alloc::alloc::dealloc(
1,107✔
787
                                            key_ptr.as_mut_byte_ptr(),
1,107✔
788
                                            key_shape,
1,107✔
789
                                        );
1,107✔
790
                                    }
1,107✔
UNCOV
791
                                }
×
UNCOV
792
                            }
×
793
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
1,107✔
794
                                if value_shape.size() > 0 {
1,107✔
795
                                    unsafe {
1,107✔
796
                                        ::alloc::alloc::dealloc(
1,107✔
797
                                            value_ptr.as_mut_byte_ptr(),
1,107✔
798
                                            value_shape,
1,107✔
799
                                        );
1,107✔
800
                                    }
1,107✔
801
                                }
×
802
                            }
×
803

804
                            // Reset to idle state
805
                            *insert_state = MapInsertState::Idle;
1,107✔
UNCOV
806
                        }
×
807
                    }
UNCOV
808
                    MapInsertState::Idle => {
×
UNCOV
809
                        // Nothing to do
×
UNCOV
810
                    }
×
811
                }
812
            }
813
            Tracker::Set { current_child } if parent_frame.is_init => {
42✔
814
                if *current_child {
42✔
815
                    // We just popped an element frame, now insert it into the set
816
                    if let Def::Set(set_def) = parent_frame.shape.def {
42✔
817
                        let insert_fn = set_def.vtable.insert_fn;
42✔
818

42✔
819
                        // The child frame contained the element value
42✔
820
                        let element_ptr = PtrMut::new(unsafe {
42✔
821
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
42✔
822
                        });
42✔
823

42✔
824
                        // Use insert to add element to the set
42✔
825
                        unsafe {
42✔
826
                            insert_fn(
42✔
827
                                PtrMut::new(NonNull::new_unchecked(
42✔
828
                                    parent_frame.data.as_mut_byte_ptr(),
42✔
829
                                )),
42✔
830
                                element_ptr,
42✔
831
                            );
42✔
832
                        }
42✔
833

42✔
834
                        // Insert moved out of popped_frame
42✔
835
                        popped_frame.tracker = Tracker::Scalar;
42✔
836
                        popped_frame.is_init = false;
42✔
837
                        popped_frame.dealloc();
42✔
838

42✔
839
                        *current_child = false;
42✔
840
                    }
42✔
UNCOV
841
                }
×
842
            }
843
            Tracker::Option { building_inner } => {
242✔
844
                crate::trace!(
845
                    "end(): matched Tracker::Option, building_inner={}",
846
                    *building_inner
847
                );
848
                // We just popped the inner value frame for an Option's Some variant
849
                if *building_inner {
242✔
850
                    if let Def::Option(option_def) = parent_frame.shape.def {
242✔
851
                        // Use the Option vtable to initialize Some(inner_value)
852
                        let init_some_fn = option_def.vtable.init_some_fn;
242✔
853

854
                        // The popped frame contains the inner value
855
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
242✔
856

857
                        // Initialize the Option as Some(inner_value)
858
                        unsafe {
242✔
859
                            init_some_fn(parent_frame.data, inner_value_ptr);
242✔
860
                        }
242✔
861

862
                        // Deallocate the inner value's memory since init_some_fn moved it
863
                        if let FrameOwnership::Owned = popped_frame.ownership {
242✔
864
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
242✔
865
                                if layout.size() > 0 {
242✔
866
                                    unsafe {
242✔
867
                                        ::alloc::alloc::dealloc(
242✔
868
                                            popped_frame.data.as_mut_byte_ptr(),
242✔
869
                                            layout,
242✔
870
                                        );
242✔
871
                                    }
242✔
UNCOV
872
                                }
×
UNCOV
873
                            }
×
UNCOV
874
                        }
×
875

876
                        // Mark that we're no longer building the inner value
877
                        *building_inner = false;
242✔
878
                        crate::trace!("end(): set building_inner to false");
879
                        // Mark the Option as initialized
880
                        parent_frame.is_init = true;
242✔
881
                        crate::trace!("end(): set parent_frame.is_init to true");
882
                    } else {
UNCOV
883
                        return Err(ReflectError::OperationFailed {
×
884
                            shape: parent_frame.shape,
×
885
                            operation: "Option frame without Option definition",
×
886
                        });
×
887
                    }
888
                } else {
889
                    // building_inner is false - the Option was already initialized but
890
                    // begin_some was called again. The popped frame was not used to
891
                    // initialize the Option, so we need to clean it up.
892
                    popped_frame.deinit();
×
893
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
894
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
895
                            if layout.size() > 0 {
×
896
                                unsafe {
×
UNCOV
897
                                    ::alloc::alloc::dealloc(
×
UNCOV
898
                                        popped_frame.data.as_mut_byte_ptr(),
×
UNCOV
899
                                        layout,
×
UNCOV
900
                                    );
×
UNCOV
901
                                }
×
UNCOV
902
                            }
×
UNCOV
903
                        }
×
UNCOV
904
                    }
×
905
                }
906
            }
907
            Tracker::Result {
908
                is_ok,
6✔
909
                building_inner,
6✔
910
            } => {
911
                crate::trace!(
912
                    "end(): matched Tracker::Result, is_ok={}, building_inner={}",
913
                    *is_ok,
914
                    *building_inner
915
                );
916
                // We just popped the inner value frame for a Result's Ok or Err variant
917
                if *building_inner {
6✔
918
                    if let Def::Result(result_def) = parent_frame.shape.def {
6✔
919
                        // The popped frame contains the inner value
920
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
6✔
921

922
                        // Initialize the Result as Ok(inner_value) or Err(inner_value)
923
                        if *is_ok {
6✔
924
                            let init_ok_fn = result_def.vtable.init_ok_fn;
3✔
925
                            unsafe {
3✔
926
                                init_ok_fn(parent_frame.data, inner_value_ptr);
3✔
927
                            }
3✔
928
                        } else {
929
                            let init_err_fn = result_def.vtable.init_err_fn;
3✔
930
                            unsafe {
3✔
931
                                init_err_fn(parent_frame.data, inner_value_ptr);
3✔
932
                            }
3✔
933
                        }
934

935
                        // Deallocate the inner value's memory since init_ok/err_fn moved it
936
                        if let FrameOwnership::Owned = popped_frame.ownership {
6✔
937
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
6✔
938
                                if layout.size() > 0 {
6✔
939
                                    unsafe {
6✔
940
                                        ::alloc::alloc::dealloc(
6✔
941
                                            popped_frame.data.as_mut_byte_ptr(),
6✔
942
                                            layout,
6✔
943
                                        );
6✔
944
                                    }
6✔
UNCOV
945
                                }
×
UNCOV
946
                            }
×
UNCOV
947
                        }
×
948

949
                        // Mark that we're no longer building the inner value
950
                        *building_inner = false;
6✔
951
                        crate::trace!("end(): set building_inner to false");
952
                        // Mark the Result as initialized
953
                        parent_frame.is_init = true;
6✔
954
                        crate::trace!("end(): set parent_frame.is_init to true");
955
                    } else {
UNCOV
956
                        return Err(ReflectError::OperationFailed {
×
957
                            shape: parent_frame.shape,
×
958
                            operation: "Result frame without Result definition",
×
959
                        });
×
960
                    }
961
                } else {
962
                    // building_inner is false - the Result was already initialized but
963
                    // begin_ok/begin_err was called again. The popped frame was not used to
964
                    // initialize the Result, so we need to clean it up.
965
                    popped_frame.deinit();
×
966
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
967
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
968
                            if layout.size() > 0 {
×
969
                                unsafe {
×
UNCOV
970
                                    ::alloc::alloc::dealloc(
×
UNCOV
971
                                        popped_frame.data.as_mut_byte_ptr(),
×
UNCOV
972
                                        layout,
×
UNCOV
973
                                    );
×
UNCOV
974
                                }
×
UNCOV
975
                            }
×
UNCOV
976
                        }
×
UNCOV
977
                    }
×
978
                }
979
            }
980
            Tracker::Scalar => {
981
                // the main case here is: the popped frame was a `String` and the
982
                // parent frame is an `Arc<str>`, `Box<str>` etc.
983
                match &parent_frame.shape.def {
8✔
984
                    Def::Pointer(smart_ptr_def) => {
8✔
985
                        let pointee =
8✔
986
                            smart_ptr_def
8✔
987
                                .pointee()
8✔
988
                                .ok_or(ReflectError::InvariantViolation {
8✔
989
                                    invariant: "pointer type doesn't have a pointee",
8✔
990
                                })?;
8✔
991

992
                        if !pointee.is_shape(str::SHAPE) {
8✔
993
                            return Err(ReflectError::InvariantViolation {
×
UNCOV
994
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
UNCOV
995
                            });
×
996
                        }
8✔
997

998
                        if !popped_frame.shape.is_shape(String::SHAPE) {
8✔
UNCOV
999
                            return Err(ReflectError::InvariantViolation {
×
UNCOV
1000
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
UNCOV
1001
                            });
×
1002
                        }
8✔
1003

1004
                        popped_frame.require_full_initialization()?;
8✔
1005

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

1013
                        let Some(known) = smart_ptr_def.known else {
8✔
UNCOV
1014
                            return Err(ReflectError::OperationFailed {
×
UNCOV
1015
                                shape: parent_shape,
×
UNCOV
1016
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
UNCOV
1017
                            });
×
1018
                        };
1019

1020
                        parent_frame.deinit();
8✔
1021

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

1026
                        match known {
8✔
1027
                            KnownPointer::Box => {
1028
                                let boxed: Box<str> = string_value.into_boxed_str();
2✔
1029
                                unsafe {
2✔
1030
                                    core::ptr::write(
2✔
1031
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
2✔
1032
                                        boxed,
2✔
1033
                                    );
2✔
1034
                                }
2✔
1035
                            }
1036
                            KnownPointer::Arc => {
1037
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
2✔
1038
                                unsafe {
2✔
1039
                                    core::ptr::write(
2✔
1040
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
2✔
1041
                                        arc,
2✔
1042
                                    );
2✔
1043
                                }
2✔
1044
                            }
1045
                            KnownPointer::Rc => {
1046
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
4✔
1047
                                unsafe {
4✔
1048
                                    core::ptr::write(
4✔
1049
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
4✔
1050
                                        rc,
4✔
1051
                                    );
4✔
1052
                                }
4✔
1053
                            }
1054
                            _ => {
UNCOV
1055
                                return Err(ReflectError::OperationFailed {
×
UNCOV
1056
                                    shape: parent_shape,
×
UNCOV
1057
                                    operation: "Don't know how to build this pointer type",
×
UNCOV
1058
                                });
×
1059
                            }
1060
                        }
1061

1062
                        parent_frame.is_init = true;
8✔
1063

1064
                        popped_frame.tracker = Tracker::Scalar;
8✔
1065
                        popped_frame.is_init = false;
8✔
1066
                        popped_frame.dealloc();
8✔
1067
                    }
1068
                    _ => {
1069
                        // This can happen if begin_inner() was called on a type that
1070
                        // has shape.inner but isn't a SmartPointer (e.g., Option).
1071
                        // In this case, we can't complete the conversion, so return error.
UNCOV
1072
                        return Err(ReflectError::OperationFailed {
×
UNCOV
1073
                            shape: parent_frame.shape,
×
UNCOV
1074
                            operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
×
UNCOV
1075
                        });
×
1076
                    }
1077
                }
1078
            }
1079
            Tracker::SmartPointerSlice {
1080
                vtable,
33✔
1081
                building_item,
33✔
1082
            } => {
1083
                if *building_item {
33✔
1084
                    // We just popped an element frame, now push it to the slice builder
1085
                    let element_ptr = PtrMut::new(unsafe {
33✔
1086
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
1087
                    });
1088

1089
                    // Use the slice builder's push_fn to add the element
1090
                    crate::trace!("Pushing element to slice builder");
1091
                    unsafe {
33✔
1092
                        let parent_ptr = parent_frame.data.assume_init();
33✔
1093
                        (vtable.push_fn)(parent_ptr, element_ptr);
33✔
1094
                    }
33✔
1095

1096
                    popped_frame.tracker = Tracker::Scalar;
33✔
1097
                    popped_frame.is_init = false;
33✔
1098
                    popped_frame.dealloc();
33✔
1099

1100
                    if let Tracker::SmartPointerSlice {
1101
                        building_item: bi, ..
33✔
1102
                    } = &mut parent_frame.tracker
33✔
1103
                    {
33✔
1104
                        *bi = false;
33✔
1105
                    }
33✔
UNCOV
1106
                }
×
1107
            }
1108
            Tracker::DynamicValue {
1109
                state: DynamicValueState::Array { building_element },
22✔
1110
            } => {
1111
                if *building_element {
22✔
1112
                    // Check that the element is initialized before pushing
1113
                    if !popped_frame.is_init {
22✔
1114
                        // Element was never set - clean up and return error
UNCOV
1115
                        let shape = parent_frame.shape;
×
UNCOV
1116
                        popped_frame.dealloc();
×
UNCOV
1117
                        *building_element = false;
×
1118
                        // No need to poison - returning Err consumes self, Drop will handle cleanup
UNCOV
1119
                        return Err(ReflectError::OperationFailed {
×
UNCOV
1120
                            shape,
×
UNCOV
1121
                            operation: "end() called but array element was never initialized",
×
UNCOV
1122
                        });
×
1123
                    }
22✔
1124

1125
                    // We just popped an element frame, now push it to the dynamic array
1126
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
22✔
1127
                        // Get mutable pointers - both array and element need PtrMut
22✔
1128
                        let array_ptr = unsafe { parent_frame.data.assume_init() };
22✔
1129
                        let element_ptr = unsafe { popped_frame.data.assume_init() };
22✔
1130

22✔
1131
                        // Use push_array_element to add element to the array
22✔
1132
                        unsafe {
22✔
1133
                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
22✔
1134
                        }
22✔
1135

22✔
1136
                        // Push moved out of popped_frame
22✔
1137
                        popped_frame.tracker = Tracker::Scalar;
22✔
1138
                        popped_frame.is_init = false;
22✔
1139
                        popped_frame.dealloc();
22✔
1140

22✔
1141
                        *building_element = false;
22✔
1142
                    }
22✔
UNCOV
1143
                }
×
1144
            }
1145
            Tracker::DynamicValue {
1146
                state: DynamicValueState::Object { insert_state },
26✔
1147
            } => {
1148
                if let DynamicObjectInsertState::BuildingValue { key } = insert_state {
26✔
1149
                    // Check that the value is initialized before inserting
1150
                    if !popped_frame.is_init {
26✔
1151
                        // Value was never set - clean up and return error
UNCOV
1152
                        let shape = parent_frame.shape;
×
UNCOV
1153
                        popped_frame.dealloc();
×
UNCOV
1154
                        *insert_state = DynamicObjectInsertState::Idle;
×
1155
                        // No need to poison - returning Err consumes self, Drop will handle cleanup
UNCOV
1156
                        return Err(ReflectError::OperationFailed {
×
UNCOV
1157
                            shape,
×
UNCOV
1158
                            operation: "end() called but object entry value was never initialized",
×
UNCOV
1159
                        });
×
1160
                    }
26✔
1161

1162
                    // We just popped a value frame, now insert it into the dynamic object
1163
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
26✔
1164
                        // Get mutable pointers - both object and value need PtrMut
26✔
1165
                        let object_ptr = unsafe { parent_frame.data.assume_init() };
26✔
1166
                        let value_ptr = unsafe { popped_frame.data.assume_init() };
26✔
1167

26✔
1168
                        // Use insert_object_entry to add the key-value pair
26✔
1169
                        unsafe {
26✔
1170
                            (dyn_def.vtable.insert_object_entry)(object_ptr, key, value_ptr);
26✔
1171
                        }
26✔
1172

26✔
1173
                        // Insert moved out of popped_frame
26✔
1174
                        popped_frame.tracker = Tracker::Scalar;
26✔
1175
                        popped_frame.is_init = false;
26✔
1176
                        popped_frame.dealloc();
26✔
1177

26✔
1178
                        // Reset insert state to Idle
26✔
1179
                        *insert_state = DynamicObjectInsertState::Idle;
26✔
1180
                    }
26✔
UNCOV
1181
                }
×
1182
            }
UNCOV
1183
            _ => {}
×
1184
        }
1185

1186
        Ok(self)
15,393✔
1187
    }
18,776✔
1188

1189
    /// Returns a human-readable path representing the current traversal in the builder,
1190
    /// e.g., `RootStruct.fieldName[index].subfield`.
1191
    pub fn path(&self) -> String {
3,165✔
1192
        let mut out = String::new();
3,165✔
1193

1194
        let mut path_components = Vec::new();
3,165✔
1195
        // The stack of enum/struct/sequence names currently in context.
1196
        // Start from root and build upwards.
1197
        for (i, frame) in self.frames().iter().enumerate() {
6,616✔
1198
            match frame.shape.ty {
6,616✔
1199
                Type::User(user_type) => match user_type {
5,688✔
1200
                    UserType::Struct(struct_type) => {
3,379✔
1201
                        // Try to get currently active field index
1202
                        let mut field_str = None;
3,379✔
1203
                        if let Tracker::Struct {
1204
                            current_child: Some(idx),
2,212✔
1205
                            ..
1206
                        } = &frame.tracker
2,605✔
1207
                        {
1208
                            if let Some(field) = struct_type.fields.get(*idx) {
2,212✔
1209
                                field_str = Some(field.name);
2,212✔
1210
                            }
2,212✔
1211
                        }
1,167✔
1212
                        if i == 0 {
3,379✔
1213
                            // Use Display for the root struct shape
2,773✔
1214
                            path_components.push(format!("{}", frame.shape));
2,773✔
1215
                        }
2,773✔
1216
                        if let Some(field_name) = field_str {
3,379✔
1217
                            path_components.push(format!(".{field_name}"));
2,212✔
1218
                        }
2,212✔
1219
                    }
1220
                    UserType::Enum(_enum_type) => {
500✔
1221
                        // Try to get currently active variant and field
1222
                        if let Tracker::Enum {
1223
                            variant,
295✔
1224
                            current_child,
295✔
1225
                            ..
1226
                        } = &frame.tracker
500✔
1227
                        {
1228
                            if i == 0 {
295✔
1229
                                // Use Display for the root enum shape
100✔
1230
                                path_components.push(format!("{}", frame.shape));
100✔
1231
                            }
195✔
1232
                            path_components.push(format!("::{}", variant.name));
295✔
1233
                            if let Some(idx) = *current_child {
295✔
1234
                                if let Some(field) = variant.data.fields.get(idx) {
187✔
1235
                                    path_components.push(format!(".{}", field.name));
187✔
1236
                                }
187✔
1237
                            }
108✔
1238
                        } else if i == 0 {
205✔
1239
                            // just the enum display
44✔
1240
                            path_components.push(format!("{}", frame.shape));
44✔
1241
                        }
161✔
1242
                    }
UNCOV
1243
                    UserType::Union(_union_type) => {
×
UNCOV
1244
                        path_components.push(format!("{}", frame.shape));
×
UNCOV
1245
                    }
×
1246
                    UserType::Opaque => {
1,809✔
1247
                        path_components.push("<opaque>".to_string());
1,809✔
1248
                    }
1,809✔
1249
                },
1250
                Type::Sequence(seq_type) => match seq_type {
29✔
1251
                    facet_core::SequenceType::Array(_array_def) => {
29✔
1252
                        // Try to show current element index
1253
                        if let Tracker::Array {
1254
                            current_child: Some(idx),
19✔
1255
                            ..
1256
                        } = &frame.tracker
26✔
1257
                        {
19✔
1258
                            path_components.push(format!("[{idx}]"));
19✔
1259
                        }
19✔
1260
                    }
1261
                    // You can add more for Slice, Vec, etc., if applicable
1262
                    _ => {
×
UNCOV
1263
                        // just indicate "[]" for sequence
×
UNCOV
1264
                        path_components.push("[]".to_string());
×
UNCOV
1265
                    }
×
1266
                },
UNCOV
1267
                Type::Pointer(_) => {
×
UNCOV
1268
                    // Indicate deref
×
UNCOV
1269
                    path_components.push("*".to_string());
×
UNCOV
1270
                }
×
1271
                _ => {
899✔
1272
                    // No structural path
899✔
1273
                }
899✔
1274
            }
1275
        }
1276
        // Merge the path_components into a single string
1277
        for component in path_components {
7,439✔
1278
            out.push_str(&component);
7,439✔
1279
        }
7,439✔
1280
        out
3,165✔
1281
    }
3,165✔
1282

1283
    /// Get the field for the parent frame
1284
    pub fn parent_field(&self) -> Option<&Field> {
153✔
1285
        self.frames()
153✔
1286
            .iter()
153✔
1287
            .rev()
153✔
1288
            .nth(1)
153✔
1289
            .and_then(|f| f.get_field())
153✔
1290
    }
153✔
1291

1292
    /// Gets the field for the current frame
UNCOV
1293
    pub fn current_field(&self) -> Option<&Field> {
×
UNCOV
1294
        self.frames().last().and_then(|f| f.get_field())
×
UNCOV
1295
    }
×
1296
}
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