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

facet-rs / facet / 19746156966

27 Nov 2025 07:23PM UTC coverage: 57.343% (+1.2%) from 56.098%
19746156966

push

github

fasterthanlime
Gate proptest fuzz tests behind fuzz-tests feature

These tests are very slow (1000+ cases with complex operations) and
shouldn't run in CI. Run manually with:
  cargo nextest run -p facet-reflect --features fuzz-tests

6825 of 11902 relevant lines covered (57.34%)

75.41 hits per line

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

64.98
/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 {
18✔
23
        self.frames()
18✔
24
            .last()
18✔
25
            .expect("Partial always has at least one frame")
18✔
26
            .shape
18✔
27
    }
18✔
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> {
60✔
62
        // Cannot enable deferred mode if already in deferred mode
63
        if self.is_deferred() {
60✔
64
            return Err(ReflectError::InvariantViolation {
1✔
65
                invariant: "begin_deferred() called but already in deferred mode",
1✔
66
            });
1✔
67
        }
59✔
68

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

77
        let start_depth = stack.len();
59✔
78
        self.mode = FrameMode::Deferred {
59✔
79
            stack,
59✔
80
            resolution,
59✔
81
            start_depth,
59✔
82
            current_path: Vec::new(),
59✔
83
            stored_frames: BTreeMap::new(),
59✔
84
        };
59✔
85
        Ok(self)
59✔
86
    }
60✔
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> {
52✔
100
        // Check if we're in deferred mode first, before extracting state
101
        if !self.is_deferred() {
52✔
102
            return Err(ReflectError::InvariantViolation {
2✔
103
                invariant: "finish_deferred() called but deferred mode is not enabled",
2✔
104
            });
2✔
105
        }
50✔
106

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

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

121
        // Sort paths by depth (deepest first) so we process children before parents
122
        let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
50✔
123
        paths.sort_by_key(|b| core::cmp::Reverse(b.len()));
370✔
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 {
196✔
133
            let frame = stored_frames.remove(&path).unwrap();
148✔
134

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

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

155
                let mut frame = frame; // Make mutable for deinit
2✔
156
                if !parent_will_drop && !matches!(frame.tracker, Tracker::Uninit) {
2✔
157
                    frame.deinit();
2✔
158
                }
2✔
159

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

164
                // Collect keys to remove (can't drain in no_std)
165
                let remaining_paths: Vec<_> = stored_frames.keys().cloned().collect();
2✔
166
                // Sort by depth (deepest first) for proper cleanup order
167
                let mut sorted_paths = remaining_paths;
2✔
168
                sorted_paths.sort_by_key(|p| core::cmp::Reverse(p.len()));
2✔
169

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

188
                        if !parent_will_drop && !matches!(remaining_frame.tracker, Tracker::Uninit)
3✔
189
                        {
3✔
190
                            remaining_frame.deinit();
3✔
191
                        }
3✔
192
                    }
×
193
                }
194
                return Err(e);
2✔
195
            }
146✔
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() {
146✔
203
                let parent_path: Vec<_> = path[..path.len() - 1].to_vec();
146✔
204

205
                if parent_path.is_empty() {
146✔
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);
95✔
210
                    if let Some(root_frame) = self.frames_mut().get_mut(parent_index) {
95✔
211
                        Self::mark_field_initialized(root_frame, field_name);
95✔
212
                    }
95✔
213
                } else {
214
                    // Try stored_frames first
215
                    if let Some(parent_frame) = stored_frames.get_mut(&parent_path) {
51✔
216
                        Self::mark_field_initialized(parent_frame, field_name);
51✔
217
                    } else {
51✔
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);
146✔
231
        }
232

233
        // Validate the root frame is fully initialized
234
        if let Some(frame) = self.frames().last() {
48✔
235
            frame.require_full_initialization()?;
48✔
236
        }
×
237

238
        Ok(self)
46✔
239
    }
52✔
240

241
    /// Mark a field as initialized in a frame's tracker
242
    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
146✔
243
        if let Some(idx) = Self::find_field_index(frame, field_name) {
146✔
244
            match &mut frame.tracker {
144✔
245
                Tracker::Struct { iset, .. } => {
130✔
246
                    iset.set(idx);
130✔
247
                }
130✔
248
                Tracker::Enum { data, .. } => {
14✔
249
                    data.set(idx);
14✔
250
                }
14✔
251
                Tracker::Array { iset, .. } => {
×
252
                    iset.set(idx);
×
253
                }
×
254
                _ => {}
×
255
            }
256
        }
2✔
257
    }
146✔
258

259
    /// Find the field index for a given field name in a frame
260
    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
162✔
261
        match frame.shape.ty {
162✔
262
            Type::User(UserType::Struct(struct_type)) => {
146✔
263
                struct_type.fields.iter().position(|f| f.name == field_name)
244✔
264
            }
265
            Type::User(UserType::Enum(_)) => {
266
                if let Tracker::Enum { variant, .. } = &frame.tracker {
16✔
267
                    variant
16✔
268
                        .data
16✔
269
                        .fields
16✔
270
                        .iter()
16✔
271
                        .position(|f| f.name == field_name)
23✔
272
                } else {
273
                    None
×
274
                }
275
            }
276
            _ => None,
×
277
        }
278
    }
162✔
279

280
    /// Check if a field is marked as initialized in the parent's iset/data tracker
281
    pub(crate) fn is_field_marked_in_parent(parent: &Frame, field_name: &str) -> bool {
12✔
282
        // First find the field index
283
        let idx = match Self::find_field_index(parent, field_name) {
12✔
284
            Some(idx) => idx,
12✔
285
            None => return false,
×
286
        };
287

288
        // Then check if it's marked in the parent's tracker
289
        match &parent.tracker {
12✔
290
            Tracker::Struct { iset, .. } => iset.get(idx),
12✔
291
            Tracker::Enum { data, .. } => data.get(idx),
×
292
            _ => false,
×
293
        }
294
    }
12✔
295

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

305
        // Then unmark it in the parent's tracker
306
        match &mut parent.tracker {
4✔
307
            Tracker::Struct { iset, .. } => iset.unset(idx),
4✔
308
            Tracker::Enum { data, .. } => data.unset(idx),
×
309
            _ => {}
×
310
        }
311
    }
4✔
312

313
    /// Pops the current frame off the stack, indicating we're done initializing the current field
314
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
680✔
315
        crate::trace!("end() called");
316
        self.require_active()?;
680✔
317

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

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

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

346
                return Ok(self);
6✔
347
            }
1✔
348
        }
673✔
349

350
        if self.frames().len() <= 1 {
674✔
351
            // Never pop the last/root frame.
352
            return Err(ReflectError::InvariantViolation {
1✔
353
                invariant: "Partial::end() called with only one frame on the stack",
1✔
354
            });
1✔
355
        }
673✔
356

357
        // In deferred mode, cannot pop below the start depth
358
        if let Some(start_depth) = self.start_depth() {
673✔
359
            if self.frames().len() <= start_depth {
276✔
360
                return Err(ReflectError::InvariantViolation {
×
361
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
362
                });
×
363
            }
276✔
364
        }
397✔
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() {
673✔
371
            true
397✔
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 {
276✔
376
                let frame_len = self.frames().len();
276✔
377
                let parent_frame = &self.frames()[frame_len - 2];
276✔
378
                matches!(
228✔
379
                    parent_frame.tracker,
276✔
380
                    Tracker::Map { .. }
381
                        | Tracker::List { .. }
382
                        | Tracker::Set { .. }
383
                        | Tracker::Option { .. }
384
                )
385
            } else {
386
                false
×
387
            }
388
        };
389

390
        if requires_full_init {
673✔
391
            let frame = self.frames().last().unwrap();
445✔
392
            trace!(
393
                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
394
                frame.shape,
395
                frame.tracker.kind()
396
            );
397
            frame.require_full_initialization()?
445✔
398
        }
228✔
399

400
        // Pop the frame and save its data pointer for SmartPointer handling
401
        let mut popped_frame = self.frames_mut().pop().unwrap();
661✔
402

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

424
            if is_tracked_field {
276✔
425
                trace!(
426
                    "end(): Storing frame for deferred path {:?}, shape {}",
427
                    current_path, popped_frame.shape
428
                );
429

430
                // Store the frame at the current path
431
                let path = current_path.clone();
214✔
432
                stored_frames.insert(path, popped_frame);
214✔
433

434
                // Pop from current_path
435
                current_path.pop();
214✔
436

437
                // Clear parent's current_child tracking
438
                if let Some(parent_frame) = stack.last_mut() {
214✔
439
                    parent_frame.tracker.clear_current_child();
214✔
440
                }
214✔
441

442
                return Ok(self);
214✔
443
            }
62✔
444
        }
385✔
445

446
        // check if this needs deserialization from a different shape
447
        if popped_frame.using_custom_deserialization {
447✔
448
            if let Some(deserialize_with) = self
8✔
449
                .parent_field()
8✔
450
                .and_then(|field| field.vtable.deserialize_with)
8✔
451
            {
452
                let parent_frame = self.frames_mut().last_mut().unwrap();
8✔
453

454
                trace!(
455
                    "Detected custom conversion needed from {} to {}",
456
                    popped_frame.shape, parent_frame.shape
457
                );
458

459
                unsafe {
460
                    let res = {
8✔
461
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
8✔
462
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
8✔
463
                    };
464
                    let popped_frame_shape = popped_frame.shape;
8✔
465

466
                    // we need to do this before any error handling to avoid leaks
467
                    popped_frame.deinit();
8✔
468
                    popped_frame.dealloc();
8✔
469
                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
8✔
470
                        message,
2✔
471
                        src_shape: popped_frame_shape,
2✔
472
                        dst_shape: parent_frame.shape,
2✔
473
                    })?;
2✔
474
                    if rptr.as_uninit() != parent_frame.data {
6✔
475
                        return Err(ReflectError::CustomDeserializationError {
×
476
                            message: "deserialize_with did not return the expected pointer".into(),
×
477
                            src_shape: popped_frame_shape,
×
478
                            dst_shape: parent_frame.shape,
×
479
                        });
×
480
                    }
6✔
481
                    parent_frame.mark_as_init();
6✔
482
                }
483
                return Ok(self);
6✔
484
            }
×
485
        }
439✔
486

487
        // Update parent frame's tracking when popping from a child
488
        let parent_frame = self.frames_mut().last_mut().unwrap();
439✔
489

490
        trace!(
491
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
492
            popped_frame.shape,
493
            popped_frame.tracker.kind(),
494
            parent_frame.shape,
495
            parent_frame.tracker.kind()
496
        );
497

498
        // Check if we need to do a conversion - this happens when:
499
        // 1. The parent frame has an inner type that matches the popped frame's shape
500
        // 2. The parent frame has try_from
501
        // 3. The parent frame is not yet initialized
502
        let needs_conversion = matches!(parent_frame.tracker, Tracker::Uninit)
439✔
503
            && parent_frame.shape.inner.is_some()
4✔
504
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
4✔
505
            && parent_frame.shape.vtable.try_from.is_some();
×
506

507
        if needs_conversion {
439✔
508
            trace!(
509
                "Detected implicit conversion needed from {} to {}",
510
                popped_frame.shape, parent_frame.shape
511
            );
512

513
            // The conversion requires the source frame to be fully initialized
514
            // (we're about to call assume_init() and pass to try_from)
515
            if let Err(e) = popped_frame.require_full_initialization() {
×
516
                // Deallocate the memory since the frame wasn't fully initialized
517
                if let FrameOwnership::Owned = popped_frame.ownership {
×
518
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
519
                        if layout.size() > 0 {
×
520
                            trace!(
521
                                "Deallocating uninitialized conversion frame memory: size={}, align={}",
522
                                layout.size(),
523
                                layout.align()
524
                            );
525
                            unsafe {
×
526
                                ::alloc::alloc::dealloc(
×
527
                                    popped_frame.data.as_mut_byte_ptr(),
×
528
                                    layout,
×
529
                                );
×
530
                            }
×
531
                        }
×
532
                    }
×
533
                }
×
534
                return Err(e);
×
535
            }
×
536

537
            // Perform the conversion
538
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
×
539
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
×
540
                let inner_shape = popped_frame.shape;
×
541

542
                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
543
                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
×
544

545
                if let Err(e) = result {
×
546
                    trace!("Conversion failed: {e:?}");
547

548
                    // Deallocate the inner value's memory since conversion failed
549
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
550
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
551
                            if layout.size() > 0 {
×
552
                                trace!(
553
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
554
                                    layout.size(),
555
                                    layout.align()
556
                                );
557
                                unsafe {
×
558
                                    ::alloc::alloc::dealloc(
×
559
                                        popped_frame.data.as_mut_byte_ptr(),
×
560
                                        layout,
×
561
                                    );
×
562
                                }
×
563
                            }
×
564
                        }
×
565
                    }
×
566

567
                    return Err(ReflectError::TryFromError {
×
568
                        src_shape: inner_shape,
×
569
                        dst_shape: parent_frame.shape,
×
570
                        inner: e,
×
571
                    });
×
572
                }
×
573

574
                trace!("Conversion succeeded, marking parent as initialized");
575
                parent_frame.tracker = Tracker::Init;
×
576

577
                // Deallocate the inner value's memory since try_from consumed it
578
                if let FrameOwnership::Owned = popped_frame.ownership {
×
579
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
580
                        if layout.size() > 0 {
×
581
                            trace!(
582
                                "Deallocating conversion frame memory: size={}, align={}",
583
                                layout.size(),
584
                                layout.align()
585
                            );
586
                            unsafe {
×
587
                                ::alloc::alloc::dealloc(
×
588
                                    popped_frame.data.as_mut_byte_ptr(),
×
589
                                    layout,
×
590
                                );
×
591
                            }
×
592
                        }
×
593
                    }
×
594
                }
×
595

596
                return Ok(self);
×
597
            }
×
598
        }
439✔
599

600
        match &mut parent_frame.tracker {
439✔
601
            Tracker::Struct {
602
                iset,
182✔
603
                current_child,
182✔
604
            } => {
605
                if let Some(idx) = *current_child {
182✔
606
                    iset.set(idx);
182✔
607
                    *current_child = None;
182✔
608
                }
182✔
609
            }
610
            Tracker::Array {
611
                iset,
43✔
612
                current_child,
43✔
613
            } => {
614
                if let Some(idx) = *current_child {
43✔
615
                    iset.set(idx);
43✔
616
                    *current_child = None;
43✔
617
                }
43✔
618
            }
619
            Tracker::SmartPointer { is_initialized } => {
7✔
620
                // We just popped the inner value frame, so now we need to create the smart pointer
621
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
7✔
622
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
7✔
623
                        return Err(ReflectError::OperationFailed {
×
624
                            shape: parent_frame.shape,
×
625
                            operation: "SmartPointer missing new_into_fn",
×
626
                        });
×
627
                    };
628

629
                    // The child frame contained the inner value
630
                    let inner_ptr = PtrMut::new(unsafe {
7✔
631
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
7✔
632
                    });
633

634
                    // Use new_into_fn to create the Box
635
                    unsafe {
7✔
636
                        new_into_fn(parent_frame.data, inner_ptr);
7✔
637
                    }
7✔
638

639
                    // We just moved out of it
640
                    popped_frame.tracker = Tracker::Uninit;
7✔
641

642
                    // Deallocate the inner value's memory since new_into_fn moved it
643
                    popped_frame.dealloc();
7✔
644

645
                    *is_initialized = true;
7✔
646
                }
×
647
            }
648
            Tracker::Enum {
649
                data,
46✔
650
                current_child,
46✔
651
                ..
652
            } => {
653
                if let Some(idx) = *current_child {
46✔
654
                    data.set(idx);
46✔
655
                    *current_child = None;
46✔
656
                }
46✔
657
            }
658
            Tracker::List {
659
                is_initialized: true,
660
                current_child,
70✔
661
            } => {
662
                if *current_child {
70✔
663
                    // We just popped an element frame, now push it to the list
664
                    if let Def::List(list_def) = parent_frame.shape.def {
70✔
665
                        let Some(push_fn) = list_def.vtable.push else {
70✔
666
                            return Err(ReflectError::OperationFailed {
×
667
                                shape: parent_frame.shape,
×
668
                                operation: "List missing push function",
×
669
                            });
×
670
                        };
671

672
                        // The child frame contained the element value
673
                        let element_ptr = PtrMut::new(unsafe {
70✔
674
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
70✔
675
                        });
676

677
                        // Use push to add element to the list
678
                        unsafe {
70✔
679
                            push_fn(
70✔
680
                                PtrMut::new(NonNull::new_unchecked(
70✔
681
                                    parent_frame.data.as_mut_byte_ptr(),
70✔
682
                                )),
70✔
683
                                element_ptr,
70✔
684
                            );
70✔
685
                        }
70✔
686

687
                        // Push moved out of popped_frame
688
                        popped_frame.tracker = Tracker::Uninit;
70✔
689
                        popped_frame.dealloc();
70✔
690

691
                        *current_child = false;
70✔
692
                    }
×
693
                }
×
694
            }
695
            Tracker::Map {
696
                is_initialized: true,
697
                insert_state,
43✔
698
            } => {
699
                match insert_state {
43✔
700
                    MapInsertState::PushingKey { key_ptr, .. } => {
23✔
701
                        // We just popped the key frame - mark key as initialized and transition
23✔
702
                        // to PushingValue state
23✔
703
                        *insert_state = MapInsertState::PushingValue {
23✔
704
                            key_ptr: *key_ptr,
23✔
705
                            value_ptr: None,
23✔
706
                            value_initialized: false,
23✔
707
                        };
23✔
708
                    }
23✔
709
                    MapInsertState::PushingValue {
710
                        key_ptr, value_ptr, ..
20✔
711
                    } => {
712
                        // We just popped the value frame, now insert the pair
713
                        if let (Some(value_ptr), Def::Map(map_def)) =
20✔
714
                            (value_ptr, parent_frame.shape.def)
20✔
715
                        {
716
                            let insert_fn = map_def.vtable.insert_fn;
20✔
717

718
                            // Use insert to add key-value pair to the map
719
                            unsafe {
20✔
720
                                insert_fn(
20✔
721
                                    PtrMut::new(NonNull::new_unchecked(
20✔
722
                                        parent_frame.data.as_mut_byte_ptr(),
20✔
723
                                    )),
20✔
724
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
20✔
725
                                    PtrMut::new(NonNull::new_unchecked(
20✔
726
                                        value_ptr.as_mut_byte_ptr(),
20✔
727
                                    )),
20✔
728
                                );
20✔
729
                            }
20✔
730

731
                            // Note: We don't deallocate the key and value memory here.
732
                            // The insert function has semantically moved the values into the map,
733
                            // but we still need to deallocate the temporary buffers.
734
                            // However, since we don't have frames for them anymore (they were popped),
735
                            // we need to handle deallocation here.
736
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
20✔
737
                                if key_shape.size() > 0 {
20✔
738
                                    unsafe {
20✔
739
                                        ::alloc::alloc::dealloc(
20✔
740
                                            key_ptr.as_mut_byte_ptr(),
20✔
741
                                            key_shape,
20✔
742
                                        );
20✔
743
                                    }
20✔
744
                                }
×
745
                            }
×
746
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
20✔
747
                                if value_shape.size() > 0 {
20✔
748
                                    unsafe {
20✔
749
                                        ::alloc::alloc::dealloc(
20✔
750
                                            value_ptr.as_mut_byte_ptr(),
20✔
751
                                            value_shape,
20✔
752
                                        );
20✔
753
                                    }
20✔
754
                                }
×
755
                            }
×
756

757
                            // Reset to idle state
758
                            *insert_state = MapInsertState::Idle;
20✔
759
                        }
×
760
                    }
761
                    MapInsertState::Idle => {
×
762
                        // Nothing to do
×
763
                    }
×
764
                }
765
            }
766
            Tracker::Set {
767
                is_initialized: true,
768
                current_child,
27✔
769
            } => {
770
                if *current_child {
27✔
771
                    // We just popped an element frame, now insert it into the set
772
                    if let Def::Set(set_def) = parent_frame.shape.def {
27✔
773
                        let insert_fn = set_def.vtable.insert_fn;
27✔
774

27✔
775
                        // The child frame contained the element value
27✔
776
                        let element_ptr = PtrMut::new(unsafe {
27✔
777
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
27✔
778
                        });
27✔
779

27✔
780
                        // Use insert to add element to the set
27✔
781
                        unsafe {
27✔
782
                            insert_fn(
27✔
783
                                PtrMut::new(NonNull::new_unchecked(
27✔
784
                                    parent_frame.data.as_mut_byte_ptr(),
27✔
785
                                )),
27✔
786
                                element_ptr,
27✔
787
                            );
27✔
788
                        }
27✔
789

27✔
790
                        // Insert moved out of popped_frame
27✔
791
                        popped_frame.tracker = Tracker::Uninit;
27✔
792
                        popped_frame.dealloc();
27✔
793

27✔
794
                        *current_child = false;
27✔
795
                    }
27✔
796
                }
×
797
            }
798
            Tracker::Option { building_inner } => {
2✔
799
                // We just popped the inner value frame for an Option's Some variant
800
                if *building_inner {
2✔
801
                    if let Def::Option(option_def) = parent_frame.shape.def {
2✔
802
                        // Use the Option vtable to initialize Some(inner_value)
803
                        let init_some_fn = option_def.vtable.init_some_fn;
2✔
804

805
                        // The popped frame contains the inner value
806
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
2✔
807

808
                        // Initialize the Option as Some(inner_value)
809
                        unsafe {
2✔
810
                            init_some_fn(parent_frame.data, inner_value_ptr);
2✔
811
                        }
2✔
812

813
                        // Deallocate the inner value's memory since init_some_fn moved it
814
                        if let FrameOwnership::Owned = popped_frame.ownership {
2✔
815
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
2✔
816
                                if layout.size() > 0 {
2✔
817
                                    unsafe {
2✔
818
                                        ::alloc::alloc::dealloc(
2✔
819
                                            popped_frame.data.as_mut_byte_ptr(),
2✔
820
                                            layout,
2✔
821
                                        );
2✔
822
                                    }
2✔
823
                                }
×
824
                            }
×
825
                        }
×
826

827
                        // Mark that we're no longer building the inner value
828
                        *building_inner = false;
2✔
829
                    } else {
830
                        return Err(ReflectError::OperationFailed {
×
831
                            shape: parent_frame.shape,
×
832
                            operation: "Option frame without Option definition",
×
833
                        });
×
834
                    }
835
                } else {
836
                    // building_inner is false - the Option was already initialized but
837
                    // begin_some was called again. The popped frame was not used to
838
                    // initialize the Option, so we need to clean it up.
839
                    popped_frame.deinit();
×
840
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
841
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
842
                            if layout.size() > 0 {
×
843
                                unsafe {
×
844
                                    ::alloc::alloc::dealloc(
×
845
                                        popped_frame.data.as_mut_byte_ptr(),
×
846
                                        layout,
×
847
                                    );
×
848
                                }
×
849
                            }
×
850
                        }
×
851
                    }
×
852
                }
853
            }
854
            Tracker::Uninit | Tracker::Init => {
855
                // the main case here is: the popped frame was a `String` and the
856
                // parent frame is an `Arc<str>`, `Box<str>` etc.
857
                match &parent_frame.shape.def {
5✔
858
                    Def::Pointer(smart_ptr_def) => {
5✔
859
                        let pointee =
5✔
860
                            smart_ptr_def
5✔
861
                                .pointee()
5✔
862
                                .ok_or(ReflectError::InvariantViolation {
5✔
863
                                    invariant: "pointer type doesn't have a pointee",
5✔
864
                                })?;
5✔
865

866
                        if !pointee.is_shape(str::SHAPE) {
5✔
867
                            return Err(ReflectError::InvariantViolation {
×
868
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
869
                            });
×
870
                        }
5✔
871

872
                        if !popped_frame.shape.is_shape(String::SHAPE) {
5✔
873
                            return Err(ReflectError::InvariantViolation {
×
874
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
875
                            });
×
876
                        }
5✔
877

878
                        popped_frame.require_full_initialization()?;
5✔
879

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

887
                        let Some(known) = smart_ptr_def.known else {
5✔
888
                            return Err(ReflectError::OperationFailed {
×
889
                                shape: parent_shape,
×
890
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
891
                            });
×
892
                        };
893

894
                        parent_frame.deinit();
5✔
895

896
                        // Interpret the memory as a String, then convert and write.
897
                        let string_ptr = popped_frame.data.as_mut_byte_ptr() as *mut String;
5✔
898
                        let string_value = unsafe { core::ptr::read(string_ptr) };
5✔
899

900
                        match known {
5✔
901
                            KnownPointer::Box => {
902
                                let boxed: Box<str> = string_value.into_boxed_str();
1✔
903
                                unsafe {
1✔
904
                                    core::ptr::write(
1✔
905
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1✔
906
                                        boxed,
1✔
907
                                    );
1✔
908
                                }
1✔
909
                            }
910
                            KnownPointer::Arc => {
911
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1✔
912
                                unsafe {
1✔
913
                                    core::ptr::write(
1✔
914
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1✔
915
                                        arc,
1✔
916
                                    );
1✔
917
                                }
1✔
918
                            }
919
                            KnownPointer::Rc => {
920
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
3✔
921
                                unsafe {
3✔
922
                                    core::ptr::write(
3✔
923
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
3✔
924
                                        rc,
3✔
925
                                    );
3✔
926
                                }
3✔
927
                            }
928
                            _ => {
929
                                return Err(ReflectError::OperationFailed {
×
930
                                    shape: parent_shape,
×
931
                                    operation: "Don't know how to build this pointer type",
×
932
                                });
×
933
                            }
934
                        }
935

936
                        parent_frame.tracker = Tracker::Init;
5✔
937

938
                        popped_frame.tracker = Tracker::Uninit;
5✔
939
                        popped_frame.dealloc();
5✔
940
                    }
941
                    _ => {
942
                        // This can happen if begin_inner() was called on a type that
943
                        // has shape.inner but isn't a SmartPointer (e.g., Option).
944
                        // In this case, we can't complete the conversion, so return error.
945
                        return Err(ReflectError::OperationFailed {
×
946
                            shape: parent_frame.shape,
×
947
                            operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
×
948
                        });
×
949
                    }
950
                }
951
            }
952
            Tracker::SmartPointerSlice {
953
                vtable,
14✔
954
                building_item,
14✔
955
            } => {
956
                if *building_item {
14✔
957
                    // We just popped an element frame, now push it to the slice builder
958
                    let element_ptr = PtrMut::new(unsafe {
14✔
959
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
14✔
960
                    });
961

962
                    // Use the slice builder's push_fn to add the element
963
                    crate::trace!("Pushing element to slice builder");
964
                    unsafe {
14✔
965
                        let parent_ptr = parent_frame.data.assume_init();
14✔
966
                        (vtable.push_fn)(parent_ptr, element_ptr);
14✔
967
                    }
14✔
968

969
                    popped_frame.tracker = Tracker::Uninit;
14✔
970
                    popped_frame.dealloc();
14✔
971

972
                    if let Tracker::SmartPointerSlice {
973
                        building_item: bi, ..
14✔
974
                    } = &mut parent_frame.tracker
14✔
975
                    {
14✔
976
                        *bi = false;
14✔
977
                    }
14✔
978
                }
×
979
            }
980
            _ => {}
×
981
        }
982

983
        Ok(self)
439✔
984
    }
680✔
985

986
    /// Returns a human-readable path representing the current traversal in the builder,
987
    /// e.g., `RootStruct.fieldName[index].subfield`.
988
    pub fn path(&self) -> String {
×
989
        let mut out = String::new();
×
990

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

1080
    /// Get the field for the parent frame
1081
    pub fn parent_field(&self) -> Option<&Field> {
16✔
1082
        self.frames()
16✔
1083
            .iter()
16✔
1084
            .rev()
16✔
1085
            .nth(1)
16✔
1086
            .and_then(|f| f.get_field())
16✔
1087
    }
16✔
1088
}
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