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

facet-rs / facet / 18683512809

21 Oct 2025 12:16PM UTC coverage: 53.804% (-0.2%) from 54.052%
18683512809

push

github

fasterthanlime
remove fn() layer of indirection where possible

100 of 260 new or added lines in 30 files covered. (38.46%)

22 existing lines in 5 files now uncovered.

4590 of 8531 relevant lines covered (53.8%)

41.11 hits per line

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

61.1
/facet-reflect/src/partial/partial_api.rs
1
// This module contains the public-facing API for `Partial`
2

3
use alloc::{
4
    boxed::Box,
5
    format,
6
    string::{String, ToString},
7
    vec::Vec,
8
};
9

10
use core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
11

12
use crate::{
13
    Guard, HeapValue, Partial, Peek, ReflectError, TypedPartial,
14
    partial::{Frame, FrameOwnership, MapInsertState, PartialState, Tracker, iset::ISet},
15
    trace,
16
};
17
use facet_core::{
18
    ArrayType, Characteristic, Def, EnumRepr, EnumType, Facet, Field, KnownPointer, PtrConst,
19
    PtrMut, PtrUninit, SequenceType, Shape, StructType, Type, UserType, Variant,
20
};
21

22
////////////////////////////////////////////////////////////////////////////////////////////////////
23
// Allocation, constructors etc.
24
////////////////////////////////////////////////////////////////////////////////////////////////////
25
impl<'facet> Partial<'facet> {
26
    /// Allocates a new [TypedPartial] instance on the heap, with the given shape and type
27
    pub fn alloc<T>() -> Result<TypedPartial<'facet, T>, ReflectError>
213✔
28
    where
213✔
29
        T: Facet<'facet> + ?Sized,
213✔
30
    {
31
        Ok(TypedPartial {
32
            inner: Self::alloc_shape(T::SHAPE)?,
213✔
33
            phantom: PhantomData,
212✔
34
        })
35
    }
213✔
36

37
    /// Allocates a new [Partial] instance on the heap, with the given shape.
38
    pub fn alloc_shape(shape: &'static Shape) -> Result<Self, ReflectError> {
228✔
39
        crate::trace!(
40
            "alloc_shape({:?}), with layout {:?}",
41
            shape,
42
            shape.layout.sized_layout()
43
        );
44

45
        let data = shape.allocate().map_err(|_| ReflectError::Unsized {
228✔
46
            shape,
1✔
47
            operation: "alloc_shape",
48
        })?;
1✔
49

50
        // Preallocate a couple of frames. The cost of allocating 4 frames is
51
        // basically identical to allocating 1 frame, so for every type that
52
        // has at least 1 level of nesting, this saves at least one guaranteed reallocation.
53
        let mut frames = Vec::with_capacity(4);
227✔
54
        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
227✔
55

56
        Ok(Self {
227✔
57
            frames,
227✔
58
            state: PartialState::Active,
227✔
59
            invariant: PhantomData,
227✔
60
        })
227✔
61
    }
228✔
62
}
63

64
////////////////////////////////////////////////////////////////////////////////////////////////////
65
// Misc.
66
////////////////////////////////////////////////////////////////////////////////////////////////////
67
impl<'facet> Partial<'facet> {
68
    /// Returns the current frame count (depth of nesting)
69
    ///
70
    /// The initial frame count is 1 — `begin_field` would push a new frame,
71
    /// bringing it to 2, then `end` would bring it back to `1`.
72
    ///
73
    /// This is an implementation detail of `Partial`, kinda, but deserializers
74
    /// might use this for debug assertions, to make sure the state is what
75
    /// they think it is.
76
    #[inline]
77
    pub fn frame_count(&self) -> usize {
4✔
78
        self.frames.len()
4✔
79
    }
4✔
80

81
    /// Returns the shape of the current frame.
82
    #[inline]
83
    pub fn shape(&self) -> &'static Shape {
11✔
84
        self.frames
11✔
85
            .last()
11✔
86
            .expect("Partial always has at least one frame")
11✔
87
            .shape
11✔
88
    }
11✔
89

90
    /// Pops the current frame off the stack, indicating we're done initializing the current field
91
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
345✔
92
        crate::trace!("end() called");
93
        self.require_active()?;
345✔
94

95
        // Special handling for SmartPointerSlice - convert builder to Arc
96
        if self.frames.len() == 1 {
345✔
97
            if let Tracker::SmartPointerSlice {
98
                vtable,
6✔
99
                building_item,
6✔
100
            } = &self.frames[0].tracker
7✔
101
            {
102
                if *building_item {
6✔
103
                    return Err(ReflectError::OperationFailed {
×
104
                        shape: self.frames[0].shape,
×
105
                        operation: "still building an item, finish it first",
×
106
                    });
×
107
                }
6✔
108

109
                // Convert the builder to Arc<[T]>
110
                let builder_ptr = unsafe { self.frames[0].data.assume_init() };
6✔
111
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
6✔
112

113
                // Update the frame to store the Arc
114
                self.frames[0].data = PtrUninit::new(unsafe {
6✔
115
                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
6✔
116
                });
6✔
117
                self.frames[0].tracker = Tracker::Init;
6✔
118
                // The builder memory has been consumed by convert_fn, so we no longer own it
119
                self.frames[0].ownership = FrameOwnership::ManagedElsewhere;
6✔
120

121
                return Ok(self);
6✔
122
            }
1✔
123
        }
338✔
124

125
        if self.frames.len() <= 1 {
339✔
126
            // Never pop the last/root frame.
127
            return Err(ReflectError::InvariantViolation {
1✔
128
                invariant: "Partial::end() called with only one frame on the stack",
1✔
129
            });
1✔
130
        }
338✔
131

132
        // Require that the top frame is fully initialized before popping.
133
        {
134
            let frame = self.frames.last().unwrap();
338✔
135
            trace!(
136
                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
137
                frame.shape,
138
                frame.tracker.kind()
139
            );
140
            frame.require_full_initialization()?
338✔
141
        }
142

143
        // Pop the frame and save its data pointer for SmartPointer handling
144
        let mut popped_frame = self.frames.pop().unwrap();
336✔
145

146
        // Update parent frame's tracking when popping from a child
147
        let parent_frame = self.frames.last_mut().unwrap();
336✔
148

149
        trace!(
150
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
151
            popped_frame.shape,
152
            popped_frame.tracker.kind(),
153
            parent_frame.shape,
154
            parent_frame.tracker.kind()
155
        );
156

157
        // Check if we need to do a conversion - this happens when:
158
        // 1. The parent frame has an inner type that matches the popped frame's shape
159
        // 2. The parent frame has try_from
160
        // 3. The parent frame is not yet initialized
161
        let needs_conversion = matches!(parent_frame.tracker, Tracker::Uninit)
336✔
162
            && parent_frame.shape.inner.is_some()
4✔
163
            && parent_frame.shape.inner.unwrap() == popped_frame.shape
4✔
NEW
164
            && parent_frame.shape.vtable.try_from.is_some();
×
165

166
        if needs_conversion {
336✔
167
            trace!(
168
                "Detected implicit conversion needed from {} to {}",
169
                popped_frame.shape, parent_frame.shape
170
            );
171
            // Perform the conversion
NEW
172
            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
×
173
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
×
174
                let inner_shape = popped_frame.shape;
×
175

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

179
                if let Err(e) = result {
×
180
                    trace!("Conversion failed: {e:?}");
181

182
                    // Deallocate the inner value's memory since conversion failed
183
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
184
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
185
                            if layout.size() > 0 {
×
186
                                trace!(
187
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
188
                                    layout.size(),
189
                                    layout.align()
190
                                );
191
                                unsafe {
×
192
                                    alloc::alloc::dealloc(
×
193
                                        popped_frame.data.as_mut_byte_ptr(),
×
194
                                        layout,
×
195
                                    );
×
196
                                }
×
197
                            }
×
198
                        }
×
199
                    }
×
200

201
                    return Err(ReflectError::TryFromError {
×
202
                        src_shape: inner_shape,
×
203
                        dst_shape: parent_frame.shape,
×
204
                        inner: e,
×
205
                    });
×
206
                }
×
207

208
                trace!("Conversion succeeded, marking parent as initialized");
209
                parent_frame.tracker = Tracker::Init;
×
210

211
                // Deallocate the inner value's memory since try_from consumed it
212
                if let FrameOwnership::Owned = popped_frame.ownership {
×
213
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
214
                        if layout.size() > 0 {
×
215
                            trace!(
216
                                "Deallocating conversion frame memory: size={}, align={}",
217
                                layout.size(),
218
                                layout.align()
219
                            );
220
                            unsafe {
×
221
                                alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
×
222
                            }
×
223
                        }
×
224
                    }
×
225
                }
×
226

227
                return Ok(self);
×
228
            }
×
229
        }
336✔
230

231
        match &mut parent_frame.tracker {
336✔
232
            Tracker::Struct {
233
                iset,
160✔
234
                current_child,
160✔
235
            } => {
236
                if let Some(idx) = *current_child {
160✔
237
                    iset.set(idx);
160✔
238
                    *current_child = None;
160✔
239
                }
160✔
240
            }
241
            Tracker::Array {
242
                iset,
37✔
243
                current_child,
37✔
244
            } => {
245
                if let Some(idx) = *current_child {
37✔
246
                    iset.set(idx);
37✔
247
                    *current_child = None;
37✔
248
                }
37✔
249
            }
250
            Tracker::SmartPointer { is_initialized } => {
7✔
251
                // We just popped the inner value frame, so now we need to create the smart pointer
252
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
7✔
253
                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
7✔
254
                        return Err(ReflectError::OperationFailed {
×
255
                            shape: parent_frame.shape,
×
256
                            operation: "SmartPointer missing new_into_fn",
×
257
                        });
×
258
                    };
259

260
                    // The child frame contained the inner value
261
                    let inner_ptr = PtrMut::new(unsafe {
7✔
262
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
7✔
263
                    });
264

265
                    // Use new_into_fn to create the Box
266
                    unsafe {
7✔
267
                        new_into_fn(parent_frame.data, inner_ptr);
7✔
268
                    }
7✔
269

270
                    // We just moved out of it
271
                    popped_frame.tracker = Tracker::Uninit;
7✔
272

273
                    // Deallocate the inner value's memory since new_into_fn moved it
274
                    popped_frame.dealloc();
7✔
275

276
                    *is_initialized = true;
7✔
277
                }
×
278
            }
279
            Tracker::Enum {
280
                data,
42✔
281
                current_child,
42✔
282
                ..
283
            } => {
284
                if let Some(idx) = *current_child {
42✔
285
                    data.set(idx);
42✔
286
                    *current_child = None;
42✔
287
                }
42✔
288
            }
289
            Tracker::List {
290
                is_initialized: true,
291
                current_child,
51✔
292
            } => {
293
                if *current_child {
51✔
294
                    // We just popped an element frame, now push it to the list
295
                    if let Def::List(list_def) = parent_frame.shape.def {
51✔
296
                        let Some(push_fn) = list_def.vtable.push else {
51✔
297
                            return Err(ReflectError::OperationFailed {
×
298
                                shape: parent_frame.shape,
×
299
                                operation: "List missing push function",
×
300
                            });
×
301
                        };
302

303
                        // The child frame contained the element value
304
                        let element_ptr = PtrMut::new(unsafe {
51✔
305
                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
51✔
306
                        });
307

308
                        // Use push to add element to the list
309
                        unsafe {
51✔
310
                            push_fn(
51✔
311
                                PtrMut::new(NonNull::new_unchecked(
51✔
312
                                    parent_frame.data.as_mut_byte_ptr(),
51✔
313
                                )),
51✔
314
                                element_ptr,
51✔
315
                            );
51✔
316
                        }
51✔
317

318
                        // Push moved out of popped_frame
319
                        popped_frame.tracker = Tracker::Uninit;
51✔
320
                        popped_frame.dealloc();
51✔
321

322
                        *current_child = false;
51✔
323
                    }
×
324
                }
×
325
            }
326
            Tracker::Map {
327
                is_initialized: true,
328
                insert_state,
19✔
329
            } => {
330
                match insert_state {
19✔
331
                    MapInsertState::PushingKey { key_ptr } => {
11✔
332
                        // We just popped the key frame
333
                        if let Some(key_ptr) = key_ptr {
11✔
334
                            // Transition to PushingValue state
11✔
335
                            *insert_state = MapInsertState::PushingValue {
11✔
336
                                key_ptr: *key_ptr,
11✔
337
                                value_ptr: None,
11✔
338
                            };
11✔
339
                        }
11✔
340
                    }
341
                    MapInsertState::PushingValue { key_ptr, value_ptr } => {
8✔
342
                        // We just popped the value frame, now insert the pair
343
                        if let (Some(value_ptr), Def::Map(map_def)) =
8✔
344
                            (value_ptr, parent_frame.shape.def)
8✔
345
                        {
346
                            let insert_fn = map_def.vtable.insert_fn;
8✔
347

348
                            // Use insert to add key-value pair to the map
349
                            unsafe {
8✔
350
                                insert_fn(
8✔
351
                                    PtrMut::new(NonNull::new_unchecked(
8✔
352
                                        parent_frame.data.as_mut_byte_ptr(),
8✔
353
                                    )),
8✔
354
                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
8✔
355
                                    PtrMut::new(NonNull::new_unchecked(
8✔
356
                                        value_ptr.as_mut_byte_ptr(),
8✔
357
                                    )),
8✔
358
                                );
8✔
359
                            }
8✔
360

361
                            // Note: We don't deallocate the key and value memory here.
362
                            // The insert function has semantically moved the values into the map,
363
                            // but we still need to deallocate the temporary buffers.
364
                            // However, since we don't have frames for them anymore (they were popped),
365
                            // we need to handle deallocation here.
366
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
8✔
367
                                if key_shape.size() > 0 {
8✔
368
                                    unsafe {
8✔
369
                                        alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
8✔
370
                                    }
8✔
371
                                }
×
372
                            }
×
373
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
8✔
374
                                if value_shape.size() > 0 {
8✔
375
                                    unsafe {
8✔
376
                                        alloc::alloc::dealloc(
8✔
377
                                            value_ptr.as_mut_byte_ptr(),
8✔
378
                                            value_shape,
8✔
379
                                        );
8✔
380
                                    }
8✔
381
                                }
×
382
                            }
×
383

384
                            // Reset to idle state
385
                            *insert_state = MapInsertState::Idle;
8✔
386
                        }
×
387
                    }
388
                    MapInsertState::Idle => {
×
389
                        // Nothing to do
×
390
                    }
×
391
                }
392
            }
393
            Tracker::Option { building_inner } => {
1✔
394
                // We just popped the inner value frame for an Option's Some variant
395
                if *building_inner {
1✔
396
                    if let Def::Option(option_def) = parent_frame.shape.def {
1✔
397
                        // Use the Option vtable to initialize Some(inner_value)
398
                        let init_some_fn = option_def.vtable.init_some_fn;
1✔
399

400
                        // The popped frame contains the inner value
401
                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
1✔
402

403
                        // Initialize the Option as Some(inner_value)
404
                        unsafe {
1✔
405
                            init_some_fn(parent_frame.data, inner_value_ptr);
1✔
406
                        }
1✔
407

408
                        // Deallocate the inner value's memory since init_some_fn moved it
409
                        if let FrameOwnership::Owned = popped_frame.ownership {
1✔
410
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
1✔
411
                                if layout.size() > 0 {
1✔
412
                                    unsafe {
1✔
413
                                        alloc::alloc::dealloc(
1✔
414
                                            popped_frame.data.as_mut_byte_ptr(),
1✔
415
                                            layout,
1✔
416
                                        );
1✔
417
                                    }
1✔
418
                                }
×
419
                            }
×
420
                        }
×
421

422
                        // Mark that we're no longer building the inner value
423
                        *building_inner = false;
1✔
424
                    } else {
425
                        return Err(ReflectError::OperationFailed {
×
426
                            shape: parent_frame.shape,
×
427
                            operation: "Option frame without Option definition",
×
428
                        });
×
429
                    }
430
                }
×
431
            }
432
            Tracker::Uninit | Tracker::Init => {
433
                // the main case here is: the popped frame was a `String` and the
434
                // parent frame is an `Arc<str>`, `Box<str>` etc.
435
                match &parent_frame.shape.def {
5✔
436
                    Def::Pointer(smart_ptr_def) => {
5✔
437
                        let pointee =
5✔
438
                            smart_ptr_def
5✔
439
                                .pointee()
5✔
440
                                .ok_or(ReflectError::InvariantViolation {
5✔
441
                                    invariant: "pointer type doesn't have a pointee",
5✔
442
                                })?;
5✔
443

444
                        if !pointee.is_shape(str::SHAPE) {
5✔
445
                            return Err(ReflectError::InvariantViolation {
×
446
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
447
                            });
×
448
                        }
5✔
449

450
                        if !popped_frame.shape.is_shape(String::SHAPE) {
5✔
451
                            return Err(ReflectError::InvariantViolation {
×
452
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
453
                            });
×
454
                        }
5✔
455

456
                        popped_frame.require_full_initialization()?;
5✔
457

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

465
                        let Some(known) = smart_ptr_def.known else {
5✔
466
                            return Err(ReflectError::OperationFailed {
×
467
                                shape: parent_shape,
×
468
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
469
                            });
×
470
                        };
471

472
                        parent_frame.deinit();
5✔
473

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

478
                        match known {
5✔
479
                            KnownPointer::Box => {
480
                                let boxed: Box<str> = string_value.into_boxed_str();
1✔
481
                                unsafe {
1✔
482
                                    core::ptr::write(
1✔
483
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1✔
484
                                        boxed,
1✔
485
                                    );
1✔
486
                                }
1✔
487
                            }
488
                            KnownPointer::Arc => {
489
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1✔
490
                                unsafe {
1✔
491
                                    core::ptr::write(
1✔
492
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1✔
493
                                        arc,
1✔
494
                                    );
1✔
495
                                }
1✔
496
                            }
497
                            KnownPointer::Rc => {
498
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
3✔
499
                                unsafe {
3✔
500
                                    core::ptr::write(
3✔
501
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
3✔
502
                                        rc,
3✔
503
                                    );
3✔
504
                                }
3✔
505
                            }
506
                            _ => {
507
                                return Err(ReflectError::OperationFailed {
×
508
                                    shape: parent_shape,
×
509
                                    operation: "Don't know how to build this pointer type",
×
510
                                });
×
511
                            }
512
                        }
513

514
                        parent_frame.tracker = Tracker::Init;
5✔
515

516
                        popped_frame.tracker = Tracker::Uninit;
5✔
517
                        popped_frame.dealloc();
5✔
518
                    }
519
                    _ => {
520
                        unreachable!(
×
521
                            "we popped a frame and parent was Init or Uninit, but it wasn't a smart pointer and... there's no way this should happen normally"
522
                        )
523
                    }
524
                }
525
            }
526
            Tracker::SmartPointerSlice {
527
                vtable,
14✔
528
                building_item,
14✔
529
            } => {
530
                if *building_item {
14✔
531
                    // We just popped an element frame, now push it to the slice builder
532
                    let element_ptr = PtrMut::new(unsafe {
14✔
533
                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
14✔
534
                    });
535

536
                    // Use the slice builder's push_fn to add the element
537
                    crate::trace!("Pushing element to slice builder");
538
                    unsafe {
14✔
539
                        let parent_ptr = parent_frame.data.assume_init();
14✔
540
                        (vtable.push_fn)(parent_ptr, element_ptr);
14✔
541
                    }
14✔
542

543
                    popped_frame.tracker = Tracker::Uninit;
14✔
544
                    popped_frame.dealloc();
14✔
545

546
                    if let Tracker::SmartPointerSlice {
547
                        building_item: bi, ..
14✔
548
                    } = &mut parent_frame.tracker
14✔
549
                    {
14✔
550
                        *bi = false;
14✔
551
                    }
14✔
552
                }
×
553
            }
554
            _ => {}
×
555
        }
556

557
        Ok(self)
336✔
558
    }
345✔
559

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

565
        let mut path_components = Vec::new();
×
566
        // The stack of enum/struct/sequence names currently in context.
567
        // Start from root and build upwards.
568
        for (i, frame) in self.frames.iter().enumerate() {
×
569
            match frame.shape.ty {
×
570
                Type::User(user_type) => match user_type {
×
571
                    UserType::Struct(struct_type) => {
×
572
                        // Try to get currently active field index
573
                        let mut field_str = None;
×
574
                        if let Tracker::Struct {
575
                            current_child: Some(idx),
×
576
                            ..
577
                        } = &frame.tracker
×
578
                        {
579
                            if let Some(field) = struct_type.fields.get(*idx) {
×
580
                                field_str = Some(field.name);
×
581
                            }
×
582
                        }
×
583
                        if i == 0 {
×
584
                            // Use Display for the root struct shape
×
585
                            path_components.push(format!("{}", frame.shape));
×
586
                        }
×
587
                        if let Some(field_name) = field_str {
×
588
                            path_components.push(format!(".{field_name}"));
×
589
                        }
×
590
                    }
591
                    UserType::Enum(_enum_type) => {
×
592
                        // Try to get currently active variant and field
593
                        if let Tracker::Enum {
594
                            variant,
×
595
                            current_child,
×
596
                            ..
597
                        } = &frame.tracker
×
598
                        {
599
                            if i == 0 {
×
600
                                // Use Display for the root enum shape
×
601
                                path_components.push(format!("{}", frame.shape));
×
602
                            }
×
603
                            path_components.push(format!("::{}", variant.name));
×
604
                            if let Some(idx) = *current_child {
×
605
                                if let Some(field) = variant.data.fields.get(idx) {
×
606
                                    path_components.push(format!(".{}", field.name));
×
607
                                }
×
608
                            }
×
609
                        } else if i == 0 {
×
610
                            // just the enum display
×
611
                            path_components.push(format!("{}", frame.shape));
×
612
                        }
×
613
                    }
614
                    UserType::Union(_union_type) => {
×
615
                        path_components.push(format!("{}", frame.shape));
×
616
                    }
×
617
                    UserType::Opaque => {
×
618
                        path_components.push("<opaque>".to_string());
×
619
                    }
×
620
                },
621
                Type::Sequence(seq_type) => match seq_type {
×
622
                    facet_core::SequenceType::Array(_array_def) => {
×
623
                        // Try to show current element index
624
                        if let Tracker::Array {
625
                            current_child: Some(idx),
×
626
                            ..
627
                        } = &frame.tracker
×
628
                        {
×
629
                            path_components.push(format!("[{idx}]"));
×
630
                        }
×
631
                    }
632
                    // You can add more for Slice, Vec, etc., if applicable
633
                    _ => {
×
634
                        // just indicate "[]" for sequence
×
635
                        path_components.push("[]".to_string());
×
636
                    }
×
637
                },
638
                Type::Pointer(_) => {
×
639
                    // Indicate deref
×
640
                    path_components.push("*".to_string());
×
641
                }
×
642
                _ => {
×
643
                    // No structural path
×
644
                }
×
645
            }
646
        }
647
        // Merge the path_components into a single string
648
        for component in path_components {
×
649
            out.push_str(&component);
×
650
        }
×
651
        out
×
652
    }
×
653
}
654

655
////////////////////////////////////////////////////////////////////////////////////////////////////
656
// Build
657
////////////////////////////////////////////////////////////////////////////////////////////////////
658
impl<'facet> Partial<'facet> {
659
    /// Builds the value
660
    pub fn build(&mut self) -> Result<HeapValue<'facet>, ReflectError> {
158✔
661
        self.require_active()?;
158✔
662
        if self.frames.len() != 1 {
158✔
663
            self.state = PartialState::BuildFailed;
2✔
664
            return Err(ReflectError::InvariantViolation {
2✔
665
                invariant: "Partial::build() expects a single frame — call end() until that's the case",
2✔
666
            });
2✔
667
        }
156✔
668

669
        let frame = self.frames.pop().unwrap();
156✔
670

671
        // Check initialization before proceeding
672
        if let Err(e) = frame.require_full_initialization() {
156✔
673
            // Put the frame back so Drop can handle cleanup properly
674
            self.frames.push(frame);
26✔
675
            self.state = PartialState::BuildFailed;
26✔
676
            return Err(e);
26✔
677
        }
130✔
678

679
        // Check invariants if present
680
        if let Some(invariants_fn) = frame.shape.vtable.invariants {
130✔
681
            // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
682
            let value_ptr = unsafe { frame.data.assume_init().as_const() };
6✔
683
            let invariants_ok = unsafe { invariants_fn(value_ptr) };
6✔
684

685
            if !invariants_ok {
6✔
686
                // Put the frame back so Drop can handle cleanup properly
687
                self.frames.push(frame);
3✔
688
                self.state = PartialState::BuildFailed;
3✔
689
                return Err(ReflectError::InvariantViolation {
3✔
690
                    invariant: "Type invariants check failed",
3✔
691
                });
3✔
692
            }
3✔
693
        }
124✔
694

695
        // Mark as built to prevent reuse
696
        self.state = PartialState::Built;
127✔
697

698
        match frame
127✔
699
            .shape
127✔
700
            .layout
127✔
701
            .sized_layout()
127✔
702
            .map_err(|_layout_err| ReflectError::Unsized {
127✔
703
                shape: frame.shape,
×
704
                operation: "build (final check for sized layout)",
705
            }) {
×
706
            Ok(layout) => Ok(HeapValue {
127✔
707
                guard: Some(Guard {
127✔
708
                    ptr: unsafe { NonNull::new_unchecked(frame.data.as_mut_byte_ptr()) },
127✔
709
                    layout,
127✔
710
                }),
127✔
711
                shape: frame.shape,
127✔
712
                phantom: PhantomData,
127✔
713
            }),
127✔
714
            Err(e) => {
×
715
                // Put the frame back for proper cleanup
716
                self.frames.push(frame);
×
717
                self.state = PartialState::BuildFailed;
×
718
                Err(e)
×
719
            }
720
        }
721
    }
158✔
722
}
723

724
////////////////////////////////////////////////////////////////////////////////////////////////////
725
// `Set` and set helpers
726
////////////////////////////////////////////////////////////////////////////////////////////////////
727
impl<'facet> Partial<'facet> {
728
    /// Sets a value wholesale into the current frame.
729
    ///
730
    /// If the current frame was already initialized, the previous value is
731
    /// dropped. If it was partially initialized, the fields that were initialized
732
    /// are dropped, etc.
733
    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
313✔
734
    where
313✔
735
        U: Facet<'facet>,
313✔
736
    {
737
        self.require_active()?;
313✔
738
        struct DropVal<U> {
739
            ptr: *mut U,
740
        }
741
        impl<U> Drop for DropVal<U> {
742
            #[inline]
743
            fn drop(&mut self) {
1✔
744
                unsafe { core::ptr::drop_in_place(self.ptr) };
1✔
745
            }
1✔
746
        }
747

748
        let mut value = ManuallyDrop::new(value);
313✔
749
        let drop = DropVal {
313✔
750
            ptr: (&mut value) as *mut ManuallyDrop<U> as *mut U,
313✔
751
        };
313✔
752

753
        let ptr_const = PtrConst::new(unsafe { NonNull::new_unchecked(drop.ptr) });
313✔
754
        unsafe {
755
            // Safety: We are calling set_shape with a valid shape and a valid pointer
756
            self.set_shape(ptr_const, U::SHAPE)?
313✔
757
        };
758
        core::mem::forget(drop);
312✔
759

760
        Ok(self)
312✔
761
    }
313✔
762

763
    /// Sets a value into the current frame by [PtrConst] / [Shape].
764
    ///
765
    /// # Safety
766
    ///
767
    /// The caller must ensure that `src_value` points to a valid instance of a value
768
    /// whose memory layout and type matches `src_shape`, and that this value can be
769
    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
770
    ///
771
    /// After a successful call, the ownership of the value at `src_value` is effectively moved
772
    /// into the Partial (i.e., the destination), and the original value should not be used
773
    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
774
    ///
775
    /// If an error is returned, the destination remains unmodified and safe for future operations.
776
    #[inline]
777
    pub unsafe fn set_shape(
313✔
778
        &mut self,
313✔
779
        src_value: PtrConst<'_>,
313✔
780
        src_shape: &'static Shape,
313✔
781
    ) -> Result<&mut Self, ReflectError> {
313✔
782
        self.require_active()?;
313✔
783

784
        let fr = self.frames.last_mut().unwrap();
313✔
785
        crate::trace!("set_shape({src_shape:?})");
786

787
        if !fr.shape.is_shape(src_shape) {
313✔
788
            return Err(ReflectError::WrongShape {
1✔
789
                expected: fr.shape,
1✔
790
                actual: src_shape,
1✔
791
            });
1✔
792
        }
312✔
793

794
        fr.deinit();
312✔
795

796
        // SAFETY: `fr.shape` and `src_shape` are the same, so they have the same size,
797
        // and the preconditions for this function are that `src_value` is fully intialized.
798
        unsafe {
312✔
799
            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
312✔
800
            // which is not possible for `Partial`
312✔
801
            fr.data.copy_from(src_value, fr.shape).unwrap();
312✔
802
        }
312✔
803

804
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
805
        unsafe {
312✔
806
            fr.mark_as_init();
312✔
807
        }
312✔
808

809
        Ok(self)
312✔
810
    }
313✔
811

812
    /// Sets the current frame using a function that initializes the value
813
    ///
814
    /// # Safety
815
    ///
816
    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
817
    /// value of the right type.
818
    ///
819
    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
820
    /// there is no need to drop it in place.
821
    pub unsafe fn set_from_function<F>(&mut self, f: F) -> Result<&mut Self, ReflectError>
7✔
822
    where
7✔
823
        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
7✔
824
    {
825
        self.require_active()?;
7✔
826
        let frame = self.frames.last_mut().unwrap();
7✔
827

828
        frame.deinit();
7✔
829
        f(frame.data)?;
7✔
830

831
        // safety: `f()` returned Ok, so `frame.data` must be initialized
832
        unsafe {
7✔
833
            frame.mark_as_init();
7✔
834
        }
7✔
835

836
        Ok(self)
7✔
837
    }
7✔
838

839
    /// Sets the current frame to its default value using `default_in_place` from the
840
    /// vtable.
841
    ///
842
    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
843
    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
844
    /// for `field`.
845
    ///
846
    /// If the current frame's shape does not implement `Default`, then this returns an error.
847
    #[inline]
848
    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
6✔
849
        let frame = self.frames.last().unwrap();
6✔
850

851
        let Some(default_fn) = frame.shape.vtable.default_in_place else {
6✔
852
            return Err(ReflectError::OperationFailed {
1✔
853
                shape: frame.shape,
1✔
854
                operation: "type does not implement Default",
1✔
855
            });
1✔
856
        };
857

858
        // SAFETY: `default_fn` fully initializes the passed pointer. we took it
859
        // from the vtable of `frame.shape`.
860
        unsafe {
861
            self.set_from_function(move |ptr| {
5✔
862
                default_fn(ptr);
5✔
863
                Ok(())
5✔
864
            })
5✔
865
        }
866
    }
6✔
867

868
    /// Copy a value from a Peek into the current frame.
869
    ///
870
    /// # Invariants
871
    ///
872
    /// `peek` must be a thin pointer, otherwise this panics.
873
    ///
874
    /// # Safety
875
    ///
876
    /// If this succeeds, the value `Peek` points to has been moved out of, and
877
    /// as such, should not be dropped (but should be deallocated).
878
    pub unsafe fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
879
        self.require_active()?;
×
880

881
        // Get the source value's pointer and shape
882
        let src_ptr = peek.data();
×
883
        let src_shape = peek.shape();
×
884

885
        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
886
        unsafe { self.set_shape(src_ptr, src_shape) }
×
887
    }
×
888

889
    /// Parses a string value into the current frame using the type's ParseFn from the vtable.
890
    ///
891
    /// If the current frame was previously initialized, its contents are dropped in place.
892
    pub fn parse_from_str(&mut self, s: &str) -> Result<&mut Self, ReflectError> {
2✔
893
        self.require_active()?;
2✔
894

895
        let frame = self.frames.last_mut().unwrap();
2✔
896

897
        // Check if the type has a parse function
898
        let Some(parse_fn) = frame.shape.vtable.parse else {
2✔
899
            return Err(ReflectError::OperationFailed {
×
900
                shape: frame.shape,
×
901
                operation: "Type does not support parsing from string",
×
902
            });
×
903
        };
904

905
        // Note: deinit leaves us in `Tracker::Uninit` state which is valid even if we error out.
906
        frame.deinit();
2✔
907

908
        // Parse the string value using the type's parse function
909
        let result = unsafe { parse_fn(s, frame.data) };
2✔
910
        if let Err(_pe) = result {
2✔
911
            // TODO: can we propagate the ParseError somehow?
912
            return Err(ReflectError::OperationFailed {
1✔
913
                shape: frame.shape,
1✔
914
                operation: "Failed to parse string value",
1✔
915
            });
1✔
916
        }
1✔
917

918
        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
919
        unsafe {
1✔
920
            frame.mark_as_init();
1✔
921
        }
1✔
922
        Ok(self)
1✔
923
    }
2✔
924
}
925

926
////////////////////////////////////////////////////////////////////////////////////////////////////
927
// Enum variant selection
928
////////////////////////////////////////////////////////////////////////////////////////////////////
929
impl<'facet> Partial<'facet> {
930
    /// Get the currently selected variant for an enum
931
    pub fn selected_variant(&self) -> Option<Variant> {
×
932
        let frame = self.frames.last()?;
×
933

934
        match &frame.tracker {
×
935
            Tracker::Enum { variant, .. } => Some(**variant),
×
936
            _ => None,
×
937
        }
938
    }
×
939

940
    /// Find a variant by name in the current enum
941
    pub fn find_variant(&self, variant_name: &str) -> Option<(usize, &'static Variant)> {
×
942
        let frame = self.frames.last()?;
×
943

944
        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
×
945
            enum_def
×
946
                .variants
×
947
                .iter()
×
948
                .enumerate()
×
949
                .find(|(_, v)| v.name == variant_name)
×
950
        } else {
951
            None
×
952
        }
953
    }
×
954

955
    /// Assuming the current frame is an enum, this selects a variant by index
956
    /// (0-based, in declaration order).
957
    ///
958
    /// For example:
959
    ///
960
    /// ```rust,no_run
961
    /// enum E { A, B, C }
962
    /// ```
963
    ///
964
    /// Calling `select_nth_variant(2)` would select variant `C`.
965
    ///
966
    /// This will return an error if the current frame is anything other than fully-uninitialized.
967
    /// In other words, it's not possible to "switch to a different variant" once you've selected one.
968
    ///
969
    /// This does _not_ push a frame on the stack.
970
    pub fn select_nth_variant(&mut self, index: usize) -> Result<&mut Self, ReflectError> {
2✔
971
        self.require_active()?;
2✔
972

973
        let frame = self.frames.last().unwrap();
2✔
974
        let enum_type = frame.get_enum_type()?;
2✔
975

976
        if index >= enum_type.variants.len() {
2✔
977
            return Err(ReflectError::OperationFailed {
×
978
                shape: frame.shape,
×
979
                operation: "variant index out of bounds",
×
980
            });
×
981
        }
2✔
982
        let variant = &enum_type.variants[index];
2✔
983

984
        self.select_variant_internal(&enum_type, variant)?;
2✔
985
        Ok(self)
2✔
986
    }
2✔
987

988
    /// Pushes a variant for enum initialization by name
989
    ///
990
    /// See [Self::select_nth_variant] for more notes.
991
    pub fn select_variant_named(&mut self, variant_name: &str) -> Result<&mut Self, ReflectError> {
30✔
992
        self.require_active()?;
30✔
993

994
        let frame = self.frames.last_mut().unwrap();
30✔
995
        let enum_type = frame.get_enum_type()?;
30✔
996

997
        let Some(variant) = enum_type.variants.iter().find(|v| v.name == variant_name) else {
69✔
998
            return Err(ReflectError::OperationFailed {
2✔
999
                shape: frame.shape,
2✔
1000
                operation: "No variant found with the given name",
2✔
1001
            });
2✔
1002
        };
1003

1004
        self.select_variant_internal(&enum_type, variant)?;
28✔
1005
        Ok(self)
28✔
1006
    }
30✔
1007

1008
    /// Selects a given enum variant by discriminant. If none of the variants
1009
    /// of the frame's enum have that discriminant, this returns an error.
1010
    ///
1011
    /// See [Self::select_nth_variant] for more notes.
1012
    pub fn select_variant(&mut self, discriminant: i64) -> Result<&mut Self, ReflectError> {
8✔
1013
        self.require_active()?;
8✔
1014

1015
        // Check all invariants early before making any changes
1016
        let frame = self.frames.last().unwrap();
8✔
1017

1018
        // Check that we're dealing with an enum
1019
        let enum_type = match frame.shape.ty {
8✔
1020
            Type::User(UserType::Enum(e)) => e,
8✔
1021
            _ => {
1022
                return Err(ReflectError::WasNotA {
×
1023
                    expected: "enum",
×
1024
                    actual: frame.shape,
×
1025
                });
×
1026
            }
1027
        };
1028

1029
        // Find the variant with the matching discriminant
1030
        let Some(variant) = enum_type
8✔
1031
            .variants
8✔
1032
            .iter()
8✔
1033
            .find(|v| v.discriminant == Some(discriminant))
12✔
1034
        else {
1035
            return Err(ReflectError::OperationFailed {
×
1036
                shape: frame.shape,
×
1037
                operation: "No variant found with the given discriminant",
×
1038
            });
×
1039
        };
1040

1041
        // Update the frame tracker to select the variant
1042
        self.select_variant_internal(&enum_type, variant)?;
8✔
1043

1044
        Ok(self)
8✔
1045
    }
8✔
1046
}
1047

1048
////////////////////////////////////////////////////////////////////////////////////////////////////
1049
// Field selection
1050
////////////////////////////////////////////////////////////////////////////////////////////////////
1051
impl Partial<'_> {
1052
    /// Find the index of a field by name in the current struct
1053
    ///
1054
    /// If the current frame isn't a struct or an enum (with a selected variant)
1055
    /// then this returns `None` for sure.
1056
    pub fn field_index(&self, field_name: &str) -> Option<usize> {
×
1057
        let frame = self.frames.last()?;
×
1058

1059
        match frame.shape.ty {
×
1060
            Type::User(UserType::Struct(struct_def)) => {
×
1061
                struct_def.fields.iter().position(|f| f.name == field_name)
×
1062
            }
1063
            Type::User(UserType::Enum(_)) => {
1064
                // If we're in an enum variant, check its fields
1065
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
1066
                    variant
×
1067
                        .data
×
1068
                        .fields
×
1069
                        .iter()
×
1070
                        .position(|f| f.name == field_name)
×
1071
                } else {
1072
                    None
×
1073
                }
1074
            }
1075
            _ => None,
×
1076
        }
1077
    }
×
1078

1079
    /// Check if a struct field at the given index has been set
1080
    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
22✔
1081
        let frame = self.frames.last().ok_or(ReflectError::NoActiveFrame)?;
22✔
1082

1083
        match &frame.tracker {
22✔
1084
            Tracker::Uninit => Ok(false),
13✔
1085
            Tracker::Init => Ok(true),
2✔
1086
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
7✔
1087
            Tracker::Enum { data, variant, .. } => {
×
1088
                // Check if the field is already marked as set
1089
                if data.get(index) {
×
1090
                    return Ok(true);
×
1091
                }
×
1092

1093
                // For enum variant fields that are empty structs, they are always initialized
1094
                if let Some(field) = variant.data.fields.get(index) {
×
NEW
1095
                    if let Type::User(UserType::Struct(field_struct)) = field.shape().ty {
×
1096
                        if field_struct.fields.is_empty() {
×
1097
                            return Ok(true);
×
1098
                        }
×
1099
                    }
×
1100
                }
×
1101

1102
                Ok(false)
×
1103
            }
1104
            Tracker::Option { building_inner } => {
×
1105
                // For Options, index 0 represents the inner value
1106
                if index == 0 {
×
1107
                    Ok(!building_inner)
×
1108
                } else {
1109
                    Err(ReflectError::InvalidOperation {
×
1110
                        operation: "is_field_set",
×
1111
                        reason: "Option only has one field (index 0)",
×
1112
                    })
×
1113
                }
1114
            }
1115
            _ => Err(ReflectError::InvalidOperation {
×
1116
                operation: "is_field_set",
×
1117
                reason: "Current frame is not a struct, enum variant, or option",
×
1118
            }),
×
1119
        }
1120
    }
22✔
1121

1122
    /// Selects a field (by name) of a struct or enum data.
1123
    ///
1124
    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
1125
    /// and friends.
1126
    pub fn begin_field(&mut self, field_name: &str) -> Result<&mut Self, ReflectError> {
162✔
1127
        self.require_active()?;
162✔
1128

1129
        let frame = self.frames.last().unwrap();
162✔
1130
        let fields = self.get_fields()?;
162✔
1131
        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
239✔
1132
            return Err(ReflectError::FieldError {
3✔
1133
                shape: frame.shape,
3✔
1134
                field_error: facet_core::FieldError::NoSuchField,
3✔
1135
            });
3✔
1136
        };
1137
        self.begin_nth_field(idx)
157✔
1138
    }
162✔
1139

1140
    /// Begins the nth field of a struct, enum variant, or array, by index.
1141
    ///
1142
    /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
1143
    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
256✔
1144
        self.require_active()?;
256✔
1145
        let frame = self.frames.last_mut().unwrap();
256✔
1146

1147
        let next_frame = match frame.shape.ty {
256✔
1148
            Type::User(user_type) => match user_type {
218✔
1149
                UserType::Struct(struct_type) => {
176✔
1150
                    Self::begin_nth_struct_field(frame, struct_type, idx)?
176✔
1151
                }
1152
                UserType::Enum(_) => {
1153
                    // Check if we have a variant selected
1154
                    match &frame.tracker {
42✔
1155
                        Tracker::Enum { variant, .. } => {
42✔
1156
                            Self::begin_nth_enum_field(frame, variant, idx)?
42✔
1157
                        }
1158
                        _ => {
1159
                            return Err(ReflectError::OperationFailed {
×
1160
                                shape: frame.shape,
×
1161
                                operation: "must call select_variant before selecting enum fields",
×
1162
                            });
×
1163
                        }
1164
                    }
1165
                }
1166
                UserType::Union(_) => {
1167
                    return Err(ReflectError::OperationFailed {
×
1168
                        shape: frame.shape,
×
1169
                        operation: "cannot select a field from a union",
×
1170
                    });
×
1171
                }
1172
                UserType::Opaque => {
1173
                    return Err(ReflectError::OperationFailed {
×
1174
                        shape: frame.shape,
×
1175
                        operation: "cannot select a field from an opaque type",
×
1176
                    });
×
1177
                }
1178
            },
1179
            Type::Sequence(sequence_type) => match sequence_type {
38✔
1180
                SequenceType::Array(array_type) => {
38✔
1181
                    Self::begin_nth_array_element(frame, array_type, idx)?
38✔
1182
                }
1183
                SequenceType::Slice(_) => {
1184
                    return Err(ReflectError::OperationFailed {
×
1185
                        shape: frame.shape,
×
1186
                        operation: "cannot select a field from slices yet",
×
1187
                    });
×
1188
                }
1189
            },
1190
            _ => {
1191
                return Err(ReflectError::OperationFailed {
×
1192
                    shape: frame.shape,
×
1193
                    operation: "cannot select a field from this type",
×
1194
                });
×
1195
            }
1196
        };
1197

1198
        self.frames.push(next_frame);
255✔
1199
        Ok(self)
255✔
1200
    }
256✔
1201

1202
    /// Sets the given field to its default value, preferring:
1203
    ///
1204
    ///   * A `default = some_fn()` function
1205
    ///   * The field's `Default` implementation if any
1206
    ///
1207
    /// But without going all the way up to the parent struct's `Default` impl.
1208
    ///
1209
    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
1210
    pub fn set_nth_field_to_default(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
×
1211
        self.require_active()?;
×
1212

1213
        let frame = self.frames.last().unwrap();
×
1214
        let fields = self.get_fields()?;
×
1215

1216
        if idx >= fields.len() {
×
1217
            return Err(ReflectError::OperationFailed {
×
1218
                shape: frame.shape,
×
1219
                operation: "field index out of bounds",
×
1220
            });
×
1221
        }
×
1222

1223
        let field = fields[idx];
×
1224

1225
        // Check for field-level default function first, then type-level default
1226
        if let Some(field_default_fn) = field.vtable.default_fn {
×
1227
            self.begin_nth_field(idx)?;
×
1228
            // the field default fn should be well-behaved
1229
            unsafe {
1230
                self.set_from_function(|ptr| {
×
1231
                    field_default_fn(ptr);
×
1232
                    Ok(())
×
1233
                })?;
×
1234
            }
1235
            self.end()
×
1236
        } else if field.shape().is(Characteristic::Default) {
×
1237
            self.begin_nth_field(idx)?;
×
1238
            self.set_default()?;
×
1239
            self.end()
×
1240
        } else {
1241
            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
1242
                shape: field.shape(),
×
1243
            });
×
1244
        }
1245
    }
×
1246

1247
    /// Given a `Partial` for the same shape, and assuming that partial has the nth
1248
    /// field initialized, move the value from `src` to `self`, marking it as deinitialized
1249
    /// in `src`.
1250
    pub fn steal_nth_field(
2✔
1251
        &mut self,
2✔
1252
        src: &mut Partial,
2✔
1253
        field_index: usize,
2✔
1254
    ) -> Result<&mut Self, ReflectError> {
2✔
1255
        let dst_shape = self.shape();
2✔
1256
        let src_shape = src.shape();
2✔
1257
        if dst_shape != src_shape {
2✔
1258
            return Err(ReflectError::HeistCancelledDifferentShapes {
×
1259
                src_shape,
×
1260
                dst_shape,
×
1261
            });
×
1262
        }
2✔
1263

1264
        // FIXME: what about enums? we don't check that the right variant is
1265
        // selected here.
1266
        if !src.is_field_set(field_index)? {
2✔
1267
            return Err(ReflectError::InvariantViolation {
×
1268
                invariant: "stolen field must be initialized",
×
1269
            });
×
1270
        }
2✔
1271

1272
        let maybe_fields = match src_shape.ty {
2✔
1273
            Type::Primitive(_primitive_type) => None,
×
1274
            Type::Sequence(_sequence_type) => None,
×
1275
            Type::User(user_type) => match user_type {
2✔
1276
                UserType::Struct(struct_type) => Some(struct_type.fields),
2✔
1277
                UserType::Enum(_enum_type) => match self.selected_variant() {
×
1278
                    Some(variant) => Some(variant.data.fields),
×
1279
                    None => {
1280
                        return Err(ReflectError::InvariantViolation {
×
1281
                            invariant: "enum field thief must have variant selected",
×
1282
                        });
×
1283
                    }
1284
                },
1285
                UserType::Union(_union_type) => None,
×
1286
                UserType::Opaque => None,
×
1287
            },
1288
            Type::Pointer(_pointer_type) => None,
×
1289
        };
1290

1291
        let Some(fields) = maybe_fields else {
2✔
1292
            return Err(ReflectError::OperationFailed {
×
1293
                shape: src_shape,
×
1294
                operation: "fetching field list for steal_nth_field",
×
1295
            });
×
1296
        };
1297

1298
        if field_index >= fields.len() {
2✔
1299
            return Err(ReflectError::OperationFailed {
×
1300
                shape: src_shape,
×
1301
                operation: "field index out of bounds",
×
1302
            });
×
1303
        }
2✔
1304
        let field = fields[field_index];
2✔
1305

1306
        let src_frame = src.frames.last_mut().unwrap();
2✔
1307

1308
        self.begin_nth_field(field_index)?;
2✔
1309
        unsafe {
1310
            self.set_from_function(|dst_field_ptr| {
2✔
1311
                let src_field_ptr = src_frame.data.field_init_at(field.offset).as_const();
2✔
1312
                dst_field_ptr
2✔
1313
                    .copy_from(src_field_ptr, field.shape())
2✔
1314
                    .unwrap();
2✔
1315
                Ok(())
2✔
1316
            })?;
2✔
1317
        }
1318
        self.end()?;
2✔
1319

1320
        // now mark field as uninitialized in `src`
1321
        match &mut src_frame.tracker {
2✔
1322
            Tracker::Uninit => {
1323
                unreachable!("we just stole a field from src, it couldn't have been fully uninit")
×
1324
            }
1325
            Tracker::Init => {
1326
                // all struct fields were init so we don't even have a struct tracker,
1327
                // let's make one!
1328
                let mut iset = ISet::new(fields.len());
1✔
1329
                iset.set_all();
1✔
1330
                iset.unset(field_index);
1✔
1331
                src_frame.tracker = Tracker::Struct {
1✔
1332
                    iset,
1✔
1333
                    current_child: None,
1✔
1334
                }
1✔
1335
            }
1336
            Tracker::Array { .. } => unreachable!("can't steal fields from arrays"),
×
1337
            Tracker::Struct { iset, .. } => {
1✔
1338
                iset.unset(field_index);
1✔
1339
            }
1✔
1340
            Tracker::SmartPointer { .. } => {
1341
                unreachable!("can't steal fields from smart pointers")
×
1342
            }
1343
            Tracker::SmartPointerSlice { .. } => {
1344
                unreachable!("can't steal fields from smart pointer slices")
×
1345
            }
1346
            Tracker::Enum { data, .. } => {
×
1347
                data.unset(field_index);
×
1348
            }
×
1349
            Tracker::List { .. } => {
1350
                unreachable!("can't steal fields from lists")
×
1351
            }
1352
            Tracker::Map { .. } => {
1353
                unreachable!("can't steal fields from maps")
×
1354
            }
1355
            Tracker::Option { .. } => {
1356
                unreachable!("can't steal fields from options")
×
1357
            }
1358
        }
1359

1360
        Ok(self)
2✔
1361
    }
2✔
1362
}
1363

1364
////////////////////////////////////////////////////////////////////////////////////////////////////
1365
// Smart pointers
1366
////////////////////////////////////////////////////////////////////////////////////////////////////
1367
impl Partial<'_> {
1368
    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
1369
    pub fn begin_smart_ptr(&mut self) -> Result<&mut Self, ReflectError> {
21✔
1370
        crate::trace!("begin_smart_ptr()");
1371
        self.require_active()?;
21✔
1372
        let frame = self.frames.last_mut().unwrap();
21✔
1373

1374
        // Check that we have a SmartPointer
1375
        match &frame.shape.def {
21✔
1376
            Def::Pointer(smart_ptr_def) => {
21✔
1377
                // Check for supported smart pointer types
1378
                match smart_ptr_def.known {
21✔
1379
                    Some(KnownPointer::Box)
1380
                    | Some(KnownPointer::Rc)
1381
                    | Some(KnownPointer::Arc)
1382
                    | Some(KnownPointer::SharedReference) => {
21✔
1383
                        // Supported types, continue
21✔
1384
                    }
21✔
1385
                    _ => {
1386
                        return Err(ReflectError::OperationFailed {
×
1387
                            shape: frame.shape,
×
1388
                            operation: "only the following pointers are currently supported: Box<T>, Rc<T>, Arc<T>, and &T",
×
1389
                        });
×
1390
                    }
1391
                }
1392

1393
                // Get the pointee shape
1394
                let pointee_shape = match smart_ptr_def.pointee() {
21✔
1395
                    Some(shape) => shape,
21✔
1396
                    None => {
1397
                        return Err(ReflectError::OperationFailed {
×
1398
                            shape: frame.shape,
×
1399
                            operation: "Box must have a pointee shape",
×
1400
                        });
×
1401
                    }
1402
                };
1403

1404
                if pointee_shape.layout.sized_layout().is_ok() {
21✔
1405
                    // pointee is sized, we can allocate it — for `Arc<T>` we'll be allocating a `T` and
1406
                    // holding onto it. We'll build a new Arc with it when ending the smart pointer frame.
1407

1408
                    if matches!(frame.tracker, Tracker::Uninit) {
7✔
1409
                        frame.tracker = Tracker::SmartPointer {
7✔
1410
                            is_initialized: false,
7✔
1411
                        };
7✔
1412
                    }
7✔
1413

1414
                    let inner_layout = match pointee_shape.layout.sized_layout() {
7✔
1415
                        Ok(layout) => layout,
7✔
1416
                        Err(_) => {
1417
                            return Err(ReflectError::Unsized {
×
1418
                                shape: pointee_shape,
×
1419
                                operation: "begin_smart_ptr, calculating inner value layout",
×
1420
                            });
×
1421
                        }
1422
                    };
1423
                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
7✔
1424
                    let Some(inner_ptr) = NonNull::new(inner_ptr) else {
7✔
1425
                        return Err(ReflectError::OperationFailed {
×
1426
                            shape: frame.shape,
×
1427
                            operation: "failed to allocate memory for smart pointer inner value",
×
1428
                        });
×
1429
                    };
1430

1431
                    // Push a new frame for the inner value
1432
                    self.frames.push(Frame::new(
7✔
1433
                        PtrUninit::new(inner_ptr),
7✔
1434
                        pointee_shape,
7✔
1435
                        FrameOwnership::Owned,
7✔
1436
                    ));
1437
                } else {
1438
                    // pointee is unsized, we only support a handful of cases there
1439
                    if pointee_shape == str::SHAPE {
14✔
1440
                        crate::trace!("Pointee is str");
1441

1442
                        // Allocate space for a String
1443
                        let string_layout = String::SHAPE
8✔
1444
                            .layout
8✔
1445
                            .sized_layout()
8✔
1446
                            .expect("String must have a sized layout");
8✔
1447
                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
8✔
1448
                        let Some(string_ptr) = NonNull::new(string_ptr) else {
8✔
1449
                            return Err(ReflectError::OperationFailed {
×
1450
                                shape: frame.shape,
×
1451
                                operation: "failed to allocate memory for string",
×
1452
                            });
×
1453
                        };
1454
                        let mut frame = Frame::new(
8✔
1455
                            PtrUninit::new(string_ptr),
8✔
1456
                            String::SHAPE,
1457
                            FrameOwnership::Owned,
8✔
1458
                        );
1459
                        frame.tracker = Tracker::Uninit;
8✔
1460
                        self.frames.push(frame);
8✔
1461
                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
6✔
1462
                        crate::trace!("Pointee is [{}]", _st.t);
1463

1464
                        // Get the slice builder vtable
1465
                        let slice_builder_vtable = smart_ptr_def
6✔
1466
                            .vtable
6✔
1467
                            .slice_builder_vtable
6✔
1468
                            .ok_or(ReflectError::OperationFailed {
6✔
1469
                                shape: frame.shape,
6✔
1470
                                operation: "smart pointer does not support slice building",
6✔
1471
                            })?;
6✔
1472

1473
                        // Create a new builder
1474
                        let builder_ptr = (slice_builder_vtable.new_fn)();
6✔
1475

1476
                        // Deallocate the original Arc allocation before replacing with slice builder
1477
                        if let FrameOwnership::Owned = frame.ownership {
6✔
1478
                            if let Ok(layout) = frame.shape.layout.sized_layout() {
6✔
1479
                                if layout.size() > 0 {
6✔
1480
                                    unsafe {
6✔
1481
                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
6✔
1482
                                    };
6✔
1483
                                }
6✔
1484
                            }
×
1485
                        }
×
1486

1487
                        // Update the current frame to use the slice builder
1488
                        frame.data = builder_ptr.as_uninit();
6✔
1489
                        frame.tracker = Tracker::SmartPointerSlice {
6✔
1490
                            vtable: slice_builder_vtable,
6✔
1491
                            building_item: false,
6✔
1492
                        };
6✔
1493
                        // The slice builder memory is managed by the vtable, not by us
1494
                        frame.ownership = FrameOwnership::ManagedElsewhere;
6✔
1495
                    } else {
1496
                        todo!("unsupported unsize pointee shape: {}", pointee_shape)
×
1497
                    }
1498
                }
1499

1500
                Ok(self)
21✔
1501
            }
1502
            _ => Err(ReflectError::OperationFailed {
×
1503
                shape: frame.shape,
×
1504
                operation: "push_smart_ptr can only be called on compatible types",
×
1505
            }),
×
1506
        }
1507
    }
21✔
1508
}
1509

1510
////////////////////////////////////////////////////////////////////////////////////////////////////
1511
// Lists
1512
////////////////////////////////////////////////////////////////////////////////////////////////////
1513
impl Partial<'_> {
1514
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
1515
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
1516
    /// `push`.
1517
    ///
1518
    /// `begin_list` does not clear the list if it was previously initialized.
1519
    /// `begin_list` does not push a new frame to the stack, and thus does not
1520
    /// require `end` to be called afterwards.
1521
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
36✔
1522
        crate::trace!("begin_list()");
1523
        self.require_active()?;
36✔
1524
        let frame = self.frames.last_mut().unwrap();
36✔
1525

1526
        match &frame.tracker {
36✔
1527
            Tracker::Uninit => {
28✔
1528
                // that's good, let's initialize it
28✔
1529
            }
28✔
1530
            Tracker::Init => {
1531
                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
1532
                frame.tracker = Tracker::List {
1✔
1533
                    is_initialized: true,
1✔
1534
                    current_child: false,
1✔
1535
                };
1✔
1536
                return Ok(self);
1✔
1537
            }
1538
            Tracker::List { is_initialized, .. } => {
1✔
1539
                if *is_initialized {
1✔
1540
                    // already initialized, nothing to do
1541
                    return Ok(self);
1✔
1542
                }
×
1543
            }
1544
            Tracker::SmartPointerSlice { .. } => {
1545
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
1546
                return Ok(self);
6✔
1547
            }
1548
            _ => {
1549
                return Err(ReflectError::UnexpectedTracker {
×
1550
                    message: "begin_list called but tracker isn't something list-like",
×
1551
                    current_tracker: frame.tracker.kind(),
×
1552
                });
×
1553
            }
1554
        };
1555

1556
        // Check that we have a List
1557
        let list_def = match &frame.shape.def {
28✔
1558
            Def::List(list_def) => list_def,
25✔
1559
            _ => {
1560
                return Err(ReflectError::OperationFailed {
3✔
1561
                    shape: frame.shape,
3✔
1562
                    operation: "begin_list can only be called on List types",
3✔
1563
                });
3✔
1564
            }
1565
        };
1566

1567
        // Check that we have init_in_place_with_capacity function
1568
        let init_fn = match list_def.vtable.init_in_place_with_capacity {
25✔
1569
            Some(f) => f,
25✔
1570
            None => {
1571
                return Err(ReflectError::OperationFailed {
×
1572
                    shape: frame.shape,
×
1573
                    operation: "list type does not support initialization with capacity",
×
1574
                });
×
1575
            }
1576
        };
1577

1578
        // Initialize the list with default capacity (0)
1579
        unsafe {
25✔
1580
            init_fn(frame.data, 0);
25✔
1581
        }
25✔
1582

1583
        // Update tracker to List state
1584
        frame.tracker = Tracker::List {
25✔
1585
            is_initialized: true,
25✔
1586
            current_child: false,
25✔
1587
        };
25✔
1588

1589
        Ok(self)
25✔
1590
    }
36✔
1591

1592
    /// Pushes an element to the list
1593
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
1594
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
72✔
1595
        crate::trace!("begin_list_item()");
1596
        self.require_active()?;
72✔
1597
        let frame = self.frames.last_mut().unwrap();
72✔
1598

1599
        // Check if we're building a smart pointer slice
1600
        if let Tracker::SmartPointerSlice {
1601
            building_item,
14✔
1602
            vtable: _,
1603
        } = &frame.tracker
72✔
1604
        {
1605
            if *building_item {
14✔
1606
                return Err(ReflectError::OperationFailed {
×
1607
                    shape: frame.shape,
×
1608
                    operation: "already building an item, call end() first",
×
1609
                });
×
1610
            }
14✔
1611

1612
            // Get the element type from the smart pointer's pointee
1613
            let element_shape = match &frame.shape.def {
14✔
1614
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
14✔
1615
                    Some(pointee_shape) => match &pointee_shape.ty {
14✔
1616
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
14✔
1617
                        _ => {
1618
                            return Err(ReflectError::OperationFailed {
×
1619
                                shape: frame.shape,
×
1620
                                operation: "smart pointer pointee is not a slice",
×
1621
                            });
×
1622
                        }
1623
                    },
1624
                    None => {
1625
                        return Err(ReflectError::OperationFailed {
×
1626
                            shape: frame.shape,
×
1627
                            operation: "smart pointer has no pointee",
×
1628
                        });
×
1629
                    }
1630
                },
1631
                _ => {
1632
                    return Err(ReflectError::OperationFailed {
×
1633
                        shape: frame.shape,
×
1634
                        operation: "expected smart pointer definition",
×
1635
                    });
×
1636
                }
1637
            };
1638

1639
            // Allocate space for the element
1640
            crate::trace!("Pointee is a slice of {element_shape}");
1641
            let element_layout = match element_shape.layout.sized_layout() {
14✔
1642
                Ok(layout) => layout,
14✔
1643
                Err(_) => {
1644
                    return Err(ReflectError::OperationFailed {
×
1645
                        shape: element_shape,
×
1646
                        operation: "cannot allocate unsized element",
×
1647
                    });
×
1648
                }
1649
            };
1650

1651
            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
14✔
1652
            let Some(element_ptr) = NonNull::new(element_ptr) else {
14✔
1653
                return Err(ReflectError::OperationFailed {
×
1654
                    shape: frame.shape,
×
1655
                    operation: "failed to allocate memory for list element",
×
1656
                });
×
1657
            };
1658

1659
            // Create and push the element frame
1660
            crate::trace!("Pushing element frame, which we just allocated");
1661
            let element_frame = Frame::new(
14✔
1662
                PtrUninit::new(element_ptr),
14✔
1663
                element_shape,
14✔
1664
                FrameOwnership::Owned,
14✔
1665
            );
1666
            self.frames.push(element_frame);
14✔
1667

1668
            // Mark that we're building an item
1669
            // We need to update the tracker after pushing the frame
1670
            let parent_idx = self.frames.len() - 2;
14✔
1671
            if let Tracker::SmartPointerSlice { building_item, .. } =
14✔
1672
                &mut self.frames[parent_idx].tracker
14✔
1673
            {
14✔
1674
                crate::trace!("Marking element frame as building item");
14✔
1675
                *building_item = true;
14✔
1676
            }
14✔
1677

1678
            return Ok(self);
14✔
1679
        }
58✔
1680

1681
        // Check that we have a List that's been initialized
1682
        let list_def = match &frame.shape.def {
58✔
1683
            Def::List(list_def) => list_def,
57✔
1684
            _ => {
1685
                return Err(ReflectError::OperationFailed {
1✔
1686
                    shape: frame.shape,
1✔
1687
                    operation: "push can only be called on List types",
1✔
1688
                });
1✔
1689
            }
1690
        };
1691

1692
        // Verify the tracker is in List state and initialized
1693
        match &mut frame.tracker {
57✔
1694
            Tracker::List {
1695
                is_initialized: true,
1696
                current_child,
57✔
1697
            } => {
1698
                if *current_child {
57✔
1699
                    return Err(ReflectError::OperationFailed {
×
1700
                        shape: frame.shape,
×
1701
                        operation: "already pushing an element, call pop() first",
×
1702
                    });
×
1703
                }
57✔
1704
                *current_child = true;
57✔
1705
            }
1706
            _ => {
1707
                return Err(ReflectError::OperationFailed {
×
1708
                    shape: frame.shape,
×
1709
                    operation: "must call begin_list() before push()",
×
1710
                });
×
1711
            }
1712
        }
1713

1714
        // Get the element shape
1715
        let element_shape = list_def.t();
57✔
1716

1717
        // Allocate space for the new element
1718
        let element_layout = match element_shape.layout.sized_layout() {
57✔
1719
            Ok(layout) => layout,
57✔
1720
            Err(_) => {
1721
                return Err(ReflectError::Unsized {
×
1722
                    shape: element_shape,
×
1723
                    operation: "begin_list_item: calculating element layout",
×
1724
                });
×
1725
            }
1726
        };
1727
        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
57✔
1728

1729
        let Some(element_ptr) = NonNull::new(element_ptr) else {
57✔
1730
            return Err(ReflectError::OperationFailed {
×
1731
                shape: frame.shape,
×
1732
                operation: "failed to allocate memory for list element",
×
1733
            });
×
1734
        };
1735

1736
        // Push a new frame for the element
1737
        self.frames.push(Frame::new(
57✔
1738
            PtrUninit::new(element_ptr),
57✔
1739
            element_shape,
57✔
1740
            FrameOwnership::Owned,
57✔
1741
        ));
1742

1743
        Ok(self)
57✔
1744
    }
72✔
1745
}
1746

1747
////////////////////////////////////////////////////////////////////////////////////////////////////
1748
// Maps
1749
////////////////////////////////////////////////////////////////////////////////////////////////////
1750
impl Partial<'_> {
1751
    /// Begins a map initialization operation
1752
    ///
1753
    /// This initializes the map with default capacity and allows inserting key-value pairs
1754
    /// It does _not_ push a new frame onto the stack.
1755
    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
12✔
1756
        self.require_active()?;
12✔
1757
        let frame = self.frames.last_mut().unwrap();
12✔
1758

1759
        // Check that we have a Map
1760
        let map_def = match &frame.shape.def {
12✔
1761
            Def::Map(map_def) => map_def,
12✔
1762
            _ => {
1763
                return Err(ReflectError::OperationFailed {
×
1764
                    shape: frame.shape,
×
1765
                    operation: "begin_map can only be called on Map types",
×
1766
                });
×
1767
            }
1768
        };
1769

1770
        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
12✔
1771

1772
        // Initialize the map with default capacity (0)
1773
        unsafe {
12✔
1774
            init_fn(frame.data, 0);
12✔
1775
        }
12✔
1776

1777
        // Update tracker to Map state
1778
        frame.tracker = Tracker::Map {
12✔
1779
            is_initialized: true,
12✔
1780
            insert_state: MapInsertState::Idle,
12✔
1781
        };
12✔
1782

1783
        Ok(self)
12✔
1784
    }
12✔
1785

1786
    /// Pushes a frame for the map key. After that, `set()` should be called
1787
    /// (or the key should be initialized somehow) and `end()` should be called
1788
    /// to pop the frame.
1789
    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
13✔
1790
        self.require_active()?;
13✔
1791
        let frame = self.frames.last_mut().unwrap();
13✔
1792

1793
        // Check that we have a Map and set up for key insertion
1794
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
13✔
1795
            (
1796
                Def::Map(map_def),
13✔
1797
                Tracker::Map {
1798
                    is_initialized: true,
1799
                    insert_state,
13✔
1800
                },
1801
            ) => {
1802
                match insert_state {
13✔
1803
                    MapInsertState::Idle => {
13✔
1804
                        // Start a new insert automatically
13✔
1805
                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
13✔
1806
                    }
13✔
1807
                    MapInsertState::PushingKey { key_ptr } => {
×
1808
                        if key_ptr.is_some() {
×
1809
                            return Err(ReflectError::OperationFailed {
×
1810
                                shape: frame.shape,
×
1811
                                operation: "already pushing a key, call end() first",
×
1812
                            });
×
1813
                        }
×
1814
                    }
1815
                    _ => {
1816
                        return Err(ReflectError::OperationFailed {
×
1817
                            shape: frame.shape,
×
1818
                            operation: "must complete current operation before begin_key()",
×
1819
                        });
×
1820
                    }
1821
                }
1822
                map_def
13✔
1823
            }
1824
            _ => {
1825
                return Err(ReflectError::OperationFailed {
×
1826
                    shape: frame.shape,
×
1827
                    operation: "must call begin_map() before begin_key()",
×
1828
                });
×
1829
            }
1830
        };
1831

1832
        // Get the key shape
1833
        let key_shape = map_def.k();
13✔
1834

1835
        // Allocate space for the key
1836
        let key_layout = match key_shape.layout.sized_layout() {
13✔
1837
            Ok(layout) => layout,
13✔
1838
            Err(_) => {
1839
                return Err(ReflectError::Unsized {
×
1840
                    shape: key_shape,
×
1841
                    operation: "begin_key allocating key",
×
1842
                });
×
1843
            }
1844
        };
1845
        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
13✔
1846

1847
        let Some(key_ptr_raw) = NonNull::new(key_ptr_raw) else {
13✔
1848
            return Err(ReflectError::OperationFailed {
×
1849
                shape: frame.shape,
×
1850
                operation: "failed to allocate memory for map key",
×
1851
            });
×
1852
        };
1853

1854
        // Store the key pointer in the insert state
1855
        match &mut frame.tracker {
13✔
1856
            Tracker::Map {
1857
                insert_state: MapInsertState::PushingKey { key_ptr: kp },
13✔
1858
                ..
1859
            } => {
13✔
1860
                *kp = Some(PtrUninit::new(key_ptr_raw));
13✔
1861
            }
13✔
1862
            _ => unreachable!(),
×
1863
        }
1864

1865
        // Push a new frame for the key
1866
        self.frames.push(Frame::new(
13✔
1867
            PtrUninit::new(key_ptr_raw),
13✔
1868
            key_shape,
13✔
1869
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
13✔
1870
        ));
1871

1872
        Ok(self)
13✔
1873
    }
13✔
1874

1875
    /// Pushes a frame for the map value
1876
    /// Must be called after the key has been set and popped
1877
    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
10✔
1878
        self.require_active()?;
10✔
1879
        let frame = self.frames.last_mut().unwrap();
10✔
1880

1881
        // Check that we have a Map in PushingValue state
1882
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
10✔
1883
            (
1884
                Def::Map(map_def),
10✔
1885
                Tracker::Map {
1886
                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
10✔
1887
                    ..
1888
                },
1889
            ) => {
1890
                if value_ptr.is_some() {
10✔
1891
                    return Err(ReflectError::OperationFailed {
×
1892
                        shape: frame.shape,
×
1893
                        operation: "already pushing a value, call pop() first",
×
1894
                    });
×
1895
                }
10✔
1896
                map_def
10✔
1897
            }
1898
            _ => {
1899
                return Err(ReflectError::OperationFailed {
×
1900
                    shape: frame.shape,
×
1901
                    operation: "must complete key before push_value()",
×
1902
                });
×
1903
            }
1904
        };
1905

1906
        // Get the value shape
1907
        let value_shape = map_def.v();
10✔
1908

1909
        // Allocate space for the value
1910
        let value_layout = match value_shape.layout.sized_layout() {
10✔
1911
            Ok(layout) => layout,
10✔
1912
            Err(_) => {
1913
                return Err(ReflectError::Unsized {
×
1914
                    shape: value_shape,
×
1915
                    operation: "begin_value allocating value",
×
1916
                });
×
1917
            }
1918
        };
1919
        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
10✔
1920

1921
        let Some(value_ptr_raw) = NonNull::new(value_ptr_raw) else {
10✔
1922
            return Err(ReflectError::OperationFailed {
×
1923
                shape: frame.shape,
×
1924
                operation: "failed to allocate memory for map value",
×
1925
            });
×
1926
        };
1927

1928
        // Store the value pointer in the insert state
1929
        match &mut frame.tracker {
10✔
1930
            Tracker::Map {
1931
                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
10✔
1932
                ..
1933
            } => {
10✔
1934
                *vp = Some(PtrUninit::new(value_ptr_raw));
10✔
1935
            }
10✔
1936
            _ => unreachable!(),
×
1937
        }
1938

1939
        // Push a new frame for the value
1940
        self.frames.push(Frame::new(
10✔
1941
            PtrUninit::new(value_ptr_raw),
10✔
1942
            value_shape,
10✔
1943
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
10✔
1944
        ));
1945

1946
        Ok(self)
10✔
1947
    }
10✔
1948
}
1949

1950
////////////////////////////////////////////////////////////////////////////////////////////////////
1951
// Option / inner
1952
////////////////////////////////////////////////////////////////////////////////////////////////////
1953
impl Partial<'_> {
1954
    /// Begin building the Some variant of an Option
1955
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1✔
1956
        self.require_active()?;
1✔
1957
        let frame = self.frames.last_mut().unwrap();
1✔
1958

1959
        // Verify we're working with an Option
1960
        let option_def = match frame.shape.def {
1✔
1961
            Def::Option(def) => def,
1✔
1962
            _ => {
1963
                return Err(ReflectError::WasNotA {
×
1964
                    expected: "Option",
×
1965
                    actual: frame.shape,
×
1966
                });
×
1967
            }
1968
        };
1969

1970
        // Initialize the tracker for Option building
1971
        if matches!(frame.tracker, Tracker::Uninit) {
1✔
1972
            frame.tracker = Tracker::Option {
1✔
1973
                building_inner: true,
1✔
1974
            };
1✔
1975
        }
1✔
1976

1977
        // Get the inner type shape
1978
        let inner_shape = option_def.t;
1✔
1979

1980
        // Allocate memory for the inner value
1981
        let inner_layout =
1✔
1982
            inner_shape
1✔
1983
                .layout
1✔
1984
                .sized_layout()
1✔
1985
                .map_err(|_| ReflectError::Unsized {
1✔
1986
                    shape: inner_shape,
×
1987
                    operation: "begin_some, allocating Option inner value",
1988
                })?;
×
1989

1990
        let inner_data = if inner_layout.size() == 0 {
1✔
1991
            // For ZST, use a non-null but unallocated pointer
1992
            PtrUninit::new(NonNull::<u8>::dangling())
×
1993
        } else {
1994
            // Allocate memory for the inner value
1995
            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1✔
1996
            let Some(ptr) = NonNull::new(ptr) else {
1✔
1997
                alloc::alloc::handle_alloc_error(inner_layout);
×
1998
            };
1999
            PtrUninit::new(ptr)
1✔
2000
        };
2001

2002
        // Create a new frame for the inner value
2003
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1✔
2004
        self.frames.push(inner_frame);
1✔
2005

2006
        Ok(self)
1✔
2007
    }
1✔
2008

2009
    /// Begin building the inner value of a wrapper type
2010
    pub fn begin_inner(&mut self) -> Result<&mut Self, ReflectError> {
×
2011
        self.require_active()?;
×
2012

2013
        // Get the inner shape and check for try_from
2014
        let (inner_shape, has_try_from, parent_shape) = {
×
2015
            let frame = self.frames.last().unwrap();
×
NEW
2016
            if let Some(inner_shape) = frame.shape.inner {
×
NEW
2017
                let has_try_from = frame.shape.vtable.try_from.is_some();
×
UNCOV
2018
                (Some(inner_shape), has_try_from, frame.shape)
×
2019
            } else {
2020
                (None, false, frame.shape)
×
2021
            }
2022
        };
2023

2024
        if let Some(inner_shape) = inner_shape {
×
2025
            if has_try_from {
×
2026
                // Create a conversion frame with the inner shape
2027

2028
                // For conversion frames, we leave the parent tracker unchanged
2029
                // This allows automatic conversion detection to work properly
2030

2031
                // Allocate memory for the inner value (conversion source)
2032
                let inner_layout =
×
2033
                    inner_shape
×
2034
                        .layout
×
2035
                        .sized_layout()
×
2036
                        .map_err(|_| ReflectError::Unsized {
×
2037
                            shape: inner_shape,
×
2038
                            operation: "begin_inner, getting inner layout",
2039
                        })?;
×
2040

2041
                let inner_data = if inner_layout.size() == 0 {
×
2042
                    // For ZST, use a non-null but unallocated pointer
2043
                    PtrUninit::new(NonNull::<u8>::dangling())
×
2044
                } else {
2045
                    // Allocate memory for the inner value
2046
                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
×
2047
                    let Some(ptr) = NonNull::new(ptr) else {
×
2048
                        alloc::alloc::handle_alloc_error(inner_layout);
×
2049
                    };
2050
                    PtrUninit::new(ptr)
×
2051
                };
2052

2053
                // For conversion frames, we create a frame directly with the inner shape
2054
                // This allows setting values of the inner type which will be converted
2055
                // The automatic conversion detection in end() will handle the conversion
2056
                trace!(
2057
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
2058
                );
2059
                self.frames
×
2060
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
×
2061

2062
                Ok(self)
×
2063
            } else {
2064
                // For wrapper types without try_from, navigate to the first field
2065
                // This is a common pattern for newtype wrappers
2066
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
2067
                self.begin_nth_field(0)
×
2068
            }
2069
        } else {
2070
            Err(ReflectError::OperationFailed {
×
2071
                shape: parent_shape,
×
2072
                operation: "type does not have an inner value",
×
2073
            })
×
2074
        }
2075
    }
×
2076
}
2077

2078
////////////////////////////////////////////////////////////////////////////////////////////////////
2079
// Shorthands
2080
////////////////////////////////////////////////////////////////////////////////////////////////////
2081
impl<'facet> Partial<'facet> {
2082
    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
2083
    ///
2084
    /// Works on structs, enums (after selecting a variant) and arrays.
2085
    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
45✔
2086
    where
45✔
2087
        U: Facet<'facet>,
45✔
2088
    {
2089
        self.begin_nth_field(idx)?.set(value)?.end()
45✔
2090
    }
45✔
2091

2092
    /// Convenience shortcut: sets the named field to value, popping after.
2093
    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
70✔
2094
    where
70✔
2095
        U: Facet<'facet>,
70✔
2096
    {
2097
        self.begin_field(field_name)?.set(value)?.end()
70✔
2098
    }
70✔
2099

2100
    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
2101
    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2✔
2102
    where
2✔
2103
        U: Facet<'facet>,
2✔
2104
    {
2105
        self.begin_key()?.set(value)?.end()
2✔
2106
    }
2✔
2107

2108
    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
2109
    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
×
2110
    where
×
2111
        U: Facet<'facet>,
×
2112
    {
2113
        self.begin_value()?.set(value)?.end()
×
2114
    }
×
2115

2116
    /// Shorthand for: begin_list_item(), set(), end()
2117
    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
27✔
2118
    where
27✔
2119
        U: Facet<'facet>,
27✔
2120
    {
2121
        self.begin_list_item()?.set(value)?.end()
27✔
2122
    }
27✔
2123
}
2124

2125
////////////////////////////////////////////////////////////////////////////////////////////////////
2126
// Internal methods
2127
////////////////////////////////////////////////////////////////////////////////////////////////////
2128
impl<'facet> Partial<'facet> {
2129
    /// Preconditions:
2130
    ///
2131
    /// - `require_active()` check was made
2132
    /// - frame.shape.ty is an Enum
2133
    /// - `discriminant` is a valid discriminant
2134
    ///
2135
    /// Panics if current tracker is anything other than `Uninit`
2136
    /// (switching variants is not supported for now).
2137
    fn select_variant_internal(
38✔
2138
        &mut self,
38✔
2139
        enum_type: &EnumType,
38✔
2140
        variant: &'static Variant,
38✔
2141
    ) -> Result<(), ReflectError> {
38✔
2142
        // Check all invariants early before making any changes
2143
        let frame = self.frames.last().unwrap();
38✔
2144

2145
        // Check enum representation early
2146
        match enum_type.enum_repr {
38✔
2147
            EnumRepr::RustNPO => {
2148
                return Err(ReflectError::OperationFailed {
×
2149
                    shape: frame.shape,
×
2150
                    operation: "RustNPO enums are not supported for incremental building",
×
2151
                });
×
2152
            }
2153
            EnumRepr::U8
2154
            | EnumRepr::U16
2155
            | EnumRepr::U32
2156
            | EnumRepr::U64
2157
            | EnumRepr::I8
2158
            | EnumRepr::I16
2159
            | EnumRepr::I32
2160
            | EnumRepr::I64
2161
            | EnumRepr::USize
2162
            | EnumRepr::ISize => {
38✔
2163
                // These are supported, continue
38✔
2164
            }
38✔
2165
        }
2166

2167
        let Some(discriminant) = variant.discriminant else {
38✔
2168
            return Err(ReflectError::OperationFailed {
×
2169
                shape: frame.shape,
×
2170
                operation: "trying to select an enum variant without a discriminant",
×
2171
            });
×
2172
        };
2173

2174
        // All checks passed, now we can safely make changes
2175
        let fr = self.frames.last_mut().unwrap();
38✔
2176

2177
        // Write the discriminant to memory
2178
        unsafe {
2179
            match enum_type.enum_repr {
38✔
2180
                EnumRepr::U8 => {
24✔
2181
                    let ptr = fr.data.as_mut_byte_ptr();
24✔
2182
                    *ptr = discriminant as u8;
24✔
2183
                }
24✔
2184
                EnumRepr::U16 => {
1✔
2185
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
1✔
2186
                    *ptr = discriminant as u16;
1✔
2187
                }
1✔
2188
                EnumRepr::U32 => {
8✔
2189
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
8✔
2190
                    *ptr = discriminant as u32;
8✔
2191
                }
8✔
2192
                EnumRepr::U64 => {
×
2193
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
2194
                    *ptr = discriminant as u64;
×
2195
                }
×
2196
                EnumRepr::I8 => {
×
2197
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
2198
                    *ptr = discriminant as i8;
×
2199
                }
×
2200
                EnumRepr::I16 => {
4✔
2201
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
2202
                    *ptr = discriminant as i16;
4✔
2203
                }
4✔
2204
                EnumRepr::I32 => {
1✔
2205
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
2206
                    *ptr = discriminant as i32;
1✔
2207
                }
1✔
2208
                EnumRepr::I64 => {
×
2209
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
2210
                    *ptr = discriminant;
×
2211
                }
×
2212
                EnumRepr::USize => {
×
2213
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
2214
                    *ptr = discriminant as usize;
×
2215
                }
×
2216
                EnumRepr::ISize => {
×
2217
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
2218
                    *ptr = discriminant as isize;
×
2219
                }
×
2220
                _ => unreachable!("Already checked enum representation above"),
×
2221
            }
2222
        }
2223

2224
        // Update tracker to track the variant
2225
        fr.tracker = Tracker::Enum {
38✔
2226
            variant,
38✔
2227
            data: ISet::new(variant.data.fields.len()),
38✔
2228
            current_child: None,
38✔
2229
        };
38✔
2230

2231
        Ok(())
38✔
2232
    }
38✔
2233

2234
    /// Used by `begin_field` etc. to get a list of fields to look through, errors out
2235
    /// if we're not pointing to a struct or an enum with an already-selected variant
2236
    fn get_fields(&self) -> Result<&'static [Field], ReflectError> {
162✔
2237
        let frame = self.frames.last().unwrap();
162✔
2238
        match frame.shape.ty {
162✔
2239
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
×
2240
                shape: frame.shape,
×
2241
                operation: "cannot select a field from a primitive type",
×
2242
            }),
×
2243
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
2244
                shape: frame.shape,
×
2245
                operation: "cannot select a field from a sequence type",
×
2246
            }),
×
2247
            Type::User(user_type) => match user_type {
162✔
2248
                UserType::Struct(struct_type) => Ok(struct_type.fields),
138✔
2249
                UserType::Enum(_) => {
2250
                    let Tracker::Enum { variant, .. } = &frame.tracker else {
23✔
2251
                        return Err(ReflectError::OperationFailed {
1✔
2252
                            shape: frame.shape,
1✔
2253
                            operation: "must select variant before selecting enum fields",
1✔
2254
                        });
1✔
2255
                    };
2256
                    Ok(variant.data.fields)
22✔
2257
                }
2258
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
2259
                    shape: frame.shape,
×
2260
                    operation: "cannot select a field from a union type",
×
2261
                }),
×
2262
                UserType::Opaque => Err(ReflectError::OperationFailed {
1✔
2263
                    shape: frame.shape,
1✔
2264
                    operation: "opaque types cannot be reflected upon",
1✔
2265
                }),
1✔
2266
            },
2267
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
2268
                shape: frame.shape,
×
2269
                operation: "cannot select a field from a pointer type",
×
2270
            }),
×
2271
        }
2272
    }
162✔
2273

2274
    /// Selects the nth field of a struct by index
2275
    fn begin_nth_struct_field(
176✔
2276
        frame: &mut Frame,
176✔
2277
        struct_type: StructType,
176✔
2278
        idx: usize,
176✔
2279
    ) -> Result<Frame, ReflectError> {
176✔
2280
        if idx >= struct_type.fields.len() {
176✔
2281
            return Err(ReflectError::OperationFailed {
×
2282
                shape: frame.shape,
×
2283
                operation: "field index out of bounds",
×
2284
            });
×
2285
        }
176✔
2286
        let field = &struct_type.fields[idx];
176✔
2287

2288
        if !matches!(frame.tracker, Tracker::Struct { .. }) {
176✔
2289
            frame.tracker = Tracker::Struct {
103✔
2290
                iset: ISet::new(struct_type.fields.len()),
103✔
2291
                current_child: None,
103✔
2292
            }
103✔
2293
        }
73✔
2294

2295
        let was_field_init = match &mut frame.tracker {
176✔
2296
            Tracker::Struct {
2297
                iset,
176✔
2298
                current_child,
176✔
2299
            } => {
2300
                *current_child = Some(idx);
176✔
2301
                iset.get(idx)
176✔
2302
            }
2303
            _ => unreachable!(),
×
2304
        };
2305

2306
        // Push a new frame for this field onto the frames stack.
2307
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
176✔
2308
        let field_shape = field.shape();
176✔
2309

2310
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
176✔
2311
        if was_field_init {
176✔
2312
            unsafe {
3✔
2313
                // the struct field tracker said so!
3✔
2314
                next_frame.mark_as_init();
3✔
2315
            }
3✔
2316
        }
173✔
2317

2318
        Ok(next_frame)
176✔
2319
    }
176✔
2320

2321
    /// Selects the nth element of an array by index
2322
    fn begin_nth_array_element(
38✔
2323
        frame: &mut Frame,
38✔
2324
        array_type: ArrayType,
38✔
2325
        idx: usize,
38✔
2326
    ) -> Result<Frame, ReflectError> {
38✔
2327
        if idx >= array_type.n {
38✔
2328
            return Err(ReflectError::OperationFailed {
1✔
2329
                shape: frame.shape,
1✔
2330
                operation: "array index out of bounds",
1✔
2331
            });
1✔
2332
        }
37✔
2333

2334
        if array_type.n > 63 {
37✔
2335
            return Err(ReflectError::OperationFailed {
×
2336
                shape: frame.shape,
×
2337
                operation: "arrays larger than 63 elements are not yet supported",
×
2338
            });
×
2339
        }
37✔
2340

2341
        // Ensure frame is in Array state
2342
        match &frame.tracker {
37✔
2343
            Tracker::Uninit => {
14✔
2344
                // this is fine
14✔
2345
                frame.tracker = Tracker::Array {
14✔
2346
                    iset: ISet::default(),
14✔
2347
                    current_child: None,
14✔
2348
                };
14✔
2349
            }
14✔
2350
            Tracker::Array { .. } => {
23✔
2351
                // fine too
23✔
2352
            }
23✔
2353
            _other => {
×
2354
                return Err(ReflectError::OperationFailed {
×
2355
                    shape: frame.shape,
×
2356
                    operation: "unexpected tracker state: expected Uninit or Array",
×
2357
                });
×
2358
            }
2359
        }
2360

2361
        match &mut frame.tracker {
37✔
2362
            Tracker::Array {
2363
                iset,
37✔
2364
                current_child,
37✔
2365
            } => {
2366
                *current_child = Some(idx);
37✔
2367
                let was_field_init = iset.get(idx);
37✔
2368

2369
                // Calculate the offset for this array element
2370
                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
37✔
2371
                    return Err(ReflectError::Unsized {
×
2372
                        shape: array_type.t,
×
2373
                        operation: "begin_nth_element, calculating array element offset",
×
2374
                    });
×
2375
                };
2376
                let offset = element_layout.size() * idx;
37✔
2377
                let element_data = unsafe { frame.data.field_uninit_at(offset) };
37✔
2378

2379
                let mut next_frame = Frame::new(element_data, array_type.t, FrameOwnership::Field);
37✔
2380
                if was_field_init {
37✔
2381
                    // safety: `iset` said it was initialized already
2382
                    unsafe {
1✔
2383
                        next_frame.mark_as_init();
1✔
2384
                    }
1✔
2385
                }
36✔
2386
                Ok(next_frame)
37✔
2387
            }
2388
            _ => unreachable!(),
×
2389
        }
2390
    }
38✔
2391

2392
    /// Selects the nth field of an enum variant by index
2393
    fn begin_nth_enum_field(
42✔
2394
        frame: &mut Frame,
42✔
2395
        variant: &'static Variant,
42✔
2396
        idx: usize,
42✔
2397
    ) -> Result<Frame, ReflectError> {
42✔
2398
        if idx >= variant.data.fields.len() {
42✔
2399
            return Err(ReflectError::OperationFailed {
×
2400
                shape: frame.shape,
×
2401
                operation: "enum field index out of bounds",
×
2402
            });
×
2403
        }
42✔
2404

2405
        let field = &variant.data.fields[idx];
42✔
2406

2407
        // Update tracker
2408
        let was_field_init = match &mut frame.tracker {
42✔
2409
            Tracker::Enum {
2410
                data,
42✔
2411
                current_child,
42✔
2412
                ..
2413
            } => {
2414
                *current_child = Some(idx);
42✔
2415
                data.get(idx)
42✔
2416
            }
2417
            _ => {
2418
                return Err(ReflectError::OperationFailed {
×
2419
                    shape: frame.shape,
×
2420
                    operation: "selecting a field on an enum requires selecting a variant first",
×
2421
                });
×
2422
            }
2423
        };
2424

2425
        // SAFETY: the field offset comes from an unsafe impl of the Facet trait, we trust it.
2426
        // also, we checked that the variant was selected.
2427
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
42✔
2428
        let field_shape = field.shape();
42✔
2429

2430
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
42✔
2431
        if was_field_init {
42✔
2432
            // SAFETY: `ISet` told us the field was initialized
2433
            unsafe {
1✔
2434
                next_frame.mark_as_init();
1✔
2435
            }
1✔
2436
        }
41✔
2437

2438
        Ok(next_frame)
42✔
2439
    }
42✔
2440

2441
    /// Require that the partial is active
2442
    #[inline]
2443
    pub(crate) fn require_active(&self) -> Result<(), ReflectError> {
1,910✔
2444
        if self.state == PartialState::Active {
1,910✔
2445
            Ok(())
1,909✔
2446
        } else {
2447
            Err(ReflectError::InvariantViolation {
1✔
2448
                invariant: "Cannot use Partial after it has been built or poisoned",
1✔
2449
            })
1✔
2450
        }
2451
    }
1,910✔
2452
}
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