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

facet-rs / facet / 19870848606

02 Dec 2025 07:24PM UTC coverage: 58.759% (-0.2%) from 58.959%
19870848606

Pull #991

github

web-flow
Merge 674638beb into e0459e2a8
Pull Request #991: Add Facet implementation for Result<T, E>

145 of 365 new or added lines in 9 files covered. (39.73%)

2 existing lines in 2 files now uncovered.

20467 of 34832 relevant lines covered (58.76%)

539.42 hits per line

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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Misc.
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl<'facet> Partial<'facet> {
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 {
30,989✔
37
        if self.state != PartialState::Active {
30,989✔
38
            panic!(
×
39
                "Partial::shape() called on non-active Partial (state: {:?})",
40
                self.state
41
            );
42
        }
30,989✔
43
        self.frames()
30,989✔
44
            .last()
30,989✔
45
            .expect("Partial::shape() called but no frames exist - this is a bug")
30,989✔
46
            .shape
30,989✔
47
    }
30,989✔
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
            frame.fill_defaults();
750✔
177

178
            // Validate the frame is fully initialized
179
            if let Err(e) = frame.require_full_initialization() {
750✔
180
                // With the ownership transfer model:
181
                // - Parent's iset was cleared when we entered this field
182
                // - Parent won't drop it, so we must deinit it ourselves
183
                frame.deinit();
4✔
184

185
                // Clean up remaining stored frames before returning error.
186
                // All stored frames have their parent's iset cleared, so we must deinit them.
187
                // Note: we must call deinit() even for partially initialized frames, since
188
                // deinit() properly handles partial initialization via the tracker's iset.
189
                for (_, mut remaining_frame) in stored_frames {
4✔
190
                    remaining_frame.deinit();
3✔
191
                }
3✔
192

193
                // No need to poison - returning Err consumes self, Drop will handle cleanup
194
                return Err(e);
4✔
195
            }
746✔
196

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

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

228
            // Frame is validated and parent is updated - frame is no longer needed
229
            // (The actual data is already in place in memory, pointed to by parent)
230
            drop(frame);
746✔
231
        }
232

233
        // Invariant check: we must have at least one frame after finish_deferred
234
        if self.frames().is_empty() {
344✔
235
            // No need to poison - returning Err consumes self, Drop will handle cleanup
236
            return Err(ReflectError::InvariantViolation {
×
237
                invariant: "finish_deferred() left Partial with no frames",
×
238
            });
×
239
        }
344✔
240

241
        // Fill defaults and validate the root frame is fully initialized
242
        if let Some(frame) = self.frames_mut().last_mut() {
344✔
243
            frame.fill_defaults();
344✔
244
            // Root validation failed. At this point, all stored frames have been
245
            // processed and their parent isets updated.
246
            // No need to poison - returning Err consumes self, Drop will handle cleanup
247
            frame.require_full_initialization()?;
344✔
248
        }
×
249

250
        Ok(self)
340✔
251
    }
350✔
252

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

268
            match &mut frame.tracker {
744✔
269
                Tracker::Struct { iset, .. } => {
653✔
270
                    iset.set(idx);
653✔
271
                }
653✔
272
                Tracker::Enum { data, .. } => {
91✔
273
                    data.set(idx);
91✔
274
                }
91✔
275
                Tracker::Array { iset, .. } => {
×
276
                    iset.set(idx);
×
277
                }
×
278
                _ => {}
×
279
            }
280
        }
2✔
281
    }
746✔
282

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

304
    /// Pops the current frame off the stack, indicating we're done initializing the current field
305
    pub fn end(mut self) -> Result<Self, ReflectError> {
18,236✔
306
        if let Some(_frame) = self.frames().last() {
18,236✔
307
            crate::trace!(
18,236✔
308
                "end() called: shape={}, tracker={:?}, is_init={}",
18,236✔
309
                _frame.shape,
18,236✔
310
                _frame.tracker.kind(),
18,236✔
311
                _frame.is_init
18,236✔
312
            );
18,236✔
313
        }
18,236✔
314

315
        // Special handling for SmartPointerSlice - convert builder to Arc
316
        if self.frames().len() == 1 {
18,236✔
317
            let frames = self.frames_mut();
14✔
318
            if let Tracker::SmartPointerSlice {
319
                vtable,
13✔
320
                building_item,
13✔
321
            } = &frames[0].tracker
14✔
322
            {
323
                if *building_item {
13✔
324
                    return Err(ReflectError::OperationFailed {
×
325
                        shape: frames[0].shape,
×
326
                        operation: "still building an item, finish it first",
×
327
                    });
×
328
                }
13✔
329

330
                // Convert the builder to Arc<[T]>
331
                let vtable = *vtable;
13✔
332
                let builder_ptr = unsafe { frames[0].data.assume_init() };
13✔
333
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
13✔
334

335
                // Update the frame to store the Arc
336
                frames[0].data = PtrUninit::new(unsafe {
13✔
337
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
13✔
338
                });
13✔
339
                frames[0].tracker = Tracker::Scalar;
13✔
340
                frames[0].is_init = true;
13✔
341
                // The builder memory has been consumed by convert_fn, so we no longer own it
342
                frames[0].ownership = FrameOwnership::ManagedElsewhere;
13✔
343

344
                return Ok(self);
13✔
345
            }
1✔
346
        }
18,222✔
347

348
        if self.frames().len() <= 1 {
18,223✔
349
            // Never pop the last/root frame - this indicates a broken state machine
350
            // No need to poison - returning Err consumes self, Drop will handle cleanup
351
            return Err(ReflectError::InvariantViolation {
1✔
352
                invariant: "Partial::end() called with only one frame on the stack",
1✔
353
            });
1✔
354
        }
18,222✔
355

356
        // In deferred mode, cannot pop below the start depth
357
        if let Some(start_depth) = self.start_depth() {
18,222✔
358
            if self.frames().len() <= start_depth {
1,221✔
359
                // No need to poison - returning Err consumes self, Drop will handle cleanup
360
                return Err(ReflectError::InvariantViolation {
×
361
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
362
                });
×
363
            }
1,221✔
364
        }
17,001✔
365

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

394
        if requires_full_init {
18,222✔
395
            let frame = self.frames().last().unwrap();
17,261✔
396
            crate::trace!(
397
                "end(): Checking full init for {}, tracker={:?}, is_init={}",
398
                frame.shape,
399
                frame.tracker.kind(),
400
                frame.is_init
401
            );
402
            let result = frame.require_full_initialization();
17,261✔
403
            crate::trace!(
404
                "end(): require_full_initialization result: {:?}",
405
                result.is_ok()
406
            );
407
            result?
17,261✔
408
        }
961✔
409

410
        // Pop the frame and save its data pointer for SmartPointer handling
411
        let mut popped_frame = self.frames_mut().pop().unwrap();
18,217✔
412

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

434
            if is_tracked_field {
1,221✔
435
                trace!(
436
                    "end(): Storing frame for deferred path {:?}, shape {}",
437
                    current_path, popped_frame.shape
438
                );
439

440
                // Store the frame at the current path
441
                let path = current_path.clone();
833✔
442
                stored_frames.insert(path, popped_frame);
833✔
443

444
                // Pop from current_path
445
                current_path.pop();
833✔
446

447
                // Clear parent's current_child tracking
448
                if let Some(parent_frame) = stack.last_mut() {
833✔
449
                    parent_frame.tracker.clear_current_child();
833✔
450
                }
833✔
451

452
                return Ok(self);
833✔
453
            }
388✔
454
        }
16,996✔
455

456
        // check if this needs deserialization from a different shape
457
        if popped_frame.using_custom_deserialization {
17,384✔
458
            if let Some(deserialize_with) = self
20✔
459
                .parent_field()
20✔
460
                .and_then(|field| field.proxy_convert_in_fn())
20✔
461
            {
462
                let parent_frame = self.frames_mut().last_mut().unwrap();
20✔
463

464
                trace!(
465
                    "Detected custom conversion needed from {} to {}",
466
                    popped_frame.shape, parent_frame.shape
467
                );
468

469
                unsafe {
470
                    let res = {
20✔
471
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
20✔
472
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
20✔
473
                    };
474
                    let popped_frame_shape = popped_frame.shape;
20✔
475

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

500
        // Update parent frame's tracking when popping from a child
501
        let parent_frame = self.frames_mut().last_mut().unwrap();
17,364✔
502

503
        crate::trace!(
504
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
505
            popped_frame.shape,
506
            popped_frame.tracker.kind(),
507
            parent_frame.shape,
508
            parent_frame.tracker.kind()
509
        );
510

511
        // Check if we need to do a conversion - this happens when:
512
        // 1. The parent frame has an inner type that matches the popped frame's shape
513
        // 2. The parent frame has try_from
514
        // 3. The parent frame is not yet initialized
515
        // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
516
        //    This ensures we only do conversion when begin_inner was used, not begin_some
517
        let needs_conversion = !parent_frame.is_init
17,364✔
518
            && matches!(parent_frame.tracker, Tracker::Scalar)
2,338✔
519
            && parent_frame.shape.inner.is_some()
71✔
520
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
71✔
521
            && parent_frame.shape.vtable.try_from.is_some();
63✔
522

523
        if needs_conversion {
17,364✔
524
            trace!(
525
                "Detected implicit conversion needed from {} to {}",
526
                popped_frame.shape, parent_frame.shape
527
            );
528

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

553
            // Perform the conversion
554
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
63✔
555
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
63✔
556
                let inner_shape = popped_frame.shape;
63✔
557

558
                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
559
                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
63✔
560

561
                if let Err(e) = result {
63✔
562
                    trace!("Conversion failed: {e:?}");
563

564
                    // Deallocate the inner value's memory since conversion failed
565
                    if let FrameOwnership::Owned = popped_frame.ownership {
2✔
566
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
2✔
567
                            if layout.size() > 0 {
2✔
568
                                trace!(
569
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
570
                                    layout.size(),
571
                                    layout.align()
572
                                );
573
                                unsafe {
2✔
574
                                    ::alloc::alloc::dealloc(
2✔
575
                                        popped_frame.data.as_mut_byte_ptr(),
2✔
576
                                        layout,
2✔
577
                                    );
2✔
578
                                }
2✔
579
                            }
×
580
                        }
×
581
                    }
×
582

583
                    return Err(ReflectError::TryFromError {
2✔
584
                        src_shape: inner_shape,
2✔
585
                        dst_shape: parent_frame.shape,
2✔
586
                        inner: e,
2✔
587
                    });
2✔
588
                }
61✔
589

590
                trace!("Conversion succeeded, marking parent as initialized");
591
                parent_frame.is_init = true;
61✔
592

593
                // Deallocate the inner value's memory since try_from consumed it
594
                if let FrameOwnership::Owned = popped_frame.ownership {
61✔
595
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
61✔
596
                        if layout.size() > 0 {
61✔
597
                            trace!(
598
                                "Deallocating conversion frame memory: size={}, align={}",
599
                                layout.size(),
600
                                layout.align()
601
                            );
602
                            unsafe {
61✔
603
                                ::alloc::alloc::dealloc(
61✔
604
                                    popped_frame.data.as_mut_byte_ptr(),
61✔
605
                                    layout,
61✔
606
                                );
61✔
607
                            }
61✔
608
                        }
×
609
                    }
×
610
                }
×
611

612
                return Ok(self);
61✔
613
            }
×
614
        }
17,301✔
615

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

661
        match &mut parent_frame.tracker {
12,716✔
662
            Tracker::SmartPointer => {
663
                // We just popped the inner value frame, so now we need to create the smart pointer
664
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
27✔
665
                    // The inner value must be fully initialized before we can create the smart pointer
666
                    if let Err(e) = popped_frame.require_full_initialization() {
27✔
667
                        // Inner value wasn't initialized, deallocate and return error
668
                        popped_frame.deinit();
×
669
                        popped_frame.dealloc();
×
670
                        return Err(e);
×
671
                    }
27✔
672

673
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
27✔
674
                        popped_frame.deinit();
×
675
                        popped_frame.dealloc();
×
676
                        return Err(ReflectError::OperationFailed {
×
677
                            shape: parent_frame.shape,
×
678
                            operation: "SmartPointer missing new_into_fn",
×
679
                        });
×
680
                    };
681

682
                    // The child frame contained the inner value
683
                    let inner_ptr = PtrMut::new(unsafe {
27✔
684
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
27✔
685
                    });
686

687
                    // Use new_into_fn to create the Box
688
                    unsafe {
27✔
689
                        new_into_fn(parent_frame.data, inner_ptr);
27✔
690
                    }
27✔
691

692
                    // We just moved out of it
693
                    popped_frame.tracker = Tracker::Scalar;
27✔
694
                    popped_frame.is_init = false;
27✔
695

696
                    // Deallocate the inner value's memory since new_into_fn moved it
697
                    popped_frame.dealloc();
27✔
698

699
                    parent_frame.is_init = true;
27✔
700
                }
×
701
            }
702
            Tracker::List { current_child } if parent_frame.is_init => {
12,716✔
703
                if *current_child {
12,716✔
704
                    // We just popped an element frame, now push it to the list
705
                    if let Def::List(list_def) = parent_frame.shape.def {
12,716✔
706
                        let Some(push_fn) = list_def.vtable.push else {
12,716✔
707
                            return Err(ReflectError::OperationFailed {
×
708
                                shape: parent_frame.shape,
×
709
                                operation: "List missing push function",
×
710
                            });
×
711
                        };
712

713
                        // The child frame contained the element value
714
                        let element_ptr = PtrMut::new(unsafe {
12,716✔
715
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
12,716✔
716
                        });
717

718
                        // Use push to add element to the list
719
                        unsafe {
12,716✔
720
                            push_fn(
12,716✔
721
                                PtrMut::new(NonNull::new_unchecked(
12,716✔
722
                                    parent_frame.data.as_mut_byte_ptr(),
12,716✔
723
                                )),
12,716✔
724
                                element_ptr,
12,716✔
725
                            );
12,716✔
726
                        }
12,716✔
727

728
                        // Push moved out of popped_frame
729
                        popped_frame.tracker = Tracker::Scalar;
12,716✔
730
                        popped_frame.is_init = false;
12,716✔
731
                        popped_frame.dealloc();
12,716✔
732

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

757
                            // Use insert to add key-value pair to the map
758
                            unsafe {
1,107✔
759
                                insert_fn(
1,107✔
760
                                    PtrMut::new(NonNull::new_unchecked(
1,107✔
761
                                        parent_frame.data.as_mut_byte_ptr(),
1,107✔
762
                                    )),
1,107✔
763
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
1,107✔
764
                                    PtrMut::new(NonNull::new_unchecked(
1,107✔
765
                                        value_ptr.as_mut_byte_ptr(),
1,107✔
766
                                    )),
1,107✔
767
                                );
1,107✔
768
                            }
1,107✔
769

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

796
                            // Reset to idle state
797
                            *insert_state = MapInsertState::Idle;
1,107✔
798
                        }
×
799
                    }
800
                    MapInsertState::Idle => {
×
801
                        // Nothing to do
×
802
                    }
×
803
                }
804
            }
805
            Tracker::Set { current_child } if parent_frame.is_init => {
42✔
806
                if *current_child {
42✔
807
                    // We just popped an element frame, now insert it into the set
808
                    if let Def::Set(set_def) = parent_frame.shape.def {
42✔
809
                        let insert_fn = set_def.vtable.insert_fn;
42✔
810

42✔
811
                        // The child frame contained the element value
42✔
812
                        let element_ptr = PtrMut::new(unsafe {
42✔
813
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
42✔
814
                        });
42✔
815

42✔
816
                        // Use insert to add element to the set
42✔
817
                        unsafe {
42✔
818
                            insert_fn(
42✔
819
                                PtrMut::new(NonNull::new_unchecked(
42✔
820
                                    parent_frame.data.as_mut_byte_ptr(),
42✔
821
                                )),
42✔
822
                                element_ptr,
42✔
823
                            );
42✔
824
                        }
42✔
825

42✔
826
                        // Insert moved out of popped_frame
42✔
827
                        popped_frame.tracker = Tracker::Scalar;
42✔
828
                        popped_frame.is_init = false;
42✔
829
                        popped_frame.dealloc();
42✔
830

42✔
831
                        *current_child = false;
42✔
832
                    }
42✔
833
                }
×
834
            }
835
            Tracker::Option { building_inner } => {
146✔
836
                crate::trace!(
837
                    "end(): matched Tracker::Option, building_inner={}",
838
                    *building_inner
839
                );
840
                // We just popped the inner value frame for an Option's Some variant
841
                if *building_inner {
146✔
842
                    if let Def::Option(option_def) = parent_frame.shape.def {
146✔
843
                        // Use the Option vtable to initialize Some(inner_value)
844
                        let init_some_fn = option_def.vtable.init_some_fn;
146✔
845

846
                        // The popped frame contains the inner value
847
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
146✔
848

849
                        // Initialize the Option as Some(inner_value)
850
                        unsafe {
146✔
851
                            init_some_fn(parent_frame.data, inner_value_ptr);
146✔
852
                        }
146✔
853

854
                        // Deallocate the inner value's memory since init_some_fn moved it
855
                        if let FrameOwnership::Owned = popped_frame.ownership {
146✔
856
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
146✔
857
                                if layout.size() > 0 {
146✔
858
                                    unsafe {
146✔
859
                                        ::alloc::alloc::dealloc(
146✔
860
                                            popped_frame.data.as_mut_byte_ptr(),
146✔
861
                                            layout,
146✔
862
                                        );
146✔
863
                                    }
146✔
864
                                }
×
865
                            }
×
866
                        }
×
867

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

914
                        // Initialize the Result as Ok(inner_value) or Err(inner_value)
915
                        if *is_ok {
6✔
916
                            let init_ok_fn = result_def.vtable.init_ok_fn;
3✔
917
                            unsafe {
3✔
918
                                init_ok_fn(parent_frame.data, inner_value_ptr);
3✔
919
                            }
3✔
920
                        } else {
921
                            let init_err_fn = result_def.vtable.init_err_fn;
3✔
922
                            unsafe {
3✔
923
                                init_err_fn(parent_frame.data, inner_value_ptr);
3✔
924
                            }
3✔
925
                        }
926

927
                        // Deallocate the inner value's memory since init_ok/err_fn moved it
928
                        if let FrameOwnership::Owned = popped_frame.ownership {
6✔
929
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
6✔
930
                                if layout.size() > 0 {
6✔
931
                                    unsafe {
6✔
932
                                        ::alloc::alloc::dealloc(
6✔
933
                                            popped_frame.data.as_mut_byte_ptr(),
6✔
934
                                            layout,
6✔
935
                                        );
6✔
936
                                    }
6✔
NEW
937
                                }
×
NEW
938
                            }
×
NEW
939
                        }
×
940

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

984
                        if !pointee.is_shape(str::SHAPE) {
8✔
985
                            return Err(ReflectError::InvariantViolation {
×
986
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
987
                            });
×
988
                        }
8✔
989

990
                        if !popped_frame.shape.is_shape(String::SHAPE) {
8✔
991
                            return Err(ReflectError::InvariantViolation {
×
992
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
993
                            });
×
994
                        }
8✔
995

996
                        popped_frame.require_full_initialization()?;
8✔
997

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

1005
                        let Some(known) = smart_ptr_def.known else {
8✔
1006
                            return Err(ReflectError::OperationFailed {
×
1007
                                shape: parent_shape,
×
1008
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
1009
                            });
×
1010
                        };
1011

1012
                        parent_frame.deinit();
8✔
1013

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

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

1054
                        parent_frame.is_init = true;
8✔
1055

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

1081
                    // Use the slice builder's push_fn to add the element
1082
                    crate::trace!("Pushing element to slice builder");
1083
                    unsafe {
33✔
1084
                        let parent_ptr = parent_frame.data.assume_init();
33✔
1085
                        (vtable.push_fn)(parent_ptr, element_ptr);
33✔
1086
                    }
33✔
1087

1088
                    popped_frame.tracker = Tracker::Scalar;
33✔
1089
                    popped_frame.is_init = false;
33✔
1090
                    popped_frame.dealloc();
33✔
1091

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

1117
                    // We just popped an element frame, now push it to the dynamic array
1118
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
22✔
1119
                        // Get mutable pointers - both array and element need PtrMut
22✔
1120
                        let array_ptr = unsafe { parent_frame.data.assume_init() };
22✔
1121
                        let element_ptr = unsafe { popped_frame.data.assume_init() };
22✔
1122

22✔
1123
                        // Use push_array_element to add element to the array
22✔
1124
                        unsafe {
22✔
1125
                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
22✔
1126
                        }
22✔
1127

22✔
1128
                        // Push moved out of popped_frame
22✔
1129
                        popped_frame.tracker = Tracker::Scalar;
22✔
1130
                        popped_frame.is_init = false;
22✔
1131
                        popped_frame.dealloc();
22✔
1132

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

1154
                    // We just popped a value frame, now insert it into the dynamic object
1155
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
26✔
1156
                        // Get mutable pointers - both object and value need PtrMut
26✔
1157
                        let object_ptr = unsafe { parent_frame.data.assume_init() };
26✔
1158
                        let value_ptr = unsafe { popped_frame.data.assume_init() };
26✔
1159

26✔
1160
                        // Use insert_object_entry to add the key-value pair
26✔
1161
                        unsafe {
26✔
1162
                            (dyn_def.vtable.insert_object_entry)(object_ptr, key, value_ptr);
26✔
1163
                        }
26✔
1164

26✔
1165
                        // Insert moved out of popped_frame
26✔
1166
                        popped_frame.tracker = Tracker::Scalar;
26✔
1167
                        popped_frame.is_init = false;
26✔
1168
                        popped_frame.dealloc();
26✔
1169

26✔
1170
                        // Reset insert state to Idle
26✔
1171
                        *insert_state = DynamicObjectInsertState::Idle;
26✔
1172
                    }
26✔
1173
                }
×
1174
            }
1175
            _ => {}
×
1176
        }
1177

1178
        Ok(self)
15,246✔
1179
    }
18,236✔
1180

1181
    /// Returns a human-readable path representing the current traversal in the builder,
1182
    /// e.g., `RootStruct.fieldName[index].subfield`.
1183
    pub fn path(&self) -> String {
3,153✔
1184
        let mut out = String::new();
3,153✔
1185

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

1275
    /// Get the field for the parent frame
1276
    pub fn parent_field(&self) -> Option<&Field> {
155✔
1277
        self.frames()
155✔
1278
            .iter()
155✔
1279
            .rev()
155✔
1280
            .nth(1)
155✔
1281
            .and_then(|f| f.get_field())
155✔
1282
    }
155✔
1283

1284
    /// Gets the field for the current frame
1285
    pub fn current_field(&self) -> Option<&Field> {
×
1286
        self.frames().last().and_then(|f| f.get_field())
×
1287
    }
×
1288
}
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