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

facet-rs / facet / 17653824345

11 Sep 2025 06:29PM UTC coverage: 54.689% (+0.3%) from 54.357%
17653824345

Pull #882

github

web-flow
Merge bc1fc820d into 2b656cc91
Pull Request #882: Clean up Partial/TypedPartial API

1034 of 1659 new or added lines in 4 files covered. (62.33%)

3 existing lines in 1 file now uncovered.

4759 of 8702 relevant lines covered (54.69%)

36.61 hits per line

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

60.45
/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;
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>
211✔
28
    where
211✔
29
        T: Facet<'facet> + ?Sized,
211✔
30
    {
31
        Ok(TypedPartial {
32
            inner: Self::alloc_shape(T::SHAPE)?,
211✔
33
            phantom: PhantomData,
210✔
34
        })
35
    }
211✔
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> {
226✔
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 {
226✔
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);
225✔
54
        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
225✔
55

56
        Ok(Self {
225✔
57
            frames,
225✔
58
            state: PartialState::Active,
225✔
59
            invariant: PhantomData,
225✔
60
        })
225✔
61
    }
226✔
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 {
7✔
84
        self.frames
7✔
85
            .last()
7✔
86
            .expect("Partial always has at least one frame")
7✔
87
            .shape
7✔
88
    }
7✔
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> {
343✔
92
        crate::trace!("end() called");
93
        self.require_active()?;
343✔
94

95
        // Special handling for SmartPointerSlice - convert builder to Arc
96
        if self.frames.len() == 1 {
343✔
97
            if let Tracker::SmartPointerSlice {
98
                vtable,
6✔
99
                building_item,
6✔
100
            } = &self.frames[0].tracker
7✔
101
            {
102
                if *building_item {
6✔
NEW
103
                    return Err(ReflectError::OperationFailed {
×
NEW
104
                        shape: self.frames[0].shape,
×
NEW
105
                        operation: "still building an item, finish it first",
×
NEW
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(arc_ptr.as_byte_ptr() as *mut u8);
6✔
115
                self.frames[0].tracker = Tracker::Init;
6✔
116
                // The builder memory has been consumed by convert_fn, so we no longer own it
117
                self.frames[0].ownership = FrameOwnership::ManagedElsewhere;
6✔
118

119
                return Ok(self);
6✔
120
            }
1✔
121
        }
336✔
122

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

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

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

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

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

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

169
        if needs_conversion {
334✔
170
            trace!(
171
                "Detected implicit conversion needed from {} to {}",
172
                popped_frame.shape, parent_frame.shape
173
            );
174
            // Perform the conversion
NEW
175
            if let Some(try_from_fn) = parent_frame
×
NEW
176
                .shape
×
NEW
177
                .vtable
×
NEW
178
                .sized()
×
NEW
179
                .and_then(|v| (v.try_from)())
×
180
            {
NEW
181
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
×
NEW
182
                let inner_shape = popped_frame.shape;
×
183

184
                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
NEW
185
                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
×
186

NEW
187
                if let Err(e) = result {
×
188
                    trace!("Conversion failed: {e:?}");
189

190
                    // Deallocate the inner value's memory since conversion failed
NEW
191
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
192
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
193
                            if layout.size() > 0 {
×
194
                                trace!(
195
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
196
                                    layout.size(),
197
                                    layout.align()
198
                                );
NEW
199
                                unsafe {
×
NEW
200
                                    alloc::alloc::dealloc(
×
NEW
201
                                        popped_frame.data.as_mut_byte_ptr(),
×
NEW
202
                                        layout,
×
NEW
203
                                    );
×
NEW
204
                                }
×
NEW
205
                            }
×
NEW
206
                        }
×
NEW
207
                    }
×
208

NEW
209
                    return Err(ReflectError::TryFromError {
×
NEW
210
                        src_shape: inner_shape,
×
NEW
211
                        dst_shape: parent_frame.shape,
×
NEW
212
                        inner: e,
×
NEW
213
                    });
×
NEW
214
                }
×
215

216
                trace!("Conversion succeeded, marking parent as initialized");
NEW
217
                parent_frame.tracker = Tracker::Init;
×
218

219
                // Deallocate the inner value's memory since try_from consumed it
NEW
220
                if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
221
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
222
                        if layout.size() > 0 {
×
223
                            trace!(
224
                                "Deallocating conversion frame memory: size={}, align={}",
225
                                layout.size(),
226
                                layout.align()
227
                            );
NEW
228
                            unsafe {
×
NEW
229
                                alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
×
NEW
230
                            }
×
NEW
231
                        }
×
NEW
232
                    }
×
NEW
233
                }
×
234

NEW
235
                return Ok(self);
×
NEW
236
            }
×
237
        }
334✔
238

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

268
                    // The child frame contained the inner value
269
                    let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
7✔
270

271
                    // Use new_into_fn to create the Box
272
                    unsafe {
7✔
273
                        new_into_fn(parent_frame.data, inner_ptr);
7✔
274
                    }
7✔
275

276
                    // We just moved out of it
277
                    popped_frame.tracker = Tracker::Uninit;
7✔
278

279
                    // Deallocate the inner value's memory since new_into_fn moved it
280
                    popped_frame.dealloc();
7✔
281

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

309
                        // The child frame contained the element value
310
                        let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
51✔
311

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

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

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

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

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

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

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

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

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

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

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

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

454
                        popped_frame.require_full_initialization()?;
5✔
455

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

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

470
                        parent_frame.deinit();
5✔
471

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

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

512
                        parent_frame.tracker = Tracker::Init;
5✔
513

514
                        popped_frame.tracker = Tracker::Uninit;
5✔
515
                        popped_frame.dealloc();
5✔
516
                    }
517
                    _ => {
NEW
518
                        unreachable!(
×
519
                            "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"
520
                        )
521
                    }
522
                }
523
            }
524
            Tracker::SmartPointerSlice {
525
                vtable,
14✔
526
                building_item,
14✔
527
            } => {
528
                if *building_item {
14✔
529
                    // We just popped an element frame, now push it to the slice builder
530
                    let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
14✔
531

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

539
                    popped_frame.tracker = Tracker::Uninit;
14✔
540
                    popped_frame.dealloc();
14✔
541

542
                    if let Tracker::SmartPointerSlice {
543
                        building_item: bi, ..
14✔
544
                    } = &mut parent_frame.tracker
14✔
545
                    {
14✔
546
                        *bi = false;
14✔
547
                    }
14✔
NEW
548
                }
×
549
            }
NEW
550
            _ => {}
×
551
        }
552

553
        Ok(self)
334✔
554
    }
343✔
555

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

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

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

665
        let frame = self.frames.pop().unwrap();
156✔
666

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

675
        // Check invariants if present
676
        if let Some(invariants_fn) = frame.shape.vtable.sized().and_then(|v| (v.invariants)()) {
130✔
677
            // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
678
            let value_ptr = unsafe { frame.data.assume_init().as_const() };
6✔
679
            let invariants_ok = unsafe { invariants_fn(value_ptr) };
6✔
680

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

691
        // Mark as built to prevent reuse
692
        self.state = PartialState::Built;
127✔
693

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

720
////////////////////////////////////////////////////////////////////////////////////////////////////
721
// `Set` and set helpers
722
////////////////////////////////////////////////////////////////////////////////////////////////////
723
impl<'facet> Partial<'facet> {
724
    /// Sets a value wholesale into the current frame.
725
    ///
726
    /// If the current frame was already initialized, the previous value is
727
    /// dropped. If it was partially initialized, the fields that were initialized
728
    /// are dropped, etc.
729
    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
313✔
730
    where
313✔
731
        U: Facet<'facet>,
313✔
732
    {
733
        self.require_active()?;
313✔
734

735
        let ptr_const = PtrConst::new(&raw const value);
313✔
736
        unsafe {
737
            // Safety: We are calling set_shape with a valid shape and a valid pointer
738
            self.set_shape(ptr_const, U::SHAPE)?
313✔
739
        };
740

741
        // Prevent the value from being dropped since we've copied it
742
        core::mem::forget(value);
312✔
743

744
        Ok(self)
312✔
745
    }
313✔
746

747
    /// Sets a value into the current frame by [PtrConst] / [Shape].
748
    ///
749
    /// # Safety
750
    ///
751
    /// The caller must ensure that `src_value` points to a valid instance of a value
752
    /// whose memory layout and type matches `src_shape`, and that this value can be
753
    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
754
    ///
755
    /// After a successful call, the ownership of the value at `src_value` is effectively moved
756
    /// into the Partial (i.e., the destination), and the original value should not be used
757
    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
758
    ///
759
    /// If an error is returned, the destination remains unmodified and safe for future operations.
760
    #[inline]
761
    pub unsafe fn set_shape(
313✔
762
        &mut self,
313✔
763
        src_value: PtrConst<'_>,
313✔
764
        src_shape: &'static Shape,
313✔
765
    ) -> Result<&mut Self, ReflectError> {
313✔
766
        self.require_active()?;
313✔
767

768
        let fr = self.frames.last_mut().unwrap();
313✔
769
        crate::trace!("set_shape({src_shape:?})");
770

771
        if !fr.shape.is_shape(src_shape) {
313✔
772
            return Err(ReflectError::WrongShape {
1✔
773
                expected: fr.shape,
1✔
774
                actual: src_shape,
1✔
775
            });
1✔
776
        }
312✔
777

778
        fr.deinit();
312✔
779

780
        // SAFETY: `fr.shape` and `src_shape` are the same, so they have the same size,
781
        // and the preconditions for this function are that `src_value` is fully intialized.
782
        unsafe {
312✔
783
            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
312✔
784
            // which is not possible for `Partial`
312✔
785
            fr.data.copy_from(src_value, fr.shape).unwrap();
312✔
786
        }
312✔
787

788
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
789
        unsafe {
312✔
790
            fr.mark_as_init();
312✔
791
        }
312✔
792

793
        Ok(self)
312✔
794
    }
313✔
795

796
    /// Sets the current frame using a function that initializes the value
797
    ///
798
    /// # Safety
799
    ///
800
    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
801
    /// value of the right type.
802
    ///
803
    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
804
    /// there is no need to drop it in place.
805
    pub unsafe fn set_from_function<F>(&mut self, f: F) -> Result<&mut Self, ReflectError>
4✔
806
    where
4✔
807
        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
4✔
808
    {
809
        self.require_active()?;
4✔
810
        let frame = self.frames.last_mut().unwrap();
4✔
811

812
        frame.deinit();
4✔
813
        f(frame.data)?;
4✔
814

815
        // safety: `f()` returned Ok, so `frame.data` must be initialized
816
        unsafe {
4✔
817
            frame.mark_as_init();
4✔
818
        }
4✔
819

820
        Ok(self)
4✔
821
    }
4✔
822

823
    /// Sets the current frame to its default value using `default_in_place` from the
824
    /// vtable.
825
    ///
826
    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
827
    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
828
    /// for `field`.
829
    ///
830
    /// If the current frame's shape does not implement `Default`, then this returns an error.
831
    #[inline]
832
    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
5✔
833
        let frame = self.frames.last().unwrap();
5✔
834

835
        let Some(default_fn) = (frame.shape.vtable.sized().unwrap().default_in_place)() else {
5✔
836
            return Err(ReflectError::OperationFailed {
1✔
837
                shape: frame.shape,
1✔
838
                operation: "type does not implement Default",
1✔
839
            });
1✔
840
        };
841

842
        // SAFETY: `default_fn` fully initializes the passed pointer. we took it
843
        // from the vtable of `frame.shape`.
844
        unsafe {
845
            self.set_from_function(move |ptr| {
4✔
846
                default_fn(ptr);
4✔
847
                Ok(())
4✔
848
            })
4✔
849
        }
850
    }
5✔
851

852
    /// Copy a value from a Peek into the current frame.
853
    ///
854
    /// # Invariants
855
    ///
856
    /// `peek` must be a thin pointer, otherwise this panics.
857
    ///
858
    /// # Safety
859
    ///
860
    /// If this suceeds, the value `Peek` points to has been moved out of, and
861
    /// as such, should not be dropped (but should be deallocated).
NEW
862
    pub unsafe fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
NEW
863
        self.require_active()?;
×
864

865
        // Get the source value's pointer and shape
NEW
866
        let src_ptr = peek
×
NEW
867
            .data()
×
NEW
868
            .thin()
×
NEW
869
            .expect("set_from_peek requires thin pointers");
×
NEW
870
        let src_shape = peek.shape();
×
871

872
        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
NEW
873
        unsafe { self.set_shape(src_ptr, src_shape) }
×
NEW
874
    }
×
875

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

882
        let frame = self.frames.last_mut().unwrap();
2✔
883

884
        // Check if the type has a parse function
885
        let Some(parse_fn) = (frame.shape.vtable.sized().unwrap().parse)() else {
2✔
NEW
886
            return Err(ReflectError::OperationFailed {
×
NEW
887
                shape: frame.shape,
×
NEW
888
                operation: "Type does not support parsing from string",
×
NEW
889
            });
×
890
        };
891

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

895
        // Parse the string value using the type's parse function
896
        let result = unsafe { parse_fn(s, frame.data) };
2✔
897
        if let Err(_pe) = result {
2✔
898
            // TODO: can we propagate the ParseError somehow?
899
            return Err(ReflectError::OperationFailed {
1✔
900
                shape: frame.shape,
1✔
901
                operation: "Failed to parse string value",
1✔
902
            });
1✔
903
        }
1✔
904

905
        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
906
        unsafe {
1✔
907
            frame.mark_as_init();
1✔
908
        }
1✔
909
        Ok(self)
1✔
910
    }
2✔
911
}
912

913
////////////////////////////////////////////////////////////////////////////////////////////////////
914
// Enum variant selection
915
////////////////////////////////////////////////////////////////////////////////////////////////////
916
impl<'facet> Partial<'facet> {
917
    /// Get the currently selected variant for an enum
NEW
918
    pub fn selected_variant(&self) -> Option<Variant> {
×
NEW
919
        let frame = self.frames.last()?;
×
920

NEW
921
        match &frame.tracker {
×
NEW
922
            Tracker::Enum { variant, .. } => Some(**variant),
×
NEW
923
            _ => None,
×
924
        }
NEW
925
    }
×
926

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

NEW
931
        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
×
NEW
932
            enum_def
×
NEW
933
                .variants
×
NEW
934
                .iter()
×
NEW
935
                .enumerate()
×
NEW
936
                .find(|(_, v)| v.name == variant_name)
×
937
        } else {
NEW
938
            None
×
939
        }
NEW
940
    }
×
941

942
    /// Assuming the current frame is an enum, this selects a variant by index
943
    /// (0-based, in declaration order).
944
    ///
945
    /// For example:
946
    ///
947
    /// ```rust,no_run
948
    /// enum E { A, B, C }
949
    /// ```
950
    ///
951
    /// Calling `select_nth_variant(2)` would select variant `C`.
952
    ///
953
    /// This will return an error if the current frame is anything other than fully-uninitialized.
954
    /// In other words, it's not possible to "switch to a different variant" once you've selected one.
955
    ///
956
    /// This does _not_ push a frame on the stack.
957
    pub fn select_nth_variant(&mut self, index: usize) -> Result<&mut Self, ReflectError> {
2✔
958
        self.require_active()?;
2✔
959

960
        let frame = self.frames.last().unwrap();
2✔
961
        let enum_type = frame.get_enum_type()?;
2✔
962

963
        if index >= enum_type.variants.len() {
2✔
NEW
964
            return Err(ReflectError::OperationFailed {
×
NEW
965
                shape: frame.shape,
×
NEW
966
                operation: "variant index out of bounds",
×
NEW
967
            });
×
968
        }
2✔
969
        let variant = &enum_type.variants[index];
2✔
970

971
        self.select_variant_internal(&enum_type, variant)?;
2✔
972
        Ok(self)
2✔
973
    }
2✔
974

975
    /// Pushes a variant for enum initialization by name
976
    ///
977
    /// See [Self::select_nth_variant] for more notes.
978
    pub fn select_variant_named(&mut self, variant_name: &str) -> Result<&mut Self, ReflectError> {
30✔
979
        self.require_active()?;
30✔
980

981
        let frame = self.frames.last_mut().unwrap();
30✔
982
        let enum_type = frame.get_enum_type()?;
30✔
983

984
        let Some(variant) = enum_type.variants.iter().find(|v| v.name == variant_name) else {
69✔
985
            return Err(ReflectError::OperationFailed {
2✔
986
                shape: frame.shape,
2✔
987
                operation: "No variant found with the given name",
2✔
988
            });
2✔
989
        };
990

991
        self.select_variant_internal(&enum_type, variant)?;
28✔
992
        Ok(self)
28✔
993
    }
30✔
994

995
    /// Selects a given enum variant by discriminant. If none of the variants
996
    /// of the frame's enum have that discriminant, this returns an error.
997
    ///
998
    /// See [Self::select_nth_variant] for more notes.
999
    pub fn select_variant(&mut self, discriminant: i64) -> Result<&mut Self, ReflectError> {
8✔
1000
        self.require_active()?;
8✔
1001

1002
        // Check all invariants early before making any changes
1003
        let frame = self.frames.last().unwrap();
8✔
1004

1005
        // Check that we're dealing with an enum
1006
        let enum_type = match frame.shape.ty {
8✔
1007
            Type::User(UserType::Enum(e)) => e,
8✔
1008
            _ => {
NEW
1009
                return Err(ReflectError::WasNotA {
×
NEW
1010
                    expected: "enum",
×
NEW
1011
                    actual: frame.shape,
×
NEW
1012
                });
×
1013
            }
1014
        };
1015

1016
        // Find the variant with the matching discriminant
1017
        let Some(variant) = enum_type
8✔
1018
            .variants
8✔
1019
            .iter()
8✔
1020
            .find(|v| v.discriminant == Some(discriminant))
12✔
1021
        else {
NEW
1022
            return Err(ReflectError::OperationFailed {
×
NEW
1023
                shape: frame.shape,
×
NEW
1024
                operation: "No variant found with the given discriminant",
×
NEW
1025
            });
×
1026
        };
1027

1028
        // Update the frame tracker to select the variant
1029
        self.select_variant_internal(&enum_type, variant)?;
8✔
1030

1031
        Ok(self)
8✔
1032
    }
8✔
1033
}
1034

1035
////////////////////////////////////////////////////////////////////////////////////////////////////
1036
// Field selection
1037
////////////////////////////////////////////////////////////////////////////////////////////////////
1038
impl Partial<'_> {
1039
    /// Find the index of a field by name in the current struct
1040
    ///
1041
    /// If the current frame isn't a struct or an enum (with a selected variant)
1042
    /// then this returns `None` for sure.
NEW
1043
    pub fn field_index(&self, field_name: &str) -> Option<usize> {
×
NEW
1044
        let frame = self.frames.last()?;
×
1045

NEW
1046
        match frame.shape.ty {
×
NEW
1047
            Type::User(UserType::Struct(struct_def)) => {
×
NEW
1048
                struct_def.fields.iter().position(|f| f.name == field_name)
×
1049
            }
1050
            Type::User(UserType::Enum(_)) => {
1051
                // If we're in an enum variant, check its fields
NEW
1052
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
NEW
1053
                    variant
×
NEW
1054
                        .data
×
NEW
1055
                        .fields
×
NEW
1056
                        .iter()
×
NEW
1057
                        .position(|f| f.name == field_name)
×
1058
                } else {
NEW
1059
                    None
×
1060
                }
1061
            }
NEW
1062
            _ => None,
×
1063
        }
NEW
1064
    }
×
1065

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

1070
        match &frame.tracker {
12✔
1071
            Tracker::Uninit => Ok(false),
12✔
NEW
1072
            Tracker::Init => Ok(true),
×
NEW
1073
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
×
NEW
1074
            Tracker::Enum { data, variant, .. } => {
×
1075
                // Check if the field is already marked as set
NEW
1076
                if data.get(index) {
×
NEW
1077
                    return Ok(true);
×
NEW
1078
                }
×
1079

1080
                // For enum variant fields that are empty structs, they are always initialized
NEW
1081
                if let Some(field) = variant.data.fields.get(index) {
×
NEW
1082
                    if let Type::User(UserType::Struct(field_struct)) = field.shape.ty {
×
NEW
1083
                        if field_struct.fields.is_empty() {
×
NEW
1084
                            return Ok(true);
×
NEW
1085
                        }
×
NEW
1086
                    }
×
NEW
1087
                }
×
1088

NEW
1089
                Ok(false)
×
1090
            }
NEW
1091
            Tracker::Option { building_inner } => {
×
1092
                // For Options, index 0 represents the inner value
NEW
1093
                if index == 0 {
×
NEW
1094
                    Ok(!building_inner)
×
1095
                } else {
NEW
1096
                    Err(ReflectError::InvalidOperation {
×
NEW
1097
                        operation: "is_field_set",
×
NEW
1098
                        reason: "Option only has one field (index 0)",
×
NEW
1099
                    })
×
1100
                }
1101
            }
NEW
1102
            _ => Err(ReflectError::InvalidOperation {
×
NEW
1103
                operation: "is_field_set",
×
NEW
1104
                reason: "Current frame is not a struct, enum variant, or option",
×
NEW
1105
            }),
×
1106
        }
1107
    }
12✔
1108

1109
    /// Selects a field (by name) of a struct or enum data.
1110
    ///
1111
    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
1112
    /// and friends.
1113
    pub fn begin_field(&mut self, field_name: &str) -> Result<&mut Self, ReflectError> {
162✔
1114
        self.require_active()?;
162✔
1115

1116
        let frame = self.frames.last().unwrap();
162✔
1117
        let fields = self.get_fields()?;
162✔
1118
        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
239✔
1119
            return Err(ReflectError::FieldError {
3✔
1120
                shape: frame.shape,
3✔
1121
                field_error: facet_core::FieldError::NoSuchField,
3✔
1122
            });
3✔
1123
        };
1124
        self.begin_nth_field(idx)
157✔
1125
    }
162✔
1126

1127
    /// Begins the nth field of a struct, enum variant, or array, by index.
1128
    ///
1129
    /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
1130
    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
254✔
1131
        self.require_active()?;
254✔
1132
        let frame = self.frames.last_mut().unwrap();
254✔
1133

1134
        let next_frame = match frame.shape.ty {
254✔
1135
            Type::User(user_type) => match user_type {
216✔
1136
                UserType::Struct(struct_type) => {
174✔
1137
                    Self::begin_nth_struct_field(frame, struct_type, idx)?
174✔
1138
                }
1139
                UserType::Enum(_) => {
1140
                    // Check if we have a variant selected
1141
                    match &frame.tracker {
42✔
1142
                        Tracker::Enum { variant, .. } => {
42✔
1143
                            Self::begin_nth_enum_field(frame, variant, idx)?
42✔
1144
                        }
1145
                        _ => {
NEW
1146
                            return Err(ReflectError::OperationFailed {
×
NEW
1147
                                shape: frame.shape,
×
NEW
1148
                                operation: "must call select_variant before selecting enum fields",
×
NEW
1149
                            });
×
1150
                        }
1151
                    }
1152
                }
1153
                UserType::Union(_) => {
NEW
1154
                    return Err(ReflectError::OperationFailed {
×
NEW
1155
                        shape: frame.shape,
×
NEW
1156
                        operation: "cannot select a field from a union",
×
NEW
1157
                    });
×
1158
                }
1159
                UserType::Opaque => {
NEW
1160
                    return Err(ReflectError::OperationFailed {
×
NEW
1161
                        shape: frame.shape,
×
NEW
1162
                        operation: "cannot select a field from an opaque type",
×
NEW
1163
                    });
×
1164
                }
1165
            },
1166
            Type::Sequence(sequence_type) => match sequence_type {
38✔
1167
                SequenceType::Array(array_type) => {
38✔
1168
                    Self::begin_nth_array_element(frame, array_type, idx)?
38✔
1169
                }
1170
                SequenceType::Slice(_) => {
NEW
1171
                    return Err(ReflectError::OperationFailed {
×
NEW
1172
                        shape: frame.shape,
×
NEW
1173
                        operation: "cannot select a field from slices yet",
×
NEW
1174
                    });
×
1175
                }
1176
            },
1177
            _ => {
NEW
1178
                return Err(ReflectError::OperationFailed {
×
NEW
1179
                    shape: frame.shape,
×
NEW
1180
                    operation: "cannot select a field from this type",
×
NEW
1181
                });
×
1182
            }
1183
        };
1184

1185
        self.frames.push(next_frame);
253✔
1186
        Ok(self)
253✔
1187
    }
254✔
1188

1189
    /// Sets the given field to its default value, preferring:
1190
    ///
1191
    ///   * A `default = some_fn()` function
1192
    ///   * The field's `Default` implementation if any
1193
    ///
1194
    /// But without going all the way up to the parent struct's `Default` impl.
1195
    ///
1196
    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
NEW
1197
    pub fn set_nth_field_to_default(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
×
NEW
1198
        self.require_active()?;
×
1199

NEW
1200
        let frame = self.frames.last().unwrap();
×
NEW
1201
        let fields = self.get_fields()?;
×
1202

NEW
1203
        if idx >= fields.len() {
×
NEW
1204
            return Err(ReflectError::OperationFailed {
×
NEW
1205
                shape: frame.shape,
×
NEW
1206
                operation: "field index out of bounds",
×
NEW
1207
            });
×
NEW
1208
        }
×
1209

NEW
1210
        let field = fields[idx];
×
1211

1212
        // Check for field-level default function first, then type-level default
NEW
1213
        if let Some(field_default_fn) = field.vtable.default_fn {
×
NEW
1214
            self.begin_nth_field(idx)?;
×
1215
            // the field default fn should be well-behaved
1216
            unsafe {
NEW
1217
                self.set_from_function(|ptr| {
×
NEW
1218
                    field_default_fn(ptr);
×
NEW
1219
                    Ok(())
×
NEW
1220
                })?;
×
1221
            }
NEW
1222
            self.end()
×
NEW
1223
        } else if field.shape().is(Characteristic::Default) {
×
NEW
1224
            self.begin_nth_field(idx)?;
×
NEW
1225
            self.set_default()?;
×
NEW
1226
            self.end()
×
1227
        } else {
NEW
1228
            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
NEW
1229
                shape: field.shape(),
×
NEW
1230
            });
×
1231
        }
NEW
1232
    }
×
1233
}
1234

1235
////////////////////////////////////////////////////////////////////////////////////////////////////
1236
// Smart pointers
1237
////////////////////////////////////////////////////////////////////////////////////////////////////
1238
impl Partial<'_> {
1239
    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
1240
    pub fn begin_smart_ptr(&mut self) -> Result<&mut Self, ReflectError> {
21✔
1241
        crate::trace!("begin_smart_ptr()");
1242
        self.require_active()?;
21✔
1243
        let frame = self.frames.last_mut().unwrap();
21✔
1244

1245
        // Check that we have a SmartPointer
1246
        match &frame.shape.def {
21✔
1247
            Def::Pointer(smart_ptr_def) => {
21✔
1248
                // Check for supported smart pointer types
1249
                match smart_ptr_def.known {
21✔
1250
                    Some(KnownPointer::Box)
1251
                    | Some(KnownPointer::Rc)
1252
                    | Some(KnownPointer::Arc)
1253
                    | Some(KnownPointer::SharedReference) => {
21✔
1254
                        // Supported types, continue
21✔
1255
                    }
21✔
1256
                    _ => {
NEW
1257
                        return Err(ReflectError::OperationFailed {
×
NEW
1258
                            shape: frame.shape,
×
NEW
1259
                            operation: "only the following pointers are currently supported: Box<T>, Rc<T>, Arc<T>, and &T",
×
NEW
1260
                        });
×
1261
                    }
1262
                }
1263

1264
                // Get the pointee shape
1265
                let pointee_shape = match smart_ptr_def.pointee() {
21✔
1266
                    Some(shape) => shape,
21✔
1267
                    None => {
NEW
1268
                        return Err(ReflectError::OperationFailed {
×
NEW
1269
                            shape: frame.shape,
×
NEW
1270
                            operation: "Box must have a pointee shape",
×
NEW
1271
                        });
×
1272
                    }
1273
                };
1274

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

1279
                    if matches!(frame.tracker, Tracker::Uninit) {
7✔
1280
                        frame.tracker = Tracker::SmartPointer {
7✔
1281
                            is_initialized: false,
7✔
1282
                        };
7✔
1283
                    }
7✔
1284

1285
                    let inner_layout = match pointee_shape.layout.sized_layout() {
7✔
1286
                        Ok(layout) => layout,
7✔
1287
                        Err(_) => {
NEW
1288
                            return Err(ReflectError::Unsized {
×
NEW
1289
                                shape: pointee_shape,
×
NEW
1290
                                operation: "begin_smart_ptr, calculating inner value layout",
×
NEW
1291
                            });
×
1292
                        }
1293
                    };
1294
                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
7✔
1295
                    if inner_ptr.is_null() {
7✔
NEW
1296
                        return Err(ReflectError::OperationFailed {
×
NEW
1297
                            shape: frame.shape,
×
NEW
1298
                            operation: "failed to allocate memory for smart pointer inner value",
×
NEW
1299
                        });
×
1300
                    }
7✔
1301

1302
                    // Push a new frame for the inner value
1303
                    self.frames.push(Frame::new(
7✔
1304
                        PtrUninit::new(inner_ptr),
7✔
1305
                        pointee_shape,
7✔
1306
                        FrameOwnership::Owned,
7✔
1307
                    ));
1308
                } else {
1309
                    // pointee is unsized, we only support a handful of cases there
1310
                    if pointee_shape == str::SHAPE {
14✔
1311
                        crate::trace!("Pointee is str");
1312

1313
                        // Allocate space for a String
1314
                        let string_layout = String::SHAPE
8✔
1315
                            .layout
8✔
1316
                            .sized_layout()
8✔
1317
                            .expect("String must have a sized layout");
8✔
1318
                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
8✔
1319
                        if string_ptr.is_null() {
8✔
NEW
1320
                            alloc::alloc::handle_alloc_error(string_layout);
×
1321
                        }
8✔
1322
                        let mut frame = Frame::new(
8✔
1323
                            PtrUninit::new(string_ptr),
8✔
1324
                            String::SHAPE,
1325
                            FrameOwnership::Owned,
8✔
1326
                        );
1327
                        frame.tracker = Tracker::Uninit;
8✔
1328
                        self.frames.push(frame);
8✔
1329
                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
6✔
1330
                        crate::trace!("Pointee is [{}]", _st.t);
1331

1332
                        // Get the slice builder vtable
1333
                        let slice_builder_vtable = smart_ptr_def
6✔
1334
                            .vtable
6✔
1335
                            .slice_builder_vtable
6✔
1336
                            .ok_or(ReflectError::OperationFailed {
6✔
1337
                                shape: frame.shape,
6✔
1338
                                operation: "smart pointer does not support slice building",
6✔
1339
                            })?;
6✔
1340

1341
                        // Create a new builder
1342
                        let builder_ptr = (slice_builder_vtable.new_fn)();
6✔
1343

1344
                        // Deallocate the original Arc allocation before replacing with slice builder
1345
                        if let FrameOwnership::Owned = frame.ownership {
6✔
1346
                            if let Ok(layout) = frame.shape.layout.sized_layout() {
6✔
1347
                                if layout.size() > 0 {
6✔
1348
                                    unsafe {
6✔
1349
                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
6✔
1350
                                    };
6✔
1351
                                }
6✔
NEW
1352
                            }
×
NEW
1353
                        }
×
1354

1355
                        // Update the current frame to use the slice builder
1356
                        frame.data = PtrUninit::new(builder_ptr.as_mut_byte_ptr());
6✔
1357
                        frame.tracker = Tracker::SmartPointerSlice {
6✔
1358
                            vtable: slice_builder_vtable,
6✔
1359
                            building_item: false,
6✔
1360
                        };
6✔
1361
                        // The slice builder memory is managed by the vtable, not by us
1362
                        frame.ownership = FrameOwnership::ManagedElsewhere;
6✔
1363
                    } else {
NEW
1364
                        todo!("unsupported unsize pointee shape: {}", pointee_shape)
×
1365
                    }
1366
                }
1367

1368
                Ok(self)
21✔
1369
            }
NEW
1370
            _ => Err(ReflectError::OperationFailed {
×
NEW
1371
                shape: frame.shape,
×
NEW
1372
                operation: "push_smart_ptr can only be called on compatible types",
×
NEW
1373
            }),
×
1374
        }
1375
    }
21✔
1376
}
1377

1378
////////////////////////////////////////////////////////////////////////////////////////////////////
1379
// Lists
1380
////////////////////////////////////////////////////////////////////////////////////////////////////
1381
impl Partial<'_> {
1382
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
1383
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
1384
    /// `push`.
1385
    ///
1386
    /// `begin_list` does not clear the list if it was previously initialized.
1387
    /// `begin_list` does not push a new frame to the stack, and thus does not
1388
    /// require `end` to be called afterwards.
1389
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
36✔
1390
        crate::trace!("begin_list()");
1391
        self.require_active()?;
36✔
1392
        let frame = self.frames.last_mut().unwrap();
36✔
1393

1394
        match &frame.tracker {
36✔
1395
            Tracker::Uninit => {
28✔
1396
                // that's good, let's initialize it
28✔
1397
            }
28✔
1398
            Tracker::Init => {
1399
                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
1400
                frame.tracker = Tracker::List {
1✔
1401
                    is_initialized: true,
1✔
1402
                    current_child: false,
1✔
1403
                };
1✔
1404
                return Ok(self);
1✔
1405
            }
1406
            Tracker::List { is_initialized, .. } => {
1✔
1407
                if *is_initialized {
1✔
1408
                    // already initialized, nothing to do
1409
                    return Ok(self);
1✔
NEW
1410
                }
×
1411
            }
1412
            Tracker::SmartPointerSlice { .. } => {
1413
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
1414
                return Ok(self);
6✔
1415
            }
1416
            _ => {
NEW
1417
                return Err(ReflectError::UnexpectedTracker {
×
NEW
1418
                    message: "begin_list called but tracker isn't something list-like",
×
NEW
1419
                    current_tracker: frame.tracker.kind(),
×
NEW
1420
                });
×
1421
            }
1422
        };
1423

1424
        // Check that we have a List
1425
        let list_def = match &frame.shape.def {
28✔
1426
            Def::List(list_def) => list_def,
25✔
1427
            _ => {
1428
                return Err(ReflectError::OperationFailed {
3✔
1429
                    shape: frame.shape,
3✔
1430
                    operation: "begin_list can only be called on List types",
3✔
1431
                });
3✔
1432
            }
1433
        };
1434

1435
        // Check that we have init_in_place_with_capacity function
1436
        let init_fn = match list_def.vtable.init_in_place_with_capacity {
25✔
1437
            Some(f) => f,
25✔
1438
            None => {
NEW
1439
                return Err(ReflectError::OperationFailed {
×
NEW
1440
                    shape: frame.shape,
×
NEW
1441
                    operation: "list type does not support initialization with capacity",
×
NEW
1442
                });
×
1443
            }
1444
        };
1445

1446
        // Initialize the list with default capacity (0)
1447
        unsafe {
25✔
1448
            init_fn(frame.data, 0);
25✔
1449
        }
25✔
1450

1451
        // Update tracker to List state
1452
        frame.tracker = Tracker::List {
25✔
1453
            is_initialized: true,
25✔
1454
            current_child: false,
25✔
1455
        };
25✔
1456

1457
        Ok(self)
25✔
1458
    }
36✔
1459

1460
    /// Pushes an element to the list
1461
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
1462
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
72✔
1463
        crate::trace!("begin_list_item()");
1464
        self.require_active()?;
72✔
1465
        let frame = self.frames.last_mut().unwrap();
72✔
1466

1467
        // Check if we're building a smart pointer slice
1468
        if let Tracker::SmartPointerSlice {
1469
            building_item,
14✔
1470
            vtable: _,
1471
        } = &frame.tracker
72✔
1472
        {
1473
            if *building_item {
14✔
NEW
1474
                return Err(ReflectError::OperationFailed {
×
NEW
1475
                    shape: frame.shape,
×
NEW
1476
                    operation: "already building an item, call end() first",
×
NEW
1477
                });
×
1478
            }
14✔
1479

1480
            // Get the element type from the smart pointer's pointee
1481
            let element_shape = match &frame.shape.def {
14✔
1482
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
14✔
1483
                    Some(pointee_shape) => match &pointee_shape.ty {
14✔
1484
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
14✔
1485
                        _ => {
NEW
1486
                            return Err(ReflectError::OperationFailed {
×
NEW
1487
                                shape: frame.shape,
×
NEW
1488
                                operation: "smart pointer pointee is not a slice",
×
NEW
1489
                            });
×
1490
                        }
1491
                    },
1492
                    None => {
NEW
1493
                        return Err(ReflectError::OperationFailed {
×
NEW
1494
                            shape: frame.shape,
×
NEW
1495
                            operation: "smart pointer has no pointee",
×
NEW
1496
                        });
×
1497
                    }
1498
                },
1499
                _ => {
NEW
1500
                    return Err(ReflectError::OperationFailed {
×
NEW
1501
                        shape: frame.shape,
×
NEW
1502
                        operation: "expected smart pointer definition",
×
NEW
1503
                    });
×
1504
                }
1505
            };
1506

1507
            // Allocate space for the element
1508
            crate::trace!("Pointee is a slice of {element_shape}");
1509
            let element_layout = match element_shape.layout.sized_layout() {
14✔
1510
                Ok(layout) => layout,
14✔
1511
                Err(_) => {
NEW
1512
                    return Err(ReflectError::OperationFailed {
×
NEW
1513
                        shape: element_shape,
×
NEW
1514
                        operation: "cannot allocate unsized element",
×
NEW
1515
                    });
×
1516
                }
1517
            };
1518

1519
            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
14✔
1520
            if element_ptr.is_null() {
14✔
NEW
1521
                alloc::alloc::handle_alloc_error(element_layout);
×
1522
            }
14✔
1523

1524
            // Create and push the element frame
1525
            crate::trace!("Pushing element frame, which we just allocated");
1526
            let element_frame = Frame::new(
14✔
1527
                PtrUninit::new(element_ptr),
14✔
1528
                element_shape,
14✔
1529
                FrameOwnership::Owned,
14✔
1530
            );
1531
            self.frames.push(element_frame);
14✔
1532

1533
            // Mark that we're building an item
1534
            // We need to update the tracker after pushing the frame
1535
            let parent_idx = self.frames.len() - 2;
14✔
1536
            if let Tracker::SmartPointerSlice { building_item, .. } =
14✔
1537
                &mut self.frames[parent_idx].tracker
14✔
1538
            {
14✔
1539
                crate::trace!("Marking element frame as building item");
14✔
1540
                *building_item = true;
14✔
1541
            }
14✔
1542

1543
            return Ok(self);
14✔
1544
        }
58✔
1545

1546
        // Check that we have a List that's been initialized
1547
        let list_def = match &frame.shape.def {
58✔
1548
            Def::List(list_def) => list_def,
57✔
1549
            _ => {
1550
                return Err(ReflectError::OperationFailed {
1✔
1551
                    shape: frame.shape,
1✔
1552
                    operation: "push can only be called on List types",
1✔
1553
                });
1✔
1554
            }
1555
        };
1556

1557
        // Verify the tracker is in List state and initialized
1558
        match &mut frame.tracker {
57✔
1559
            Tracker::List {
1560
                is_initialized: true,
1561
                current_child,
57✔
1562
            } => {
1563
                if *current_child {
57✔
NEW
1564
                    return Err(ReflectError::OperationFailed {
×
NEW
1565
                        shape: frame.shape,
×
NEW
1566
                        operation: "already pushing an element, call pop() first",
×
NEW
1567
                    });
×
1568
                }
57✔
1569
                *current_child = true;
57✔
1570
            }
1571
            _ => {
NEW
1572
                return Err(ReflectError::OperationFailed {
×
NEW
1573
                    shape: frame.shape,
×
NEW
1574
                    operation: "must call begin_list() before push()",
×
NEW
1575
                });
×
1576
            }
1577
        }
1578

1579
        // Get the element shape
1580
        let element_shape = list_def.t();
57✔
1581

1582
        // Allocate space for the new element
1583
        let element_layout = match element_shape.layout.sized_layout() {
57✔
1584
            Ok(layout) => layout,
57✔
1585
            Err(_) => {
NEW
1586
                return Err(ReflectError::Unsized {
×
NEW
1587
                    shape: element_shape,
×
NEW
1588
                    operation: "begin_list_item: calculating element layout",
×
NEW
1589
                });
×
1590
            }
1591
        };
1592
        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
57✔
1593

1594
        if element_ptr.is_null() {
57✔
NEW
1595
            return Err(ReflectError::OperationFailed {
×
NEW
1596
                shape: frame.shape,
×
NEW
1597
                operation: "failed to allocate memory for list element",
×
NEW
1598
            });
×
1599
        }
57✔
1600

1601
        // Push a new frame for the element
1602
        self.frames.push(Frame::new(
57✔
1603
            PtrUninit::new(element_ptr),
57✔
1604
            element_shape,
57✔
1605
            FrameOwnership::Owned,
57✔
1606
        ));
1607

1608
        Ok(self)
57✔
1609
    }
72✔
1610
}
1611

1612
////////////////////////////////////////////////////////////////////////////////////////////////////
1613
// Maps
1614
////////////////////////////////////////////////////////////////////////////////////////////////////
1615
impl Partial<'_> {
1616
    /// Begins a map initialization operation
1617
    ///
1618
    /// This initializes the map with default capacity and allows inserting key-value pairs
1619
    /// It does _not_ push a new frame onto the stack.
1620
    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
12✔
1621
        self.require_active()?;
12✔
1622
        let frame = self.frames.last_mut().unwrap();
12✔
1623

1624
        // Check that we have a Map
1625
        let map_def = match &frame.shape.def {
12✔
1626
            Def::Map(map_def) => map_def,
12✔
1627
            _ => {
NEW
1628
                return Err(ReflectError::OperationFailed {
×
NEW
1629
                    shape: frame.shape,
×
NEW
1630
                    operation: "begin_map can only be called on Map types",
×
NEW
1631
                });
×
1632
            }
1633
        };
1634

1635
        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
12✔
1636

1637
        // Initialize the map with default capacity (0)
1638
        unsafe {
12✔
1639
            init_fn(frame.data, 0);
12✔
1640
        }
12✔
1641

1642
        // Update tracker to Map state
1643
        frame.tracker = Tracker::Map {
12✔
1644
            is_initialized: true,
12✔
1645
            insert_state: MapInsertState::Idle,
12✔
1646
        };
12✔
1647

1648
        Ok(self)
12✔
1649
    }
12✔
1650

1651
    /// Pushes a frame for the map key. After that, `set()` should be called
1652
    /// (or the key should be initialized somehow) and `end()` should be called
1653
    /// to pop the frame.
1654
    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
13✔
1655
        self.require_active()?;
13✔
1656
        let frame = self.frames.last_mut().unwrap();
13✔
1657

1658
        // Check that we have a Map and set up for key insertion
1659
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
13✔
1660
            (
1661
                Def::Map(map_def),
13✔
1662
                Tracker::Map {
1663
                    is_initialized: true,
1664
                    insert_state,
13✔
1665
                },
1666
            ) => {
1667
                match insert_state {
13✔
1668
                    MapInsertState::Idle => {
13✔
1669
                        // Start a new insert automatically
13✔
1670
                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
13✔
1671
                    }
13✔
NEW
1672
                    MapInsertState::PushingKey { key_ptr } => {
×
NEW
1673
                        if key_ptr.is_some() {
×
NEW
1674
                            return Err(ReflectError::OperationFailed {
×
NEW
1675
                                shape: frame.shape,
×
NEW
1676
                                operation: "already pushing a key, call end() first",
×
NEW
1677
                            });
×
NEW
1678
                        }
×
1679
                    }
1680
                    _ => {
NEW
1681
                        return Err(ReflectError::OperationFailed {
×
NEW
1682
                            shape: frame.shape,
×
NEW
1683
                            operation: "must complete current operation before begin_key()",
×
NEW
1684
                        });
×
1685
                    }
1686
                }
1687
                map_def
13✔
1688
            }
1689
            _ => {
NEW
1690
                return Err(ReflectError::OperationFailed {
×
NEW
1691
                    shape: frame.shape,
×
NEW
1692
                    operation: "must call begin_map() before begin_key()",
×
NEW
1693
                });
×
1694
            }
1695
        };
1696

1697
        // Get the key shape
1698
        let key_shape = map_def.k();
13✔
1699

1700
        // Allocate space for the key
1701
        let key_layout = match key_shape.layout.sized_layout() {
13✔
1702
            Ok(layout) => layout,
13✔
1703
            Err(_) => {
NEW
1704
                return Err(ReflectError::Unsized {
×
NEW
1705
                    shape: key_shape,
×
NEW
1706
                    operation: "begin_key allocating key",
×
NEW
1707
                });
×
1708
            }
1709
        };
1710
        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
13✔
1711
        if key_ptr_raw.is_null() {
13✔
NEW
1712
            return Err(ReflectError::OperationFailed {
×
NEW
1713
                shape: frame.shape,
×
NEW
1714
                operation: "failed to allocate memory for map key",
×
NEW
1715
            });
×
1716
        }
13✔
1717

1718
        // Store the key pointer in the insert state
1719
        match &mut frame.tracker {
13✔
1720
            Tracker::Map {
1721
                insert_state: MapInsertState::PushingKey { key_ptr: kp },
13✔
1722
                ..
1723
            } => {
13✔
1724
                *kp = Some(PtrUninit::new(key_ptr_raw));
13✔
1725
            }
13✔
NEW
1726
            _ => unreachable!(),
×
1727
        }
1728

1729
        // Push a new frame for the key
1730
        self.frames.push(Frame::new(
13✔
1731
            PtrUninit::new(key_ptr_raw),
13✔
1732
            key_shape,
13✔
1733
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
13✔
1734
        ));
1735

1736
        Ok(self)
13✔
1737
    }
13✔
1738

1739
    /// Pushes a frame for the map value
1740
    /// Must be called after the key has been set and popped
1741
    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
10✔
1742
        self.require_active()?;
10✔
1743
        let frame = self.frames.last_mut().unwrap();
10✔
1744

1745
        // Check that we have a Map in PushingValue state
1746
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
10✔
1747
            (
1748
                Def::Map(map_def),
10✔
1749
                Tracker::Map {
1750
                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
10✔
1751
                    ..
1752
                },
1753
            ) => {
1754
                if value_ptr.is_some() {
10✔
NEW
1755
                    return Err(ReflectError::OperationFailed {
×
NEW
1756
                        shape: frame.shape,
×
NEW
1757
                        operation: "already pushing a value, call pop() first",
×
NEW
1758
                    });
×
1759
                }
10✔
1760
                map_def
10✔
1761
            }
1762
            _ => {
NEW
1763
                return Err(ReflectError::OperationFailed {
×
NEW
1764
                    shape: frame.shape,
×
NEW
1765
                    operation: "must complete key before push_value()",
×
NEW
1766
                });
×
1767
            }
1768
        };
1769

1770
        // Get the value shape
1771
        let value_shape = map_def.v();
10✔
1772

1773
        // Allocate space for the value
1774
        let value_layout = match value_shape.layout.sized_layout() {
10✔
1775
            Ok(layout) => layout,
10✔
1776
            Err(_) => {
NEW
1777
                return Err(ReflectError::Unsized {
×
NEW
1778
                    shape: value_shape,
×
NEW
1779
                    operation: "begin_value allocating value",
×
NEW
1780
                });
×
1781
            }
1782
        };
1783
        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
10✔
1784

1785
        if value_ptr_raw.is_null() {
10✔
NEW
1786
            return Err(ReflectError::OperationFailed {
×
NEW
1787
                shape: frame.shape,
×
NEW
1788
                operation: "failed to allocate memory for map value",
×
NEW
1789
            });
×
1790
        }
10✔
1791

1792
        // Store the value pointer in the insert state
1793
        match &mut frame.tracker {
10✔
1794
            Tracker::Map {
1795
                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
10✔
1796
                ..
1797
            } => {
10✔
1798
                *vp = Some(PtrUninit::new(value_ptr_raw));
10✔
1799
            }
10✔
NEW
1800
            _ => unreachable!(),
×
1801
        }
1802

1803
        // Push a new frame for the value
1804
        self.frames.push(Frame::new(
10✔
1805
            PtrUninit::new(value_ptr_raw),
10✔
1806
            value_shape,
10✔
1807
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
10✔
1808
        ));
1809

1810
        Ok(self)
10✔
1811
    }
10✔
1812
}
1813

1814
////////////////////////////////////////////////////////////////////////////////////////////////////
1815
// Option / inner
1816
////////////////////////////////////////////////////////////////////////////////////////////////////
1817
impl Partial<'_> {
1818
    /// Begin building the Some variant of an Option
1819
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1✔
1820
        self.require_active()?;
1✔
1821
        let frame = self.frames.last_mut().unwrap();
1✔
1822

1823
        // Verify we're working with an Option
1824
        let option_def = match frame.shape.def {
1✔
1825
            Def::Option(def) => def,
1✔
1826
            _ => {
NEW
1827
                return Err(ReflectError::WasNotA {
×
NEW
1828
                    expected: "Option",
×
NEW
1829
                    actual: frame.shape,
×
NEW
1830
                });
×
1831
            }
1832
        };
1833

1834
        // Initialize the tracker for Option building
1835
        if matches!(frame.tracker, Tracker::Uninit) {
1✔
1836
            frame.tracker = Tracker::Option {
1✔
1837
                building_inner: true,
1✔
1838
            };
1✔
1839
        }
1✔
1840

1841
        // Get the inner type shape
1842
        let inner_shape = option_def.t;
1✔
1843

1844
        // Allocate memory for the inner value
1845
        let inner_layout =
1✔
1846
            inner_shape
1✔
1847
                .layout
1✔
1848
                .sized_layout()
1✔
1849
                .map_err(|_| ReflectError::Unsized {
1✔
NEW
1850
                    shape: inner_shape,
×
1851
                    operation: "begin_some, allocating Option inner value",
NEW
1852
                })?;
×
1853

1854
        let inner_data = if inner_layout.size() == 0 {
1✔
1855
            // For ZST, use a non-null but unallocated pointer
NEW
1856
            PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
1857
        } else {
1858
            // Allocate memory for the inner value
1859
            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1✔
1860
            if ptr.is_null() {
1✔
NEW
1861
                alloc::alloc::handle_alloc_error(inner_layout);
×
1862
            }
1✔
1863
            PtrUninit::new(ptr)
1✔
1864
        };
1865

1866
        // Create a new frame for the inner value
1867
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1✔
1868
        self.frames.push(inner_frame);
1✔
1869

1870
        Ok(self)
1✔
1871
    }
1✔
1872

1873
    /// Begin building the inner value of a wrapper type
NEW
1874
    pub fn begin_inner(&mut self) -> Result<&mut Self, ReflectError> {
×
NEW
1875
        self.require_active()?;
×
1876

1877
        // Get the inner shape and check for try_from
NEW
1878
        let (inner_shape, has_try_from, parent_shape) = {
×
NEW
1879
            let frame = self.frames.last().unwrap();
×
NEW
1880
            if let Some(inner_fn) = frame.shape.inner {
×
NEW
1881
                let inner_shape = inner_fn();
×
NEW
1882
                let has_try_from = frame
×
NEW
1883
                    .shape
×
NEW
1884
                    .vtable
×
NEW
1885
                    .sized()
×
NEW
1886
                    .and_then(|v| (v.try_from)())
×
NEW
1887
                    .is_some();
×
NEW
1888
                (Some(inner_shape), has_try_from, frame.shape)
×
1889
            } else {
NEW
1890
                (None, false, frame.shape)
×
1891
            }
1892
        };
1893

NEW
1894
        if let Some(inner_shape) = inner_shape {
×
NEW
1895
            if has_try_from {
×
1896
                // Create a conversion frame with the inner shape
1897

1898
                // For conversion frames, we leave the parent tracker unchanged
1899
                // This allows automatic conversion detection to work properly
1900

1901
                // Allocate memory for the inner value (conversion source)
NEW
1902
                let inner_layout =
×
NEW
1903
                    inner_shape
×
NEW
1904
                        .layout
×
NEW
1905
                        .sized_layout()
×
NEW
1906
                        .map_err(|_| ReflectError::Unsized {
×
NEW
1907
                            shape: inner_shape,
×
1908
                            operation: "begin_inner, getting inner layout",
NEW
1909
                        })?;
×
1910

NEW
1911
                let inner_data = if inner_layout.size() == 0 {
×
1912
                    // For ZST, use a non-null but unallocated pointer
NEW
1913
                    PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
1914
                } else {
1915
                    // Allocate memory for the inner value
NEW
1916
                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
×
NEW
1917
                    if ptr.is_null() {
×
NEW
1918
                        alloc::alloc::handle_alloc_error(inner_layout);
×
NEW
1919
                    }
×
NEW
1920
                    PtrUninit::new(ptr)
×
1921
                };
1922

1923
                // For conversion frames, we create a frame directly with the inner shape
1924
                // This allows setting values of the inner type which will be converted
1925
                // The automatic conversion detection in end() will handle the conversion
1926
                trace!(
1927
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
1928
                );
NEW
1929
                self.frames
×
NEW
1930
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
×
1931

NEW
1932
                Ok(self)
×
1933
            } else {
1934
                // For wrapper types without try_from, navigate to the first field
1935
                // This is a common pattern for newtype wrappers
1936
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
NEW
1937
                self.begin_nth_field(0)
×
1938
            }
1939
        } else {
NEW
1940
            Err(ReflectError::OperationFailed {
×
NEW
1941
                shape: parent_shape,
×
NEW
1942
                operation: "type does not have an inner value",
×
NEW
1943
            })
×
1944
        }
NEW
1945
    }
×
1946
}
1947

1948
////////////////////////////////////////////////////////////////////////////////////////////////////
1949
// Shorthands
1950
////////////////////////////////////////////////////////////////////////////////////////////////////
1951
impl<'facet> Partial<'facet> {
1952
    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
1953
    ///
1954
    /// Works on structs, enums (after selecting a variant) and arrays.
1955
    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
45✔
1956
    where
45✔
1957
        U: Facet<'facet>,
45✔
1958
    {
1959
        self.begin_nth_field(idx)?.set(value)?.end()
45✔
1960
    }
45✔
1961

1962
    /// Convenience shortcut: sets the named field to value, popping after.
1963
    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
70✔
1964
    where
70✔
1965
        U: Facet<'facet>,
70✔
1966
    {
1967
        self.begin_field(field_name)?.set(value)?.end()
70✔
1968
    }
70✔
1969

1970
    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
1971
    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2✔
1972
    where
2✔
1973
        U: Facet<'facet>,
2✔
1974
    {
1975
        self.begin_key()?.set(value)?.end()
2✔
1976
    }
2✔
1977

1978
    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
NEW
1979
    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
×
NEW
1980
    where
×
NEW
1981
        U: Facet<'facet>,
×
1982
    {
NEW
1983
        self.begin_value()?.set(value)?.end()
×
NEW
1984
    }
×
1985

1986
    /// Shorthand for: begin_list_item(), set(), end()
1987
    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
27✔
1988
    where
27✔
1989
        U: Facet<'facet>,
27✔
1990
    {
1991
        self.begin_list_item()?.set(value)?.end()
27✔
1992
    }
27✔
1993
}
1994

1995
////////////////////////////////////////////////////////////////////////////////////////////////////
1996
// Internal methods
1997
////////////////////////////////////////////////////////////////////////////////////////////////////
1998
impl<'facet> Partial<'facet> {
1999
    /// Preconditions:
2000
    ///
2001
    /// - `require_active()` check was made
2002
    /// - frame.shape.ty is an Enum
2003
    /// - `discriminant` is a valid discriminant
2004
    ///
2005
    /// Panics if current tracker is anything other than `Uninit`
2006
    /// (switching variants is not supported for now).
2007
    fn select_variant_internal(
38✔
2008
        &mut self,
38✔
2009
        enum_type: &EnumType,
38✔
2010
        variant: &'static Variant,
38✔
2011
    ) -> Result<(), ReflectError> {
38✔
2012
        // Check all invariants early before making any changes
2013
        let frame = self.frames.last().unwrap();
38✔
2014

2015
        // Check enum representation early
2016
        match enum_type.enum_repr {
38✔
2017
            EnumRepr::RustNPO => {
NEW
2018
                return Err(ReflectError::OperationFailed {
×
NEW
2019
                    shape: frame.shape,
×
NEW
2020
                    operation: "RustNPO enums are not supported for incremental building",
×
NEW
2021
                });
×
2022
            }
2023
            EnumRepr::U8
2024
            | EnumRepr::U16
2025
            | EnumRepr::U32
2026
            | EnumRepr::U64
2027
            | EnumRepr::I8
2028
            | EnumRepr::I16
2029
            | EnumRepr::I32
2030
            | EnumRepr::I64
2031
            | EnumRepr::USize
2032
            | EnumRepr::ISize => {
38✔
2033
                // These are supported, continue
38✔
2034
            }
38✔
2035
        }
2036

2037
        let Some(discriminant) = variant.discriminant else {
38✔
NEW
2038
            return Err(ReflectError::OperationFailed {
×
NEW
2039
                shape: frame.shape,
×
NEW
2040
                operation: "trying to select an enum variant without a discriminant",
×
NEW
2041
            });
×
2042
        };
2043

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

2047
        // Write the discriminant to memory
2048
        unsafe {
2049
            match enum_type.enum_repr {
38✔
2050
                EnumRepr::U8 => {
24✔
2051
                    let ptr = fr.data.as_mut_byte_ptr();
24✔
2052
                    *ptr = discriminant as u8;
24✔
2053
                }
24✔
2054
                EnumRepr::U16 => {
1✔
2055
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
1✔
2056
                    *ptr = discriminant as u16;
1✔
2057
                }
1✔
2058
                EnumRepr::U32 => {
8✔
2059
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
8✔
2060
                    *ptr = discriminant as u32;
8✔
2061
                }
8✔
NEW
2062
                EnumRepr::U64 => {
×
NEW
2063
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
NEW
2064
                    *ptr = discriminant as u64;
×
NEW
2065
                }
×
NEW
2066
                EnumRepr::I8 => {
×
NEW
2067
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
NEW
2068
                    *ptr = discriminant as i8;
×
NEW
2069
                }
×
2070
                EnumRepr::I16 => {
4✔
2071
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
2072
                    *ptr = discriminant as i16;
4✔
2073
                }
4✔
2074
                EnumRepr::I32 => {
1✔
2075
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
2076
                    *ptr = discriminant as i32;
1✔
2077
                }
1✔
NEW
2078
                EnumRepr::I64 => {
×
NEW
2079
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
NEW
2080
                    *ptr = discriminant;
×
NEW
2081
                }
×
NEW
2082
                EnumRepr::USize => {
×
NEW
2083
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
NEW
2084
                    *ptr = discriminant as usize;
×
NEW
2085
                }
×
NEW
2086
                EnumRepr::ISize => {
×
NEW
2087
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
NEW
2088
                    *ptr = discriminant as isize;
×
NEW
2089
                }
×
NEW
2090
                _ => unreachable!("Already checked enum representation above"),
×
2091
            }
2092
        }
2093

2094
        // Update tracker to track the variant
2095
        fr.tracker = Tracker::Enum {
38✔
2096
            variant,
38✔
2097
            data: ISet::new(variant.data.fields.len()),
38✔
2098
            current_child: None,
38✔
2099
        };
38✔
2100

2101
        Ok(())
38✔
2102
    }
38✔
2103

2104
    /// Used by `begin_field` etc. to get a list of fields to look through, errors out
2105
    /// if we're not pointing to a struct or an enum with an already-selected variant
2106
    fn get_fields(&self) -> Result<&'static [Field], ReflectError> {
162✔
2107
        let frame = self.frames.last().unwrap();
162✔
2108
        match frame.shape.ty {
162✔
NEW
2109
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
×
NEW
2110
                shape: frame.shape,
×
NEW
2111
                operation: "cannot select a field from a primitive type",
×
NEW
2112
            }),
×
NEW
2113
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
NEW
2114
                shape: frame.shape,
×
NEW
2115
                operation: "cannot select a field from a sequence type",
×
NEW
2116
            }),
×
2117
            Type::User(user_type) => match user_type {
162✔
2118
                UserType::Struct(struct_type) => Ok(struct_type.fields),
138✔
2119
                UserType::Enum(_) => {
2120
                    let Tracker::Enum { variant, .. } = &frame.tracker else {
23✔
2121
                        return Err(ReflectError::OperationFailed {
1✔
2122
                            shape: frame.shape,
1✔
2123
                            operation: "must select variant before selecting enum fields",
1✔
2124
                        });
1✔
2125
                    };
2126
                    Ok(variant.data.fields)
22✔
2127
                }
NEW
2128
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
2129
                    shape: frame.shape,
×
NEW
2130
                    operation: "cannot select a field from a union type",
×
NEW
2131
                }),
×
2132
                UserType::Opaque => Err(ReflectError::OperationFailed {
1✔
2133
                    shape: frame.shape,
1✔
2134
                    operation: "opaque types cannot be reflected upon",
1✔
2135
                }),
1✔
2136
            },
NEW
2137
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
NEW
2138
                shape: frame.shape,
×
NEW
2139
                operation: "cannot select a field from a pointer type",
×
NEW
2140
            }),
×
2141
        }
2142
    }
162✔
2143

2144
    /// Selects the nth field of a struct by index
2145
    fn begin_nth_struct_field(
174✔
2146
        frame: &mut Frame,
174✔
2147
        struct_type: StructType,
174✔
2148
        idx: usize,
174✔
2149
    ) -> Result<Frame, ReflectError> {
174✔
2150
        if idx >= struct_type.fields.len() {
174✔
NEW
2151
            return Err(ReflectError::OperationFailed {
×
NEW
2152
                shape: frame.shape,
×
NEW
2153
                operation: "field index out of bounds",
×
NEW
2154
            });
×
2155
        }
174✔
2156
        let field = &struct_type.fields[idx];
174✔
2157

2158
        if !matches!(frame.tracker, Tracker::Struct { .. }) {
174✔
2159
            frame.tracker = Tracker::Struct {
102✔
2160
                iset: ISet::new(struct_type.fields.len()),
102✔
2161
                current_child: None,
102✔
2162
            }
102✔
2163
        }
72✔
2164

2165
        let was_field_init = match &mut frame.tracker {
174✔
2166
            Tracker::Struct {
2167
                iset,
174✔
2168
                current_child,
174✔
2169
            } => {
2170
                *current_child = Some(idx);
174✔
2171
                iset.get(idx)
174✔
2172
            }
NEW
2173
            _ => unreachable!(),
×
2174
        };
2175

2176
        // Push a new frame for this field onto the frames stack.
2177
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
174✔
2178
        let field_shape = field.shape;
174✔
2179

2180
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
174✔
2181
        if was_field_init {
174✔
2182
            unsafe {
3✔
2183
                // the struct field tracker said so!
3✔
2184
                next_frame.mark_as_init();
3✔
2185
            }
3✔
2186
        }
171✔
2187

2188
        Ok(next_frame)
174✔
2189
    }
174✔
2190

2191
    /// Selects the nth element of an array by index
2192
    fn begin_nth_array_element(
38✔
2193
        frame: &mut Frame,
38✔
2194
        array_type: ArrayType,
38✔
2195
        idx: usize,
38✔
2196
    ) -> Result<Frame, ReflectError> {
38✔
2197
        if idx >= array_type.n {
38✔
2198
            return Err(ReflectError::OperationFailed {
1✔
2199
                shape: frame.shape,
1✔
2200
                operation: "array index out of bounds",
1✔
2201
            });
1✔
2202
        }
37✔
2203

2204
        if array_type.n > 63 {
37✔
NEW
2205
            return Err(ReflectError::OperationFailed {
×
NEW
2206
                shape: frame.shape,
×
NEW
2207
                operation: "arrays larger than 63 elements are not yet supported",
×
NEW
2208
            });
×
2209
        }
37✔
2210

2211
        // Ensure frame is in Array state
2212
        match &frame.tracker {
37✔
2213
            Tracker::Uninit => {
14✔
2214
                // this is fine
14✔
2215
                frame.tracker = Tracker::Array {
14✔
2216
                    iset: ISet::default(),
14✔
2217
                    current_child: None,
14✔
2218
                };
14✔
2219
            }
14✔
2220
            Tracker::Array { .. } => {
23✔
2221
                // fine too
23✔
2222
            }
23✔
NEW
2223
            _other => {
×
NEW
2224
                return Err(ReflectError::OperationFailed {
×
NEW
2225
                    shape: frame.shape,
×
NEW
2226
                    operation: "unexpected tracker state: expected Uninit or Array",
×
NEW
2227
                });
×
2228
            }
2229
        }
2230

2231
        match &mut frame.tracker {
37✔
2232
            Tracker::Array {
2233
                iset,
37✔
2234
                current_child,
37✔
2235
            } => {
2236
                *current_child = Some(idx);
37✔
2237
                let was_field_init = iset.get(idx);
37✔
2238

2239
                // Calculate the offset for this array element
2240
                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
37✔
NEW
2241
                    return Err(ReflectError::Unsized {
×
NEW
2242
                        shape: array_type.t,
×
NEW
2243
                        operation: "begin_nth_element, calculating array element offset",
×
NEW
2244
                    });
×
2245
                };
2246
                let offset = element_layout.size() * idx;
37✔
2247
                let element_data = unsafe { frame.data.field_uninit_at(offset) };
37✔
2248

2249
                let mut next_frame = Frame::new(element_data, array_type.t, FrameOwnership::Field);
37✔
2250
                if was_field_init {
37✔
2251
                    // safety: `iset` said it was initialized already
2252
                    unsafe {
1✔
2253
                        next_frame.mark_as_init();
1✔
2254
                    }
1✔
2255
                }
36✔
2256
                Ok(next_frame)
37✔
2257
            }
NEW
2258
            _ => unreachable!(),
×
2259
        }
2260
    }
38✔
2261

2262
    /// Selects the nth field of an enum variant by index
2263
    fn begin_nth_enum_field(
42✔
2264
        frame: &mut Frame,
42✔
2265
        variant: &'static Variant,
42✔
2266
        idx: usize,
42✔
2267
    ) -> Result<Frame, ReflectError> {
42✔
2268
        if idx >= variant.data.fields.len() {
42✔
NEW
2269
            return Err(ReflectError::OperationFailed {
×
NEW
2270
                shape: frame.shape,
×
NEW
2271
                operation: "enum field index out of bounds",
×
NEW
2272
            });
×
2273
        }
42✔
2274

2275
        let field = &variant.data.fields[idx];
42✔
2276

2277
        // Update tracker
2278
        let was_field_init = match &mut frame.tracker {
42✔
2279
            Tracker::Enum {
2280
                data,
42✔
2281
                current_child,
42✔
2282
                ..
2283
            } => {
2284
                *current_child = Some(idx);
42✔
2285
                data.get(idx)
42✔
2286
            }
2287
            _ => {
NEW
2288
                return Err(ReflectError::OperationFailed {
×
NEW
2289
                    shape: frame.shape,
×
NEW
2290
                    operation: "selecting a field on an enum requires selecting a variant first",
×
NEW
2291
                });
×
2292
            }
2293
        };
2294

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

2300
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
42✔
2301
        if was_field_init {
42✔
2302
            // SAFETY: `ISet` told us the field was initialized
2303
            unsafe {
1✔
2304
                next_frame.mark_as_init();
1✔
2305
            }
1✔
2306
        }
41✔
2307

2308
        Ok(next_frame)
42✔
2309
    }
42✔
2310

2311
    /// Require that the partial is active
2312
    #[inline]
2313
    pub(crate) fn require_active(&self) -> Result<(), ReflectError> {
1,903✔
2314
        if self.state == PartialState::Active {
1,903✔
2315
            Ok(())
1,902✔
2316
        } else {
2317
            Err(ReflectError::InvariantViolation {
1✔
2318
                invariant: "Cannot use Partial after it has been built or poisoned",
1✔
2319
            })
1✔
2320
        }
2321
    }
1,903✔
2322
}
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