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

facet-rs / facet / 19771986547

28 Nov 2025 07:03PM UTC coverage: 60.235% (-0.7%) from 60.902%
19771986547

Pull #956

github

web-flow
Merge 67a560773 into 628cd558c
Pull Request #956: Add DynamicValue support for deserializing into facet_value::Value

294 of 744 new or added lines in 19 files covered. (39.52%)

285 existing lines in 3 files now uncovered.

16705 of 27733 relevant lines covered (60.24%)

153.12 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

145
            // Validate the frame is fully initialized
146
            if let Err(e) = frame.require_full_initialization() {
746✔
147
                // Clean up the current frame that failed validation.
148
                // We need to check if the parent will drop it.
149
                let parent_will_drop = if path.len() == 1 {
4✔
150
                    let field_name = path.first().unwrap();
3✔
151
                    self.frames()
3✔
152
                        .first()
3✔
153
                        .is_some_and(|parent| Self::is_field_marked_in_parent(parent, field_name))
3✔
154
                } else {
155
                    false
1✔
156
                };
157

158
                let mut frame = frame; // Make mutable for deinit
4✔
159
                if !parent_will_drop {
4✔
160
                    // Always call deinit - it handles partially initialized structs/enums
4✔
161
                    // by checking the tracker's iset and dropping individual fields
4✔
162
                    frame.deinit();
4✔
163
                }
4✔
164

165
                // Clean up remaining stored frames before returning error.
166
                // When finish_deferred fails, the parent's iset was NEVER updated for any stored frame,
167
                // so we must deinit all initialized frames ourselves - the parent won't drop them.
168

169
                // Collect keys to remove (can't drain in no_std)
170
                let remaining_paths: Vec<_> = stored_frames.keys().cloned().collect();
4✔
171
                // Sort by depth (deepest first) for proper cleanup order
172
                let mut sorted_paths = remaining_paths;
4✔
173
                sorted_paths.sort_by_key(|p| core::cmp::Reverse(p.len()));
4✔
174

175
                for remaining_path in sorted_paths {
7✔
176
                    if let Some(mut remaining_frame) = stored_frames.remove(&remaining_path) {
3✔
177
                        // Check if this frame was re-entered (parent already has it marked as init).
178
                        // If so, the parent will drop it - we must NOT deinit (double-free).
179
                        // If not, we must deinit because the parent won't drop it.
180
                        let parent_will_drop = if remaining_path.len() == 1 {
3✔
181
                            // Parent is the root frame
182
                            let field_name = remaining_path.first().unwrap();
3✔
183
                            self.frames().first().is_some_and(|parent| {
3✔
184
                                Self::is_field_marked_in_parent(parent, field_name)
3✔
185
                            })
3✔
186
                        } else {
187
                            // Parent is a stored frame - but stored frames haven't been updated yet,
188
                            // so we need to check against what was already set before deferred mode.
189
                            // For now, conservatively assume parent won't drop nested frames.
190
                            false
×
191
                        };
192

193
                        if !parent_will_drop {
3✔
194
                            // Always call deinit - it handles partially initialized structs/enums
3✔
195
                            // by checking the tracker's iset and dropping individual fields
3✔
196
                            remaining_frame.deinit();
3✔
197
                        }
3✔
198
                    }
×
199
                }
200
                return Err(e);
4✔
201
            }
742✔
202

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

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

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

239
        // Fill defaults and validate the root frame is fully initialized
240
        if let Some(frame) = self.frames_mut().last_mut() {
333✔
241
            frame.fill_defaults();
333✔
242
            frame.require_full_initialization()?;
333✔
243
        }
×
244

245
        Ok(self)
329✔
246
    }
339✔
247

248
    /// Mark a field as initialized in a frame's tracker
249
    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
742✔
250
        if let Some(idx) = Self::find_field_index(frame, field_name) {
742✔
251
            match &mut frame.tracker {
740✔
252
                Tracker::Struct { iset, .. } => {
649✔
253
                    iset.set(idx);
649✔
254
                }
649✔
255
                Tracker::Enum { data, .. } => {
91✔
256
                    data.set(idx);
91✔
257
                }
91✔
258
                Tracker::Array { iset, .. } => {
×
259
                    iset.set(idx);
×
260
                }
×
261
                _ => {}
×
262
            }
263
        }
2✔
264
    }
742✔
265

266
    /// Find the field index for a given field name in a frame
267
    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
762✔
268
        match frame.shape.ty {
762✔
269
            Type::User(UserType::Struct(struct_type)) => {
669✔
270
                struct_type.fields.iter().position(|f| f.name == field_name)
1,395✔
271
            }
272
            Type::User(UserType::Enum(_)) => {
273
                if let Tracker::Enum { variant, .. } = &frame.tracker {
93✔
274
                    variant
93✔
275
                        .data
93✔
276
                        .fields
93✔
277
                        .iter()
93✔
278
                        .position(|f| f.name == field_name)
112✔
279
                } else {
280
                    None
×
281
                }
282
            }
283
            _ => None,
×
284
        }
285
    }
762✔
286

287
    /// Check if a field is marked as initialized in the parent's iset/data tracker
288
    pub(crate) fn is_field_marked_in_parent(parent: &Frame, field_name: &str) -> bool {
16✔
289
        // First find the field index
290
        let idx = match Self::find_field_index(parent, field_name) {
16✔
291
            Some(idx) => idx,
16✔
292
            None => return false,
×
293
        };
294

295
        // Then check if it's marked in the parent's tracker
296
        match &parent.tracker {
16✔
297
            Tracker::Struct { iset, .. } => iset.get(idx),
16✔
298
            Tracker::Enum { data, .. } => data.get(idx),
×
299
            _ => false,
×
300
        }
301
    }
16✔
302

303
    /// Unmark a field from the parent's iset/data tracker
304
    /// Used when cleaning up stored frames to prevent double-free
305
    pub(crate) fn unmark_field_in_parent(parent: &mut Frame, field_name: &str) {
4✔
306
        // First find the field index
307
        let idx = match Self::find_field_index(parent, field_name) {
4✔
308
            Some(idx) => idx,
4✔
309
            None => return,
×
310
        };
311

312
        // Then unmark it in the parent's tracker
313
        match &mut parent.tracker {
4✔
314
            Tracker::Struct { iset, .. } => iset.unset(idx),
4✔
315
            Tracker::Enum { data, .. } => data.unset(idx),
×
316
            _ => {}
×
317
        }
318
    }
4✔
319

320
    /// Pops the current frame off the stack, indicating we're done initializing the current field
321
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
3,274✔
322
        if let Some(_frame) = self.frames().last() {
3,274✔
323
            crate::trace!(
3,274✔
324
                "end() called: shape={}, tracker={:?}, is_init={}",
3,274✔
325
                _frame.shape,
3,274✔
326
                _frame.tracker.kind(),
3,274✔
327
                _frame.is_init
3,274✔
328
            );
3,274✔
329
        }
3,274✔
330
        self.require_active()?;
3,274✔
331

332
        // Special handling for SmartPointerSlice - convert builder to Arc
333
        if self.frames().len() == 1 {
3,274✔
334
            let frames = self.frames_mut();
14✔
335
            if let Tracker::SmartPointerSlice {
336
                vtable,
13✔
337
                building_item,
13✔
338
            } = &frames[0].tracker
14✔
339
            {
340
                if *building_item {
13✔
341
                    return Err(ReflectError::OperationFailed {
×
342
                        shape: frames[0].shape,
×
343
                        operation: "still building an item, finish it first",
×
344
                    });
×
345
                }
13✔
346

347
                // Convert the builder to Arc<[T]>
348
                let vtable = *vtable;
13✔
349
                let builder_ptr = unsafe { frames[0].data.assume_init() };
13✔
350
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
13✔
351

352
                // Update the frame to store the Arc
353
                frames[0].data = PtrUninit::new(unsafe {
13✔
354
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
13✔
355
                });
13✔
356
                frames[0].tracker = Tracker::Scalar;
13✔
357
                frames[0].is_init = true;
13✔
358
                // The builder memory has been consumed by convert_fn, so we no longer own it
359
                frames[0].ownership = FrameOwnership::ManagedElsewhere;
13✔
360

361
                return Ok(self);
13✔
362
            }
1✔
363
        }
3,260✔
364

365
        if self.frames().len() <= 1 {
3,261✔
366
            // Never pop the last/root frame.
367
            return Err(ReflectError::InvariantViolation {
1✔
368
                invariant: "Partial::end() called with only one frame on the stack",
1✔
369
            });
1✔
370
        }
3,260✔
371

372
        // In deferred mode, cannot pop below the start depth
373
        if let Some(start_depth) = self.start_depth() {
3,260✔
374
            if self.frames().len() <= start_depth {
1,182✔
375
                return Err(ReflectError::InvariantViolation {
×
376
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
377
                });
×
378
            }
1,182✔
379
        }
2,078✔
380

381
        // Require that the top frame is fully initialized before popping.
382
        // Skip this check in deferred mode - validation happens in finish_deferred().
383
        // EXCEPT for collection items (map, list, set, option) which must be fully
384
        // initialized before insertion/completion.
385
        let requires_full_init = if !self.is_deferred() {
3,260✔
386
            true
2,078✔
387
        } else {
388
            // In deferred mode, check if parent is a collection that requires
389
            // fully initialized items (map, list, set, option)
390
            if self.frames().len() >= 2 {
1,182✔
391
                let frame_len = self.frames().len();
1,182✔
392
                let parent_frame = &self.frames()[frame_len - 2];
1,182✔
393
                matches!(
931✔
394
                    parent_frame.tracker,
1,182✔
395
                    Tracker::Map { .. }
396
                        | Tracker::List { .. }
397
                        | Tracker::Set { .. }
398
                        | Tracker::Option { .. }
399
                )
400
            } else {
401
                false
×
402
            }
403
        };
404

405
        if requires_full_init {
3,260✔
406
            let frame = self.frames().last().unwrap();
2,329✔
407
            crate::trace!(
408
                "end(): Checking full init for {}, tracker={:?}, is_init={}",
409
                frame.shape,
410
                frame.tracker.kind(),
411
                frame.is_init
412
            );
413
            let result = frame.require_full_initialization();
2,329✔
414
            crate::trace!(
415
                "end(): require_full_initialization result: {:?}",
416
                result.is_ok()
417
            );
418
            result?
2,329✔
419
        }
931✔
420

421
        // Pop the frame and save its data pointer for SmartPointer handling
422
        let mut popped_frame = self.frames_mut().pop().unwrap();
3,245✔
423

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

445
            if is_tracked_field {
1,182✔
446
                trace!(
447
                    "end(): Storing frame for deferred path {:?}, shape {}",
448
                    current_path, popped_frame.shape
449
                );
450

451
                // Store the frame at the current path
452
                let path = current_path.clone();
830✔
453
                stored_frames.insert(path, popped_frame);
830✔
454

455
                // Pop from current_path
456
                current_path.pop();
830✔
457

458
                // Clear parent's current_child tracking
459
                if let Some(parent_frame) = stack.last_mut() {
830✔
460
                    parent_frame.tracker.clear_current_child();
830✔
461
                }
830✔
462

463
                return Ok(self);
830✔
464
            }
352✔
465
        }
2,063✔
466

467
        // check if this needs deserialization from a different shape
468
        if popped_frame.using_custom_deserialization {
2,415✔
469
            if let Some(deserialize_with) = self
19✔
470
                .parent_field()
19✔
471
                .and_then(|field| field.vtable.deserialize_with)
19✔
472
            {
473
                let parent_frame = self.frames_mut().last_mut().unwrap();
19✔
474

475
                trace!(
476
                    "Detected custom conversion needed from {} to {}",
477
                    popped_frame.shape, parent_frame.shape
478
                );
479

480
                unsafe {
481
                    let res = {
19✔
482
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
19✔
483
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
19✔
484
                    };
485
                    let popped_frame_shape = popped_frame.shape;
19✔
486

487
                    // we need to do this before any error handling to avoid leaks
488
                    popped_frame.deinit();
19✔
489
                    popped_frame.dealloc();
19✔
490
                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
19✔
491
                        message,
2✔
492
                        src_shape: popped_frame_shape,
2✔
493
                        dst_shape: parent_frame.shape,
2✔
494
                    })?;
2✔
495
                    if rptr.as_uninit() != parent_frame.data {
17✔
496
                        return Err(ReflectError::CustomDeserializationError {
×
497
                            message: "deserialize_with did not return the expected pointer".into(),
×
498
                            src_shape: popped_frame_shape,
×
499
                            dst_shape: parent_frame.shape,
×
500
                        });
×
501
                    }
17✔
502
                    parent_frame.mark_as_init();
17✔
503
                }
504
                return Ok(self);
17✔
505
            }
×
506
        }
2,396✔
507

508
        // Update parent frame's tracking when popping from a child
509
        let parent_frame = self.frames_mut().last_mut().unwrap();
2,396✔
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
2,396✔
526
            && matches!(parent_frame.tracker, Tracker::Scalar)
2,374✔
527
            && parent_frame.shape.inner.is_some()
42✔
528
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
42✔
529
            && parent_frame.shape.vtable.try_from.is_some();
35✔
530

531
        if needs_conversion {
2,396✔
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() {
35✔
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(
×
551
                                    popped_frame.data.as_mut_byte_ptr(),
×
552
                                    layout,
×
553
                                );
×
554
                            }
×
555
                        }
×
556
                    }
×
557
                }
×
558
                return Err(e);
×
559
            }
35✔
560

561
            // Perform the conversion
562
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
35✔
563
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
35✔
564
                let inner_shape = popped_frame.shape;
35✔
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) };
35✔
568

569
                if let Err(e) = result {
35✔
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✔
587
                            }
×
588
                        }
×
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
                }
33✔
597

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

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

620
                return Ok(self);
33✔
621
            }
×
622
        }
2,361✔
623

624
        match &mut parent_frame.tracker {
13✔
625
            Tracker::Struct {
626
                iset,
1,137✔
627
                current_child,
1,137✔
628
            } => {
629
                if let Some(idx) = *current_child {
1,137✔
630
                    iset.set(idx);
1,137✔
631
                    *current_child = None;
1,137✔
632
                }
1,137✔
633
            }
634
            Tracker::Array {
635
                iset,
92✔
636
                current_child,
92✔
637
            } => {
638
                if let Some(idx) = *current_child {
92✔
639
                    iset.set(idx);
92✔
640
                    *current_child = None;
92✔
641
                }
92✔
642
            }
643
            Tracker::SmartPointer { is_initialized } => {
26✔
644
                // We just popped the inner value frame, so now we need to create the smart pointer
645
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
26✔
646
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
26✔
647
                        return Err(ReflectError::OperationFailed {
×
648
                            shape: parent_frame.shape,
×
649
                            operation: "SmartPointer missing new_into_fn",
×
650
                        });
×
651
                    };
652

653
                    // The child frame contained the inner value
654
                    let inner_ptr = PtrMut::new(unsafe {
26✔
655
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
26✔
656
                    });
657

658
                    // Use new_into_fn to create the Box
659
                    unsafe {
26✔
660
                        new_into_fn(parent_frame.data, inner_ptr);
26✔
661
                    }
26✔
662

663
                    // We just moved out of it
664
                    popped_frame.tracker = Tracker::Scalar;
26✔
665
                    popped_frame.is_init = false;
26✔
666

667
                    // Deallocate the inner value's memory since new_into_fn moved it
668
                    popped_frame.dealloc();
26✔
669

670
                    *is_initialized = true;
26✔
671
                }
×
672
            }
673
            Tracker::Enum {
674
                data,
110✔
675
                current_child,
110✔
676
                ..
677
            } => {
678
                if let Some(idx) = *current_child {
110✔
679
                    data.set(idx);
110✔
680
                    *current_child = None;
110✔
681
                }
110✔
682
            }
683
            Tracker::List {
684
                is_initialized: true,
685
                current_child,
617✔
686
            } => {
687
                if *current_child {
617✔
688
                    // We just popped an element frame, now push it to the list
689
                    if let Def::List(list_def) = parent_frame.shape.def {
617✔
690
                        let Some(push_fn) = list_def.vtable.push else {
617✔
691
                            return Err(ReflectError::OperationFailed {
×
692
                                shape: parent_frame.shape,
×
693
                                operation: "List missing push function",
×
694
                            });
×
695
                        };
696

697
                        // The child frame contained the element value
698
                        let element_ptr = PtrMut::new(unsafe {
617✔
699
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
617✔
700
                        });
701

702
                        // Use push to add element to the list
703
                        unsafe {
617✔
704
                            push_fn(
617✔
705
                                PtrMut::new(NonNull::new_unchecked(
617✔
706
                                    parent_frame.data.as_mut_byte_ptr(),
617✔
707
                                )),
617✔
708
                                element_ptr,
617✔
709
                            );
617✔
710
                        }
617✔
711

712
                        // Push moved out of popped_frame
713
                        popped_frame.tracker = Tracker::Scalar;
617✔
714
                        popped_frame.is_init = false;
617✔
715
                        popped_frame.dealloc();
617✔
716

717
                        *current_child = false;
617✔
718
                    }
×
719
                }
×
720
            }
721
            Tracker::Map {
722
                is_initialized: true,
723
                insert_state,
180✔
724
            } => {
725
                match insert_state {
180✔
726
                    MapInsertState::PushingKey { key_ptr, .. } => {
93✔
727
                        // We just popped the key frame - mark key as initialized and transition
93✔
728
                        // to PushingValue state
93✔
729
                        *insert_state = MapInsertState::PushingValue {
93✔
730
                            key_ptr: *key_ptr,
93✔
731
                            value_ptr: None,
93✔
732
                            value_initialized: false,
93✔
733
                        };
93✔
734
                    }
93✔
735
                    MapInsertState::PushingValue {
736
                        key_ptr, value_ptr, ..
87✔
737
                    } => {
738
                        // We just popped the value frame, now insert the pair
739
                        if let (Some(value_ptr), Def::Map(map_def)) =
87✔
740
                            (value_ptr, parent_frame.shape.def)
87✔
741
                        {
742
                            let insert_fn = map_def.vtable.insert_fn;
87✔
743

744
                            // Use insert to add key-value pair to the map
745
                            unsafe {
87✔
746
                                insert_fn(
87✔
747
                                    PtrMut::new(NonNull::new_unchecked(
87✔
748
                                        parent_frame.data.as_mut_byte_ptr(),
87✔
749
                                    )),
87✔
750
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
87✔
751
                                    PtrMut::new(NonNull::new_unchecked(
87✔
752
                                        value_ptr.as_mut_byte_ptr(),
87✔
753
                                    )),
87✔
754
                                );
87✔
755
                            }
87✔
756

757
                            // Note: We don't deallocate the key and value memory here.
758
                            // The insert function has semantically moved the values into the map,
759
                            // but we still need to deallocate the temporary buffers.
760
                            // However, since we don't have frames for them anymore (they were popped),
761
                            // we need to handle deallocation here.
762
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
87✔
763
                                if key_shape.size() > 0 {
87✔
764
                                    unsafe {
87✔
765
                                        ::alloc::alloc::dealloc(
87✔
766
                                            key_ptr.as_mut_byte_ptr(),
87✔
767
                                            key_shape,
87✔
768
                                        );
87✔
769
                                    }
87✔
770
                                }
×
771
                            }
×
772
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
87✔
773
                                if value_shape.size() > 0 {
87✔
774
                                    unsafe {
87✔
775
                                        ::alloc::alloc::dealloc(
87✔
776
                                            value_ptr.as_mut_byte_ptr(),
87✔
777
                                            value_shape,
87✔
778
                                        );
87✔
779
                                    }
87✔
780
                                }
×
781
                            }
×
782

783
                            // Reset to idle state
784
                            *insert_state = MapInsertState::Idle;
87✔
785
                        }
×
786
                    }
787
                    MapInsertState::Idle => {
×
788
                        // Nothing to do
×
789
                    }
×
790
                }
791
            }
792
            Tracker::Set {
793
                is_initialized: true,
794
                current_child,
33✔
795
            } => {
796
                if *current_child {
33✔
797
                    // We just popped an element frame, now insert it into the set
798
                    if let Def::Set(set_def) = parent_frame.shape.def {
33✔
799
                        let insert_fn = set_def.vtable.insert_fn;
33✔
800

33✔
801
                        // The child frame contained the element value
33✔
802
                        let element_ptr = PtrMut::new(unsafe {
33✔
803
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
804
                        });
33✔
805

33✔
806
                        // Use insert to add element to the set
33✔
807
                        unsafe {
33✔
808
                            insert_fn(
33✔
809
                                PtrMut::new(NonNull::new_unchecked(
33✔
810
                                    parent_frame.data.as_mut_byte_ptr(),
33✔
811
                                )),
33✔
812
                                element_ptr,
33✔
813
                            );
33✔
814
                        }
33✔
815

33✔
816
                        // Insert moved out of popped_frame
33✔
817
                        popped_frame.tracker = Tracker::Scalar;
33✔
818
                        popped_frame.is_init = false;
33✔
819
                        popped_frame.dealloc();
33✔
820

33✔
821
                        *current_child = false;
33✔
822
                    }
33✔
823
                }
×
824
            }
825
            Tracker::Option { building_inner } => {
112✔
826
                crate::trace!(
827
                    "end(): matched Tracker::Option, building_inner={}",
828
                    *building_inner
829
                );
830
                // We just popped the inner value frame for an Option's Some variant
831
                if *building_inner {
112✔
832
                    if let Def::Option(option_def) = parent_frame.shape.def {
112✔
833
                        // Use the Option vtable to initialize Some(inner_value)
834
                        let init_some_fn = option_def.vtable.init_some_fn;
112✔
835

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

839
                        // Initialize the Option as Some(inner_value)
840
                        unsafe {
112✔
841
                            init_some_fn(parent_frame.data, inner_value_ptr);
112✔
842
                        }
112✔
843

844
                        // Deallocate the inner value's memory since init_some_fn moved it
845
                        if let FrameOwnership::Owned = popped_frame.ownership {
112✔
846
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
112✔
847
                                if layout.size() > 0 {
112✔
848
                                    unsafe {
112✔
849
                                        ::alloc::alloc::dealloc(
112✔
850
                                            popped_frame.data.as_mut_byte_ptr(),
112✔
851
                                            layout,
112✔
852
                                        );
112✔
853
                                    }
112✔
854
                                }
×
855
                            }
×
856
                        }
×
857

858
                        // Mark that we're no longer building the inner value
859
                        *building_inner = false;
112✔
860
                        crate::trace!("end(): set building_inner to false");
861
                        // Mark the Option as initialized
862
                        parent_frame.is_init = true;
112✔
863
                        crate::trace!("end(): set parent_frame.is_init to true");
864
                    } else {
865
                        return Err(ReflectError::OperationFailed {
×
866
                            shape: parent_frame.shape,
×
867
                            operation: "Option frame without Option definition",
×
868
                        });
×
869
                    }
870
                } else {
871
                    // building_inner is false - the Option was already initialized but
872
                    // begin_some was called again. The popped frame was not used to
873
                    // initialize the Option, so we need to clean it up.
874
                    popped_frame.deinit();
×
875
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
876
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
877
                            if layout.size() > 0 {
×
878
                                unsafe {
×
879
                                    ::alloc::alloc::dealloc(
×
880
                                        popped_frame.data.as_mut_byte_ptr(),
×
881
                                        layout,
×
882
                                    );
×
883
                                }
×
884
                            }
×
885
                        }
×
886
                    }
×
887
                }
888
            }
889
            Tracker::Scalar => {
890
                // the main case here is: the popped frame was a `String` and the
891
                // parent frame is an `Arc<str>`, `Box<str>` etc.
892
                match &parent_frame.shape.def {
8✔
893
                    Def::Pointer(smart_ptr_def) => {
8✔
894
                        let pointee =
8✔
895
                            smart_ptr_def
8✔
896
                                .pointee()
8✔
897
                                .ok_or(ReflectError::InvariantViolation {
8✔
898
                                    invariant: "pointer type doesn't have a pointee",
8✔
899
                                })?;
8✔
900

901
                        if !pointee.is_shape(str::SHAPE) {
8✔
902
                            return Err(ReflectError::InvariantViolation {
×
903
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
904
                            });
×
905
                        }
8✔
906

907
                        if !popped_frame.shape.is_shape(String::SHAPE) {
8✔
908
                            return Err(ReflectError::InvariantViolation {
×
909
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
910
                            });
×
911
                        }
8✔
912

913
                        popped_frame.require_full_initialization()?;
8✔
914

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

922
                        let Some(known) = smart_ptr_def.known else {
8✔
923
                            return Err(ReflectError::OperationFailed {
×
924
                                shape: parent_shape,
×
925
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
926
                            });
×
927
                        };
928

929
                        parent_frame.deinit();
8✔
930

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

935
                        match known {
8✔
936
                            KnownPointer::Box => {
937
                                let boxed: Box<str> = string_value.into_boxed_str();
2✔
938
                                unsafe {
2✔
939
                                    core::ptr::write(
2✔
940
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
2✔
941
                                        boxed,
2✔
942
                                    );
2✔
943
                                }
2✔
944
                            }
945
                            KnownPointer::Arc => {
946
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
2✔
947
                                unsafe {
2✔
948
                                    core::ptr::write(
2✔
949
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
2✔
950
                                        arc,
2✔
951
                                    );
2✔
952
                                }
2✔
953
                            }
954
                            KnownPointer::Rc => {
955
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
4✔
956
                                unsafe {
4✔
957
                                    core::ptr::write(
4✔
958
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
4✔
959
                                        rc,
4✔
960
                                    );
4✔
961
                                }
4✔
962
                            }
963
                            _ => {
964
                                return Err(ReflectError::OperationFailed {
×
965
                                    shape: parent_shape,
×
966
                                    operation: "Don't know how to build this pointer type",
×
967
                                });
×
968
                            }
969
                        }
970

971
                        parent_frame.is_init = true;
8✔
972

973
                        popped_frame.tracker = Tracker::Scalar;
8✔
974
                        popped_frame.is_init = false;
8✔
975
                        popped_frame.dealloc();
8✔
976
                    }
977
                    _ => {
978
                        // This can happen if begin_inner() was called on a type that
979
                        // has shape.inner but isn't a SmartPointer (e.g., Option).
980
                        // In this case, we can't complete the conversion, so return error.
981
                        return Err(ReflectError::OperationFailed {
×
982
                            shape: parent_frame.shape,
×
983
                            operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
×
984
                        });
×
985
                    }
986
                }
987
            }
988
            Tracker::SmartPointerSlice {
989
                vtable,
33✔
990
                building_item,
33✔
991
            } => {
992
                if *building_item {
33✔
993
                    // We just popped an element frame, now push it to the slice builder
994
                    let element_ptr = PtrMut::new(unsafe {
33✔
995
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
996
                    });
997

998
                    // Use the slice builder's push_fn to add the element
999
                    crate::trace!("Pushing element to slice builder");
1000
                    unsafe {
33✔
1001
                        let parent_ptr = parent_frame.data.assume_init();
33✔
1002
                        (vtable.push_fn)(parent_ptr, element_ptr);
33✔
1003
                    }
33✔
1004

1005
                    popped_frame.tracker = Tracker::Scalar;
33✔
1006
                    popped_frame.is_init = false;
33✔
1007
                    popped_frame.dealloc();
33✔
1008

1009
                    if let Tracker::SmartPointerSlice {
1010
                        building_item: bi, ..
33✔
1011
                    } = &mut parent_frame.tracker
33✔
1012
                    {
33✔
1013
                        *bi = false;
33✔
1014
                    }
33✔
1015
                }
×
1016
            }
1017
            Tracker::DynamicValue {
1018
                state: DynamicValueState::Array { building_element },
13✔
1019
            } => {
1020
                if *building_element {
13✔
1021
                    // We just popped an element frame, now push it to the dynamic array
1022
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
13✔
1023
                        // Get mutable pointers - both array and element need PtrMut
13✔
1024
                        let array_ptr = unsafe { parent_frame.data.assume_init() };
13✔
1025
                        let element_ptr = unsafe { popped_frame.data.assume_init() };
13✔
1026

13✔
1027
                        // Use push_array_element to add element to the array
13✔
1028
                        unsafe {
13✔
1029
                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
13✔
1030
                        }
13✔
1031

13✔
1032
                        // Push moved out of popped_frame
13✔
1033
                        popped_frame.tracker = Tracker::Scalar;
13✔
1034
                        popped_frame.is_init = false;
13✔
1035
                        popped_frame.dealloc();
13✔
1036

13✔
1037
                        *building_element = false;
13✔
1038
                    }
13✔
NEW
1039
                }
×
1040
            }
UNCOV
1041
            _ => {}
×
1042
        }
1043

1044
        Ok(self)
2,361✔
1045
    }
3,274✔
1046

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

1052
        let mut path_components = Vec::new();
364✔
1053
        // The stack of enum/struct/sequence names currently in context.
1054
        // Start from root and build upwards.
1055
        for (i, frame) in self.frames().iter().enumerate() {
718✔
1056
            match frame.shape.ty {
718✔
1057
                Type::User(user_type) => match user_type {
600✔
1058
                    UserType::Struct(struct_type) => {
351✔
1059
                        // Try to get currently active field index
1060
                        let mut field_str = None;
351✔
1061
                        if let Tracker::Struct {
1062
                            current_child: Some(idx),
216✔
1063
                            ..
1064
                        } = &frame.tracker
220✔
1065
                        {
1066
                            if let Some(field) = struct_type.fields.get(*idx) {
216✔
1067
                                field_str = Some(field.name);
216✔
1068
                            }
216✔
1069
                        }
135✔
1070
                        if i == 0 {
351✔
1071
                            // Use Display for the root struct shape
272✔
1072
                            path_components.push(format!("{}", frame.shape));
272✔
1073
                        }
272✔
1074
                        if let Some(field_name) = field_str {
351✔
1075
                            path_components.push(format!(".{field_name}"));
216✔
1076
                        }
216✔
1077
                    }
1078
                    UserType::Enum(_enum_type) => {
15✔
1079
                        // Try to get currently active variant and field
1080
                        if let Tracker::Enum {
1081
                            variant,
4✔
1082
                            current_child,
4✔
1083
                            ..
1084
                        } = &frame.tracker
15✔
1085
                        {
1086
                            if i == 0 {
4✔
1087
                                // Use Display for the root enum shape
4✔
1088
                                path_components.push(format!("{}", frame.shape));
4✔
1089
                            }
4✔
1090
                            path_components.push(format!("::{}", variant.name));
4✔
1091
                            if let Some(idx) = *current_child {
4✔
1092
                                if let Some(field) = variant.data.fields.get(idx) {
4✔
1093
                                    path_components.push(format!(".{}", field.name));
4✔
1094
                                }
4✔
1095
                            }
×
1096
                        } else if i == 0 {
11✔
1097
                            // just the enum display
×
1098
                            path_components.push(format!("{}", frame.shape));
×
1099
                        }
11✔
1100
                    }
1101
                    UserType::Union(_union_type) => {
×
1102
                        path_components.push(format!("{}", frame.shape));
×
1103
                    }
×
1104
                    UserType::Opaque => {
234✔
1105
                        path_components.push("<opaque>".to_string());
234✔
1106
                    }
234✔
1107
                },
1108
                Type::Sequence(seq_type) => match seq_type {
×
1109
                    facet_core::SequenceType::Array(_array_def) => {
×
1110
                        // Try to show current element index
1111
                        if let Tracker::Array {
1112
                            current_child: Some(idx),
×
1113
                            ..
1114
                        } = &frame.tracker
×
1115
                        {
×
1116
                            path_components.push(format!("[{idx}]"));
×
1117
                        }
×
1118
                    }
1119
                    // You can add more for Slice, Vec, etc., if applicable
1120
                    _ => {
×
1121
                        // just indicate "[]" for sequence
×
1122
                        path_components.push("[]".to_string());
×
1123
                    }
×
1124
                },
1125
                Type::Pointer(_) => {
×
1126
                    // Indicate deref
×
1127
                    path_components.push("*".to_string());
×
1128
                }
×
1129
                _ => {
118✔
1130
                    // No structural path
118✔
1131
                }
118✔
1132
            }
1133
        }
1134
        // Merge the path_components into a single string
1135
        for component in path_components {
1,098✔
1136
            out.push_str(&component);
734✔
1137
        }
734✔
1138
        out
364✔
1139
    }
364✔
1140

1141
    /// Get the field for the parent frame
1142
    pub fn parent_field(&self) -> Option<&Field> {
145✔
1143
        self.frames()
145✔
1144
            .iter()
145✔
1145
            .rev()
145✔
1146
            .nth(1)
145✔
1147
            .and_then(|f| f.get_field())
145✔
1148
    }
145✔
1149

1150
    /// Gets the field for the current frame
1151
    pub fn current_field(&self) -> Option<&Field> {
×
1152
        self.frames().last().and_then(|f| f.get_field())
×
1153
    }
×
1154
}
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