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

facet-rs / facet / 19777793341

29 Nov 2025 02:37AM UTC coverage: 61.03% (+0.2%) from 60.834%
19777793341

push

github

fasterthanlime
Fix clippy warnings and update compile test expectations

- Use direct comparison instead of to_string() in process_struct.rs
- Use starts_with() instead of chars().next() in format.rs
- Collapse nested if let patterns in facet-yaml
- Update compile_tests to expect "unknown extension attribute" error

2 of 6 new or added lines in 4 files covered. (33.33%)

249 existing lines in 9 files now uncovered.

17255 of 28273 relevant lines covered (61.03%)

156.0 hits per line

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

79.03
/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 {
86✔
17
        self.frames().len()
86✔
18
    }
86✔
19

20
    /// Returns the shape of the current frame.
21
    #[inline]
22
    pub fn shape(&self) -> &'static Shape {
13,685✔
23
        self.frames()
13,685✔
24
            .last()
13,685✔
25
            .expect("Partial always has at least one frame")
13,685✔
26
            .shape
13,685✔
27
    }
13,685✔
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> {
453✔
62
        self.require_active()?;
453✔
63

64
        // Cannot enable deferred mode if already in deferred mode
65
        if self.is_deferred() {
448✔
66
            return Err(ReflectError::InvariantViolation {
11✔
67
                invariant: "begin_deferred() called but already in deferred mode",
11✔
68
            });
11✔
69
        }
437✔
70

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

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

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

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

120
        // Restore the stack to self.mode
121
        self.mode = FrameMode::Strict { stack };
348✔
122

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

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

133
        // Process each stored frame from deepest to shallowest
134
        for path in paths {
1,109✔
135
            let mut frame = stored_frames.remove(&path).unwrap();
768✔
136

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

144
            // Fill in defaults for unset fields that have defaults
145
            frame.fill_defaults();
768✔
146

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

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

162
                self.poison_and_cleanup();
7✔
163
                return Err(e);
7✔
164
            }
761✔
165

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

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

197
            // Frame is validated and parent is updated - frame is no longer needed
198
            // (The actual data is already in place in memory, pointed to by parent)
199
            drop(frame);
761✔
200
        }
201

202
        // Fill defaults and validate the root frame is fully initialized
203
        if let Some(frame) = self.frames_mut().last_mut() {
341✔
204
            frame.fill_defaults();
341✔
205
            if let Err(e) = frame.require_full_initialization() {
341✔
206
                // Root validation failed. At this point, all stored frames have been
207
                // processed and their parent isets updated. We must poison the Partial
208
                // to prevent further use, which would leave data in an inconsistent state.
209
                self.poison_and_cleanup();
5✔
210
                return Err(e);
5✔
211
            }
336✔
UNCOV
212
        }
×
213

214
        Ok(self)
336✔
215
    }
350✔
216

217
    /// Mark a field as initialized in a frame's tracker
218
    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
761✔
219
        if let Some(idx) = Self::find_field_index(frame, field_name) {
761✔
220
            // If the tracker is Scalar but this is a struct type, upgrade to Struct tracker.
221
            // This can happen if the frame was deinit'd (e.g., by a failed set_default)
222
            // which resets the tracker to Scalar.
223
            if matches!(frame.tracker, Tracker::Scalar) {
759✔
224
                if let Type::User(UserType::Struct(struct_type)) = frame.shape.ty {
1✔
225
                    frame.tracker = Tracker::Struct {
1✔
226
                        iset: ISet::new(struct_type.fields.len()),
1✔
227
                        current_child: None,
1✔
228
                    };
1✔
229
                }
1✔
230
            }
758✔
231

232
            match &mut frame.tracker {
759✔
233
                Tracker::Struct { iset, .. } => {
668✔
234
                    iset.set(idx);
668✔
235
                }
668✔
236
                Tracker::Enum { data, .. } => {
91✔
237
                    data.set(idx);
91✔
238
                }
91✔
239
                Tracker::Array { iset, .. } => {
×
UNCOV
240
                    iset.set(idx);
×
UNCOV
241
                }
×
242
                _ => {}
×
243
            }
244
        }
2✔
245
    }
761✔
246

247
    /// Find the field index for a given field name in a frame
248
    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
761✔
249
        match frame.shape.ty {
761✔
250
            Type::User(UserType::Struct(struct_type)) => {
668✔
251
                struct_type.fields.iter().position(|f| f.name == field_name)
1,403✔
252
            }
253
            Type::User(UserType::Enum(_)) => {
254
                if let Tracker::Enum { variant, .. } = &frame.tracker {
93✔
255
                    variant
93✔
256
                        .data
93✔
257
                        .fields
93✔
258
                        .iter()
93✔
259
                        .position(|f| f.name == field_name)
112✔
260
                } else {
UNCOV
261
                    None
×
262
                }
263
            }
UNCOV
264
            _ => None,
×
265
        }
266
    }
761✔
267

268
    /// Pops the current frame off the stack, indicating we're done initializing the current field
269
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
3,338✔
270
        if let Some(_frame) = self.frames().last() {
3,338✔
271
            crate::trace!(
3,334✔
272
                "end() called: shape={}, tracker={:?}, is_init={}",
3,334✔
273
                _frame.shape,
3,334✔
274
                _frame.tracker.kind(),
3,334✔
275
                _frame.is_init
3,334✔
276
            );
3,334✔
277
        }
3,334✔
278
        self.require_active()?;
3,338✔
279

280
        // Special handling for SmartPointerSlice - convert builder to Arc
281
        if self.frames().len() == 1 {
3,334✔
282
            let frames = self.frames_mut();
28✔
283
            if let Tracker::SmartPointerSlice {
284
                vtable,
13✔
285
                building_item,
13✔
286
            } = &frames[0].tracker
28✔
287
            {
288
                if *building_item {
13✔
UNCOV
289
                    return Err(ReflectError::OperationFailed {
×
UNCOV
290
                        shape: frames[0].shape,
×
UNCOV
291
                        operation: "still building an item, finish it first",
×
UNCOV
292
                    });
×
293
                }
13✔
294

295
                // Convert the builder to Arc<[T]>
296
                let vtable = *vtable;
13✔
297
                let builder_ptr = unsafe { frames[0].data.assume_init() };
13✔
298
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
13✔
299

300
                // Update the frame to store the Arc
301
                frames[0].data = PtrUninit::new(unsafe {
13✔
302
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
13✔
303
                });
13✔
304
                frames[0].tracker = Tracker::Scalar;
13✔
305
                frames[0].is_init = true;
13✔
306
                // The builder memory has been consumed by convert_fn, so we no longer own it
307
                frames[0].ownership = FrameOwnership::ManagedElsewhere;
13✔
308

309
                return Ok(self);
13✔
310
            }
15✔
311
        }
3,306✔
312

313
        if self.frames().len() <= 1 {
3,321✔
314
            // Never pop the last/root frame.
315
            return Err(ReflectError::InvariantViolation {
15✔
316
                invariant: "Partial::end() called with only one frame on the stack",
15✔
317
            });
15✔
318
        }
3,306✔
319

320
        // In deferred mode, cannot pop below the start depth
321
        if let Some(start_depth) = self.start_depth() {
3,306✔
322
            if self.frames().len() <= start_depth {
1,220✔
UNCOV
323
                return Err(ReflectError::InvariantViolation {
×
UNCOV
324
                    invariant: "Partial::end() called but would pop below deferred start depth",
×
UNCOV
325
                });
×
326
            }
1,220✔
327
        }
2,086✔
328

329
        // Require that the top frame is fully initialized before popping.
330
        // Skip this check in deferred mode - validation happens in finish_deferred().
331
        // EXCEPT for collection items (map, list, set, option) which must be fully
332
        // initialized before insertion/completion.
333
        let requires_full_init = if !self.is_deferred() {
3,306✔
334
            true
2,086✔
335
        } else {
336
            // In deferred mode, check if parent is a collection that requires
337
            // fully initialized items (map, list, set, option)
338
            if self.frames().len() >= 2 {
1,220✔
339
                let frame_len = self.frames().len();
1,220✔
340
                let parent_frame = &self.frames()[frame_len - 2];
1,220✔
341
                matches!(
963✔
342
                    parent_frame.tracker,
6✔
343
                    Tracker::Map { .. }
344
                        | Tracker::List { .. }
345
                        | Tracker::Set { .. }
346
                        | Tracker::Option { .. }
347
                        | Tracker::DynamicValue {
348
                            state: DynamicValueState::Array { .. }
349
                        }
350
                )
351
            } else {
UNCOV
352
                false
×
353
            }
354
        };
355

356
        if requires_full_init {
3,306✔
357
            let frame = self.frames().last().unwrap();
2,343✔
358
            crate::trace!(
359
                "end(): Checking full init for {}, tracker={:?}, is_init={}",
360
                frame.shape,
361
                frame.tracker.kind(),
362
                frame.is_init
363
            );
364
            let result = frame.require_full_initialization();
2,343✔
365
            crate::trace!(
366
                "end(): require_full_initialization result: {:?}",
367
                result.is_ok()
368
            );
369
            result?
2,343✔
370
        }
963✔
371

372
        // Pop the frame and save its data pointer for SmartPointer handling
373
        let mut popped_frame = self.frames_mut().pop().unwrap();
3,289✔
374

375
        // In deferred mode, store the frame for potential re-entry and skip
376
        // the normal parent-updating logic. The frame will be finalized later
377
        // in finish_deferred().
378
        //
379
        // We only store if the path depth matches the frame depth, meaning we're
380
        // ending a tracked struct/enum field, not something like begin_some()
381
        // or a field inside a collection item.
382
        if let FrameMode::Deferred {
383
            stack,
1,218✔
384
            start_depth,
1,218✔
385
            current_path,
1,218✔
386
            stored_frames,
1,218✔
387
            ..
388
        } = &mut self.mode
3,289✔
389
        {
390
            // Path depth should match the relative frame depth for a tracked field.
391
            // After popping: frames.len() - start_depth + 1 should equal path.len()
392
            // for fields entered via begin_field (not begin_some/begin_inner).
393
            let relative_depth = stack.len() - *start_depth + 1;
1,218✔
394
            let is_tracked_field = !current_path.is_empty() && current_path.len() == relative_depth;
1,218✔
395

396
            if is_tracked_field {
1,218✔
397
                trace!(
398
                    "end(): Storing frame for deferred path {:?}, shape {}",
399
                    current_path, popped_frame.shape
400
                );
401

402
                // Store the frame at the current path
403
                let path = current_path.clone();
862✔
404
                stored_frames.insert(path, popped_frame);
862✔
405

406
                // Pop from current_path
407
                current_path.pop();
862✔
408

409
                // Clear parent's current_child tracking
410
                if let Some(parent_frame) = stack.last_mut() {
862✔
411
                    parent_frame.tracker.clear_current_child();
862✔
412
                }
862✔
413

414
                return Ok(self);
862✔
415
            }
356✔
416
        }
2,071✔
417

418
        // check if this needs deserialization from a different shape
419
        if popped_frame.using_custom_deserialization {
2,427✔
420
            if let Some(deserialize_with) = self
19✔
421
                .parent_field()
19✔
422
                .and_then(|field| field.vtable.deserialize_with)
19✔
423
            {
424
                let parent_frame = self.frames_mut().last_mut().unwrap();
19✔
425

426
                trace!(
427
                    "Detected custom conversion needed from {} to {}",
428
                    popped_frame.shape, parent_frame.shape
429
                );
430

431
                unsafe {
432
                    let res = {
19✔
433
                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
19✔
434
                        (deserialize_with)(inner_value_ptr, parent_frame.data)
19✔
435
                    };
436
                    let popped_frame_shape = popped_frame.shape;
19✔
437

438
                    // we need to do this before any error handling to avoid leaks
439
                    popped_frame.deinit();
19✔
440
                    popped_frame.dealloc();
19✔
441
                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
19✔
442
                        message,
2✔
443
                        src_shape: popped_frame_shape,
2✔
444
                        dst_shape: parent_frame.shape,
2✔
445
                    })?;
2✔
446
                    if rptr.as_uninit() != parent_frame.data {
17✔
UNCOV
447
                        return Err(ReflectError::CustomDeserializationError {
×
UNCOV
448
                            message: "deserialize_with did not return the expected pointer".into(),
×
UNCOV
449
                            src_shape: popped_frame_shape,
×
UNCOV
450
                            dst_shape: parent_frame.shape,
×
UNCOV
451
                        });
×
452
                    }
17✔
453
                    parent_frame.mark_as_init();
17✔
454
                }
455
                return Ok(self);
17✔
UNCOV
456
            }
×
457
        }
2,408✔
458

459
        // Update parent frame's tracking when popping from a child
460
        let parent_frame = self.frames_mut().last_mut().unwrap();
2,408✔
461

462
        crate::trace!(
463
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
464
            popped_frame.shape,
465
            popped_frame.tracker.kind(),
466
            parent_frame.shape,
467
            parent_frame.tracker.kind()
468
        );
469

470
        // Check if we need to do a conversion - this happens when:
471
        // 1. The parent frame has an inner type that matches the popped frame's shape
472
        // 2. The parent frame has try_from
473
        // 3. The parent frame is not yet initialized
474
        // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
475
        //    This ensures we only do conversion when begin_inner was used, not begin_some
476
        let needs_conversion = !parent_frame.is_init
2,408✔
477
            && matches!(parent_frame.tracker, Tracker::Scalar)
1,559✔
478
            && parent_frame.shape.inner.is_some()
43✔
479
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
43✔
480
            && parent_frame.shape.vtable.try_from.is_some();
35✔
481

482
        if needs_conversion {
2,408✔
483
            trace!(
484
                "Detected implicit conversion needed from {} to {}",
485
                popped_frame.shape, parent_frame.shape
486
            );
487

488
            // The conversion requires the source frame to be fully initialized
489
            // (we're about to call assume_init() and pass to try_from)
490
            if let Err(e) = popped_frame.require_full_initialization() {
35✔
491
                // Deallocate the memory since the frame wasn't fully initialized
UNCOV
492
                if let FrameOwnership::Owned = popped_frame.ownership {
×
UNCOV
493
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
UNCOV
494
                        if layout.size() > 0 {
×
495
                            trace!(
496
                                "Deallocating uninitialized conversion frame memory: size={}, align={}",
497
                                layout.size(),
498
                                layout.align()
499
                            );
UNCOV
500
                            unsafe {
×
UNCOV
501
                                ::alloc::alloc::dealloc(
×
UNCOV
502
                                    popped_frame.data.as_mut_byte_ptr(),
×
UNCOV
503
                                    layout,
×
UNCOV
504
                                );
×
UNCOV
505
                            }
×
UNCOV
506
                        }
×
UNCOV
507
                    }
×
UNCOV
508
                }
×
UNCOV
509
                return Err(e);
×
510
            }
35✔
511

512
            // Perform the conversion
513
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
35✔
514
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
35✔
515
                let inner_shape = popped_frame.shape;
35✔
516

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

520
                if let Err(e) = result {
35✔
521
                    trace!("Conversion failed: {e:?}");
522

523
                    // Deallocate the inner value's memory since conversion failed
524
                    if let FrameOwnership::Owned = popped_frame.ownership {
2✔
525
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
2✔
526
                            if layout.size() > 0 {
2✔
527
                                trace!(
528
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
529
                                    layout.size(),
530
                                    layout.align()
531
                                );
532
                                unsafe {
2✔
533
                                    ::alloc::alloc::dealloc(
2✔
534
                                        popped_frame.data.as_mut_byte_ptr(),
2✔
535
                                        layout,
2✔
536
                                    );
2✔
537
                                }
2✔
UNCOV
538
                            }
×
UNCOV
539
                        }
×
UNCOV
540
                    }
×
541

542
                    return Err(ReflectError::TryFromError {
2✔
543
                        src_shape: inner_shape,
2✔
544
                        dst_shape: parent_frame.shape,
2✔
545
                        inner: e,
2✔
546
                    });
2✔
547
                }
33✔
548

549
                trace!("Conversion succeeded, marking parent as initialized");
550
                parent_frame.is_init = true;
33✔
551

552
                // Deallocate the inner value's memory since try_from consumed it
553
                if let FrameOwnership::Owned = popped_frame.ownership {
33✔
554
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
33✔
555
                        if layout.size() > 0 {
33✔
556
                            trace!(
557
                                "Deallocating conversion frame memory: size={}, align={}",
558
                                layout.size(),
559
                                layout.align()
560
                            );
561
                            unsafe {
33✔
562
                                ::alloc::alloc::dealloc(
33✔
563
                                    popped_frame.data.as_mut_byte_ptr(),
33✔
564
                                    layout,
33✔
565
                                );
33✔
566
                            }
33✔
UNCOV
567
                        }
×
UNCOV
568
                    }
×
UNCOV
569
                }
×
570

571
                return Ok(self);
33✔
UNCOV
572
            }
×
573
        }
2,373✔
574

575
        // For Field-owned frames, reclaim responsibility in parent's tracker
576
        // Only mark as initialized if the child frame was actually initialized.
577
        // This prevents double-free when begin_inner/begin_some drops a value via
578
        // prepare_for_reinitialization but then fails, leaving the child uninitialized.
579
        //
580
        // We use require_full_initialization() rather than just is_init because:
581
        // - Scalar frames use is_init as the source of truth
582
        // - Struct/Array/Enum frames use their iset/data as the source of truth
583
        //   (is_init may never be set to true for these tracker types)
584
        if let FrameOwnership::Field { field_idx } = popped_frame.ownership {
2,373✔
585
            let child_is_initialized = popped_frame.require_full_initialization().is_ok();
1,345✔
586
            match &mut parent_frame.tracker {
1,345✔
587
                Tracker::Struct {
588
                    iset,
1,143✔
589
                    current_child,
1,143✔
590
                } => {
591
                    if child_is_initialized {
1,143✔
592
                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
1,143✔
593
                    }
1,143✔
594
                    *current_child = None;
1,143✔
595
                }
596
                Tracker::Array {
597
                    iset,
92✔
598
                    current_child,
92✔
599
                } => {
600
                    if child_is_initialized {
92✔
601
                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
92✔
602
                    }
92✔
603
                    *current_child = None;
92✔
604
                }
605
                Tracker::Enum {
606
                    data,
110✔
607
                    current_child,
110✔
608
                    ..
609
                } => {
610
                    if child_is_initialized {
110✔
611
                        data.set(field_idx); // Parent reclaims responsibility only if child was init
110✔
612
                    }
110✔
613
                    *current_child = None;
110✔
614
                }
UNCOV
615
                _ => {}
×
616
            }
617
            return Ok(self);
1,345✔
618
        }
1,028✔
619

620
        match &mut parent_frame.tracker {
617✔
621
            Tracker::SmartPointer => {
622
                // We just popped the inner value frame, so now we need to create the smart pointer
623
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
26✔
624
                    // The inner value must be fully initialized before we can create the smart pointer
625
                    if let Err(e) = popped_frame.require_full_initialization() {
26✔
626
                        // Inner value wasn't initialized, deallocate and return error
UNCOV
627
                        popped_frame.deinit();
×
UNCOV
628
                        popped_frame.dealloc();
×
629
                        return Err(e);
×
630
                    }
26✔
631

632
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
26✔
UNCOV
633
                        popped_frame.deinit();
×
UNCOV
634
                        popped_frame.dealloc();
×
UNCOV
635
                        return Err(ReflectError::OperationFailed {
×
UNCOV
636
                            shape: parent_frame.shape,
×
UNCOV
637
                            operation: "SmartPointer missing new_into_fn",
×
UNCOV
638
                        });
×
639
                    };
640

641
                    // The child frame contained the inner value
642
                    let inner_ptr = PtrMut::new(unsafe {
26✔
643
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
26✔
644
                    });
645

646
                    // Use new_into_fn to create the Box
647
                    unsafe {
26✔
648
                        new_into_fn(parent_frame.data, inner_ptr);
26✔
649
                    }
26✔
650

651
                    // We just moved out of it
652
                    popped_frame.tracker = Tracker::Scalar;
26✔
653
                    popped_frame.is_init = false;
26✔
654

655
                    // Deallocate the inner value's memory since new_into_fn moved it
656
                    popped_frame.dealloc();
26✔
657

658
                    parent_frame.is_init = true;
26✔
UNCOV
659
                }
×
660
            }
661
            Tracker::List { current_child } if parent_frame.is_init => {
617✔
662
                if *current_child {
617✔
663
                    // We just popped an element frame, now push it to the list
664
                    if let Def::List(list_def) = parent_frame.shape.def {
617✔
665
                        let Some(push_fn) = list_def.vtable.push else {
617✔
UNCOV
666
                            return Err(ReflectError::OperationFailed {
×
UNCOV
667
                                shape: parent_frame.shape,
×
UNCOV
668
                                operation: "List missing push function",
×
UNCOV
669
                            });
×
670
                        };
671

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

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

687
                        // Push moved out of popped_frame
688
                        popped_frame.tracker = Tracker::Scalar;
617✔
689
                        popped_frame.is_init = false;
617✔
690
                        popped_frame.dealloc();
617✔
691

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

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

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

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

33✔
770
                        // The child frame contained the element value
33✔
771
                        let element_ptr = PtrMut::new(unsafe {
33✔
772
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
33✔
773
                        });
33✔
774

33✔
775
                        // Use insert to add element to the set
33✔
776
                        unsafe {
33✔
777
                            insert_fn(
33✔
778
                                PtrMut::new(NonNull::new_unchecked(
33✔
779
                                    parent_frame.data.as_mut_byte_ptr(),
33✔
780
                                )),
33✔
781
                                element_ptr,
33✔
782
                            );
33✔
783
                        }
33✔
784

33✔
785
                        // Insert moved out of popped_frame
33✔
786
                        popped_frame.tracker = Tracker::Scalar;
33✔
787
                        popped_frame.is_init = false;
33✔
788
                        popped_frame.dealloc();
33✔
789

33✔
790
                        *current_child = false;
33✔
791
                    }
33✔
UNCOV
792
                }
×
793
            }
794
            Tracker::Option { building_inner } => {
112✔
795
                crate::trace!(
796
                    "end(): matched Tracker::Option, building_inner={}",
797
                    *building_inner
798
                );
799
                // We just popped the inner value frame for an Option's Some variant
800
                if *building_inner {
112✔
801
                    if let Def::Option(option_def) = parent_frame.shape.def {
112✔
802
                        // Use the Option vtable to initialize Some(inner_value)
803
                        let init_some_fn = option_def.vtable.init_some_fn;
112✔
804

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

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

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

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

870
                        if !pointee.is_shape(str::SHAPE) {
8✔
UNCOV
871
                            return Err(ReflectError::InvariantViolation {
×
UNCOV
872
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
UNCOV
873
                            });
×
874
                        }
8✔
875

876
                        if !popped_frame.shape.is_shape(String::SHAPE) {
8✔
UNCOV
877
                            return Err(ReflectError::InvariantViolation {
×
UNCOV
878
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
UNCOV
879
                            });
×
880
                        }
8✔
881

882
                        popped_frame.require_full_initialization()?;
8✔
883

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

891
                        let Some(known) = smart_ptr_def.known else {
8✔
UNCOV
892
                            return Err(ReflectError::OperationFailed {
×
UNCOV
893
                                shape: parent_shape,
×
UNCOV
894
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
UNCOV
895
                            });
×
896
                        };
897

898
                        parent_frame.deinit();
8✔
899

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

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

940
                        parent_frame.is_init = true;
8✔
941

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

967
                    // Use the slice builder's push_fn to add the element
968
                    crate::trace!("Pushing element to slice builder");
969
                    unsafe {
33✔
970
                        let parent_ptr = parent_frame.data.assume_init();
33✔
971
                        (vtable.push_fn)(parent_ptr, element_ptr);
33✔
972
                    }
33✔
973

974
                    popped_frame.tracker = Tracker::Scalar;
33✔
975
                    popped_frame.is_init = false;
33✔
976
                    popped_frame.dealloc();
33✔
977

978
                    if let Tracker::SmartPointerSlice {
979
                        building_item: bi, ..
33✔
980
                    } = &mut parent_frame.tracker
33✔
981
                    {
33✔
982
                        *bi = false;
33✔
983
                    }
33✔
UNCOV
984
                }
×
985
            }
986
            Tracker::DynamicValue {
987
                state: DynamicValueState::Array { building_element },
18✔
988
            } => {
989
                if *building_element {
18✔
990
                    // We just popped an element frame, now push it to the dynamic array
991
                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
18✔
992
                        // Get mutable pointers - both array and element need PtrMut
18✔
993
                        let array_ptr = unsafe { parent_frame.data.assume_init() };
18✔
994
                        let element_ptr = unsafe { popped_frame.data.assume_init() };
18✔
995

18✔
996
                        // Use push_array_element to add element to the array
18✔
997
                        unsafe {
18✔
998
                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
18✔
999
                        }
18✔
1000

18✔
1001
                        // Push moved out of popped_frame
18✔
1002
                        popped_frame.tracker = Tracker::Scalar;
18✔
1003
                        popped_frame.is_init = false;
18✔
1004
                        popped_frame.dealloc();
18✔
1005

18✔
1006
                        *building_element = false;
18✔
1007
                    }
18✔
UNCOV
1008
                }
×
1009
            }
UNCOV
1010
            _ => {}
×
1011
        }
1012

1013
        Ok(self)
1,028✔
1014
    }
3,338✔
1015

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

1021
        let mut path_components = Vec::new();
364✔
1022
        // The stack of enum/struct/sequence names currently in context.
1023
        // Start from root and build upwards.
1024
        for (i, frame) in self.frames().iter().enumerate() {
714✔
1025
            match frame.shape.ty {
714✔
1026
                Type::User(user_type) => match user_type {
596✔
1027
                    UserType::Struct(struct_type) => {
347✔
1028
                        // Try to get currently active field index
1029
                        let mut field_str = None;
347✔
1030
                        if let Tracker::Struct {
1031
                            current_child: Some(idx),
216✔
1032
                            ..
1033
                        } = &frame.tracker
216✔
1034
                        {
1035
                            if let Some(field) = struct_type.fields.get(*idx) {
216✔
1036
                                field_str = Some(field.name);
216✔
1037
                            }
216✔
1038
                        }
131✔
1039
                        if i == 0 {
347✔
1040
                            // Use Display for the root struct shape
268✔
1041
                            path_components.push(format!("{}", frame.shape));
268✔
1042
                        }
268✔
1043
                        if let Some(field_name) = field_str {
347✔
1044
                            path_components.push(format!(".{field_name}"));
216✔
1045
                        }
216✔
1046
                    }
1047
                    UserType::Enum(_enum_type) => {
15✔
1048
                        // Try to get currently active variant and field
1049
                        if let Tracker::Enum {
1050
                            variant,
4✔
1051
                            current_child,
4✔
1052
                            ..
1053
                        } = &frame.tracker
15✔
1054
                        {
1055
                            if i == 0 {
4✔
1056
                                // Use Display for the root enum shape
4✔
1057
                                path_components.push(format!("{}", frame.shape));
4✔
1058
                            }
4✔
1059
                            path_components.push(format!("::{}", variant.name));
4✔
1060
                            if let Some(idx) = *current_child {
4✔
1061
                                if let Some(field) = variant.data.fields.get(idx) {
4✔
1062
                                    path_components.push(format!(".{}", field.name));
4✔
1063
                                }
4✔
UNCOV
1064
                            }
×
1065
                        } else if i == 0 {
11✔
UNCOV
1066
                            // just the enum display
×
UNCOV
1067
                            path_components.push(format!("{}", frame.shape));
×
1068
                        }
11✔
1069
                    }
UNCOV
1070
                    UserType::Union(_union_type) => {
×
UNCOV
1071
                        path_components.push(format!("{}", frame.shape));
×
UNCOV
1072
                    }
×
1073
                    UserType::Opaque => {
234✔
1074
                        path_components.push("<opaque>".to_string());
234✔
1075
                    }
234✔
1076
                },
UNCOV
1077
                Type::Sequence(seq_type) => match seq_type {
×
UNCOV
1078
                    facet_core::SequenceType::Array(_array_def) => {
×
1079
                        // Try to show current element index
1080
                        if let Tracker::Array {
UNCOV
1081
                            current_child: Some(idx),
×
1082
                            ..
1083
                        } = &frame.tracker
×
1084
                        {
×
1085
                            path_components.push(format!("[{idx}]"));
×
UNCOV
1086
                        }
×
1087
                    }
1088
                    // You can add more for Slice, Vec, etc., if applicable
UNCOV
1089
                    _ => {
×
UNCOV
1090
                        // just indicate "[]" for sequence
×
UNCOV
1091
                        path_components.push("[]".to_string());
×
UNCOV
1092
                    }
×
1093
                },
UNCOV
1094
                Type::Pointer(_) => {
×
UNCOV
1095
                    // Indicate deref
×
UNCOV
1096
                    path_components.push("*".to_string());
×
UNCOV
1097
                }
×
1098
                _ => {
118✔
1099
                    // No structural path
118✔
1100
                }
118✔
1101
            }
1102
        }
1103
        // Merge the path_components into a single string
1104
        for component in path_components {
1,094✔
1105
            out.push_str(&component);
730✔
1106
        }
730✔
1107
        out
364✔
1108
    }
364✔
1109

1110
    /// Get the field for the parent frame
1111
    pub fn parent_field(&self) -> Option<&Field> {
145✔
1112
        self.frames()
145✔
1113
            .iter()
145✔
1114
            .rev()
145✔
1115
            .nth(1)
145✔
1116
            .and_then(|f| f.get_field())
145✔
1117
    }
145✔
1118

1119
    /// Gets the field for the current frame
UNCOV
1120
    pub fn current_field(&self) -> Option<&Field> {
×
UNCOV
1121
        self.frames().last().and_then(|f| f.get_field())
×
UNCOV
1122
    }
×
1123
}
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