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

facet-rs / facet / 17652885740

11 Sep 2025 05:50PM UTC coverage: 54.89% (+0.5%) from 54.357%
17652885740

Pull #882

github

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

1040 of 1638 new or added lines in 4 files covered. (63.49%)

3 existing lines in 1 file now uncovered.

4765 of 8681 relevant lines covered (54.89%)

36.61 hits per line

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

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

3
use core::marker::PhantomData;
4

5
use crate::{
6
    Guard, HeapValue, Partial, Peek, ReflectError, TypedPartial,
7
    partial::{Frame, FrameOwnership, MapInsertState, PartialState, Tracker, iset::ISet},
8
    trace,
9
};
10
use facet_core::{
11
    ArrayType, Def, EnumRepr, EnumType, Facet, Field, KnownPointer, PtrConst, PtrMut, PtrUninit,
12
    SequenceType, Shape, StructType, Type, UserType, Variant,
13
};
14

15
////////////////////////////////////////////////////////////////////////////////////////////////////
16
// Allocation, constructors etc.
17
////////////////////////////////////////////////////////////////////////////////////////////////////
18
impl<'facet> Partial<'facet> {
19
    /// Allocates a new [TypedPartial] instance on the heap, with the given shape and type
20
    pub fn alloc<T>() -> Result<TypedPartial<'facet, T>, ReflectError>
211✔
21
    where
211✔
22
        T: Facet<'facet> + ?Sized,
211✔
23
    {
24
        Ok(TypedPartial {
25
            inner: Self::alloc_shape(T::SHAPE)?,
211✔
26
            phantom: PhantomData,
210✔
27
        })
28
    }
211✔
29

30
    /// Allocates a new [Partial] instance on the heap, with the given shape.
31
    pub fn alloc_shape(shape: &'static Shape) -> Result<Self, ReflectError> {
226✔
32
        crate::trace!(
33
            "alloc_shape({:?}), with layout {:?}",
34
            shape,
35
            shape.layout.sized_layout()
36
        );
37

38
        let data = shape.allocate().map_err(|_| ReflectError::Unsized {
226✔
39
            shape,
1✔
40
            operation: "alloc_shape",
41
        })?;
1✔
42

43
        // Preallocate a couple of frames. The cost of allocating 4 frames is
44
        // basically identical to allocating 1 frame, so for every type that
45
        // has at least 1 level of nesting, this saves at least one guaranteed reallocation.
46
        let mut frames = Vec::with_capacity(4);
225✔
47
        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
225✔
48

49
        Ok(Self {
225✔
50
            frames,
225✔
51
            state: PartialState::Active,
225✔
52
            invariant: PhantomData,
225✔
53
        })
225✔
54
    }
226✔
55
}
56

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

74
    /// Returns the shape of the current frame.
75
    #[inline]
76
    pub fn shape(&self) -> &'static Shape {
7✔
77
        self.frames
7✔
78
            .last()
7✔
79
            .expect("Partial always has at least one frame")
7✔
80
            .shape
7✔
81
    }
7✔
82

83
    /// Pops the current frame off the stack, indicating we're done initializing the current field
84
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
343✔
85
        crate::trace!("end() called");
86
        self.require_active()?;
343✔
87

88
        // Special handling for SmartPointerSlice - convert builder to Arc
89
        if self.frames.len() == 1 {
343✔
90
            if let Tracker::SmartPointerSlice {
91
                vtable,
6✔
92
                building_item,
6✔
93
            } = &self.frames[0].tracker
7✔
94
            {
95
                if *building_item {
6✔
NEW
96
                    return Err(ReflectError::OperationFailed {
×
NEW
97
                        shape: self.frames[0].shape,
×
NEW
98
                        operation: "still building an item, finish it first",
×
NEW
99
                    });
×
100
                }
6✔
101

102
                // Convert the builder to Arc<[T]>
103
                let builder_ptr = unsafe { self.frames[0].data.assume_init() };
6✔
104
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
6✔
105

106
                // Update the frame to store the Arc
107
                self.frames[0].data = PtrUninit::new(arc_ptr.as_byte_ptr() as *mut u8);
6✔
108
                self.frames[0].tracker = Tracker::Init;
6✔
109
                // The builder memory has been consumed by convert_fn, so we no longer own it
110
                self.frames[0].ownership = FrameOwnership::ManagedElsewhere;
6✔
111

112
                return Ok(self);
6✔
113
            }
1✔
114
        }
336✔
115

116
        if self.frames.len() <= 1 {
337✔
117
            // Never pop the last/root frame.
118
            return Err(ReflectError::InvariantViolation {
1✔
119
                invariant: "Partial::end() called with only one frame on the stack",
1✔
120
            });
1✔
121
        }
336✔
122

123
        // Require that the top frame is fully initialized before popping.
124
        {
125
            let frame = self.frames.last().unwrap();
336✔
126
            trace!(
127
                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
128
                frame.shape,
129
                frame.tracker.kind()
130
            );
131
            frame.require_full_initialization()?
336✔
132
        }
133

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

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

140
        trace!(
141
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
142
            popped_frame.shape,
143
            popped_frame.tracker.kind(),
144
            parent_frame.shape,
145
            parent_frame.tracker.kind()
146
        );
147

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

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

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

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

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

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

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

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

NEW
228
                return Ok(self);
×
NEW
229
            }
×
230
        }
334✔
231

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

261
                    // The child frame contained the inner value
262
                    let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
7✔
263

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

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

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

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

302
                        // The child frame contained the element value
303
                        let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
51✔
304

305
                        // Use push to add element to the list
306
                        unsafe {
51✔
307
                            push_fn(
51✔
308
                                PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
51✔
309
                                element_ptr,
51✔
310
                            );
51✔
311
                        }
51✔
312

313
                        // Push moved out of popped_frame
314
                        popped_frame.tracker = Tracker::Uninit;
51✔
315
                        popped_frame.dealloc();
51✔
316

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

343
                            // Use insert to add key-value pair to the map
344
                            unsafe {
8✔
345
                                insert_fn(
8✔
346
                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
8✔
347
                                    PtrMut::new(key_ptr.as_mut_byte_ptr()),
8✔
348
                                    PtrMut::new(value_ptr.as_mut_byte_ptr()),
8✔
349
                                );
8✔
350
                            }
8✔
351

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

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

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

394
                        // Initialize the Option as Some(inner_value)
395
                        unsafe {
1✔
396
                            init_some_fn(parent_frame.data, inner_value_ptr);
1✔
397
                        }
1✔
398

399
                        // Deallocate the inner value's memory since init_some_fn moved it
400
                        if let FrameOwnership::Owned = popped_frame.ownership {
1✔
401
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
1✔
402
                                if layout.size() > 0 {
1✔
403
                                    unsafe {
1✔
404
                                        alloc::alloc::dealloc(
1✔
405
                                            popped_frame.data.as_mut_byte_ptr(),
1✔
406
                                            layout,
1✔
407
                                        );
1✔
408
                                    }
1✔
NEW
409
                                }
×
NEW
410
                            }
×
NEW
411
                        }
×
412

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

435
                        if !pointee.is_shape(str::SHAPE) {
5✔
NEW
436
                            return Err(ReflectError::InvariantViolation {
×
NEW
437
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
NEW
438
                            });
×
439
                        }
5✔
440

441
                        if !popped_frame.shape.is_shape(String::SHAPE) {
5✔
NEW
442
                            return Err(ReflectError::InvariantViolation {
×
NEW
443
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
NEW
444
                            });
×
445
                        }
5✔
446

447
                        popped_frame.require_full_initialization()?;
5✔
448

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

456
                        let Some(known) = smart_ptr_def.known else {
5✔
NEW
457
                            return Err(ReflectError::OperationFailed {
×
NEW
458
                                shape: parent_shape,
×
NEW
459
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
NEW
460
                            });
×
461
                        };
462

463
                        parent_frame.deinit();
5✔
464

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

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

505
                        parent_frame.tracker = Tracker::Init;
5✔
506

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

525
                    // Use the slice builder's push_fn to add the element
526
                    crate::trace!("Pushing element to slice builder");
527
                    unsafe {
14✔
528
                        let parent_ptr = parent_frame.data.assume_init();
14✔
529
                        (vtable.push_fn)(parent_ptr, element_ptr);
14✔
530
                    }
14✔
531

532
                    // Deallocate the element's memory since push_fn moved it
533
                    if let FrameOwnership::Owned = popped_frame.ownership {
14✔
534
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
14✔
535
                            if layout.size() > 0 {
14✔
536
                                unsafe {
14✔
537
                                    alloc::alloc::dealloc(
14✔
538
                                        popped_frame.data.as_mut_byte_ptr(),
14✔
539
                                        layout,
14✔
540
                                    );
14✔
541
                                }
14✔
NEW
542
                            }
×
NEW
543
                        }
×
NEW
544
                    }
×
545

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

557
        Ok(self)
334✔
558
    }
343✔
559

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

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

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

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

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

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

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

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

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

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

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

745
        // Prevent the value from being dropped since we've copied it
746
        core::mem::forget(value);
312✔
747

748
        Ok(self)
312✔
749
    }
313✔
750

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

772
        let fr = self.frames.last_mut().unwrap();
313✔
773
        crate::trace!("set_shape({src_shape:?})");
774

775
        if !fr.shape.is_shape(src_shape) {
313✔
776
            return Err(ReflectError::WrongShape {
1✔
777
                expected: fr.shape,
1✔
778
                actual: src_shape,
1✔
779
            });
1✔
780
        }
312✔
781

782
        fr.deinit();
312✔
783

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

792
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
793
        unsafe {
312✔
794
            fr.mark_as_init();
312✔
795
        }
312✔
796

797
        Ok(self)
312✔
798
    }
313✔
799

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

816
        frame.deinit();
4✔
817
        f(frame.data)?;
4✔
818

819
        // safety: `f()` returned Ok, so `frame.data` must be initialized
820
        unsafe {
4✔
821
            frame.mark_as_init();
4✔
822
        }
4✔
823

824
        Ok(self)
4✔
825
    }
4✔
826

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

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

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

856
    /// Copy a value from a Peek into the current position (safe alternative to set_shape)
857
    ///
858
    /// # Invariants
859
    ///
860
    /// `peek` must be a thin pointer, otherwise this panics.
NEW
861
    pub fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
NEW
862
        self.require_active()?;
×
863

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1189
////////////////////////////////////////////////////////////////////////////////////////////////////
1190
// Smart pointers
1191
////////////////////////////////////////////////////////////////////////////////////////////////////
1192
impl Partial<'_> {
1193
    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
1194
    pub fn begin_smart_ptr(&mut self) -> Result<&mut Self, ReflectError> {
21✔
1195
        crate::trace!("begin_smart_ptr()");
1196
        self.require_active()?;
21✔
1197
        let frame = self.frames.last_mut().unwrap();
21✔
1198

1199
        // Check that we have a SmartPointer
1200
        match &frame.shape.def {
21✔
1201
            Def::Pointer(smart_ptr_def) => {
21✔
1202
                // Check for supported smart pointer types
1203
                match smart_ptr_def.known {
21✔
1204
                    Some(KnownPointer::Box)
1205
                    | Some(KnownPointer::Rc)
1206
                    | Some(KnownPointer::Arc)
1207
                    | Some(KnownPointer::SharedReference) => {
21✔
1208
                        // Supported types, continue
21✔
1209
                    }
21✔
1210
                    _ => {
NEW
1211
                        return Err(ReflectError::OperationFailed {
×
NEW
1212
                            shape: frame.shape,
×
NEW
1213
                            operation: "only the following pointers are currently supported: Box<T>, Rc<T>, Arc<T>, and &T",
×
NEW
1214
                        });
×
1215
                    }
1216
                }
1217

1218
                // Get the pointee shape
1219
                let pointee_shape = match smart_ptr_def.pointee() {
21✔
1220
                    Some(shape) => shape,
21✔
1221
                    None => {
NEW
1222
                        return Err(ReflectError::OperationFailed {
×
NEW
1223
                            shape: frame.shape,
×
NEW
1224
                            operation: "Box must have a pointee shape",
×
NEW
1225
                        });
×
1226
                    }
1227
                };
1228

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

1233
                    if matches!(frame.tracker, Tracker::Uninit) {
7✔
1234
                        frame.tracker = Tracker::SmartPointer {
7✔
1235
                            is_initialized: false,
7✔
1236
                        };
7✔
1237
                    }
7✔
1238

1239
                    let inner_layout = match pointee_shape.layout.sized_layout() {
7✔
1240
                        Ok(layout) => layout,
7✔
1241
                        Err(_) => {
NEW
1242
                            return Err(ReflectError::Unsized {
×
NEW
1243
                                shape: pointee_shape,
×
NEW
1244
                                operation: "begin_smart_ptr, calculating inner value layout",
×
NEW
1245
                            });
×
1246
                        }
1247
                    };
1248
                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
7✔
1249
                    if inner_ptr.is_null() {
7✔
NEW
1250
                        return Err(ReflectError::OperationFailed {
×
NEW
1251
                            shape: frame.shape,
×
NEW
1252
                            operation: "failed to allocate memory for smart pointer inner value",
×
NEW
1253
                        });
×
1254
                    }
7✔
1255

1256
                    // Push a new frame for the inner value
1257
                    self.frames.push(Frame::new(
7✔
1258
                        PtrUninit::new(inner_ptr),
7✔
1259
                        pointee_shape,
7✔
1260
                        FrameOwnership::Owned,
7✔
1261
                    ));
1262
                } else {
1263
                    // pointee is unsized, we only support a handful of cases there
1264
                    if pointee_shape == str::SHAPE {
14✔
1265
                        crate::trace!("Pointee is str");
1266

1267
                        // Allocate space for a String
1268
                        let string_layout = String::SHAPE
8✔
1269
                            .layout
8✔
1270
                            .sized_layout()
8✔
1271
                            .expect("String must have a sized layout");
8✔
1272
                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
8✔
1273
                        if string_ptr.is_null() {
8✔
NEW
1274
                            alloc::alloc::handle_alloc_error(string_layout);
×
1275
                        }
8✔
1276
                        let mut frame = Frame::new(
8✔
1277
                            PtrUninit::new(string_ptr),
8✔
1278
                            String::SHAPE,
1279
                            FrameOwnership::Owned,
8✔
1280
                        );
1281
                        frame.tracker = Tracker::Uninit;
8✔
1282
                        self.frames.push(frame);
8✔
1283
                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
6✔
1284
                        crate::trace!("Pointee is [{}]", _st.t);
1285

1286
                        // Get the slice builder vtable
1287
                        let slice_builder_vtable = smart_ptr_def
6✔
1288
                            .vtable
6✔
1289
                            .slice_builder_vtable
6✔
1290
                            .ok_or(ReflectError::OperationFailed {
6✔
1291
                                shape: frame.shape,
6✔
1292
                                operation: "smart pointer does not support slice building",
6✔
1293
                            })?;
6✔
1294

1295
                        // Create a new builder
1296
                        let builder_ptr = (slice_builder_vtable.new_fn)();
6✔
1297

1298
                        // Deallocate the original Arc allocation before replacing with slice builder
1299
                        if let FrameOwnership::Owned = frame.ownership {
6✔
1300
                            if let Ok(layout) = frame.shape.layout.sized_layout() {
6✔
1301
                                if layout.size() > 0 {
6✔
1302
                                    unsafe {
6✔
1303
                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
6✔
1304
                                    };
6✔
1305
                                }
6✔
NEW
1306
                            }
×
NEW
1307
                        }
×
1308

1309
                        // Update the current frame to use the slice builder
1310
                        frame.data = PtrUninit::new(builder_ptr.as_mut_byte_ptr());
6✔
1311
                        frame.tracker = Tracker::SmartPointerSlice {
6✔
1312
                            vtable: slice_builder_vtable,
6✔
1313
                            building_item: false,
6✔
1314
                        };
6✔
1315
                        // The slice builder memory is managed by the vtable, not by us
1316
                        frame.ownership = FrameOwnership::ManagedElsewhere;
6✔
1317
                    } else {
NEW
1318
                        todo!("unsupported unsize pointee shape: {}", pointee_shape)
×
1319
                    }
1320
                }
1321

1322
                Ok(self)
21✔
1323
            }
NEW
1324
            _ => Err(ReflectError::OperationFailed {
×
NEW
1325
                shape: frame.shape,
×
NEW
1326
                operation: "push_smart_ptr can only be called on compatible types",
×
NEW
1327
            }),
×
1328
        }
1329
    }
21✔
1330
}
1331

1332
////////////////////////////////////////////////////////////////////////////////////////////////////
1333
// Lists
1334
////////////////////////////////////////////////////////////////////////////////////////////////////
1335
impl Partial<'_> {
1336
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
1337
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
1338
    /// `push`.
1339
    ///
1340
    /// `begin_list` does not clear the list if it was previously initialized.
1341
    /// `begin_list` does not push a new frame to the stack, and thus does not
1342
    /// require `end` to be called afterwards.
1343
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
36✔
1344
        crate::trace!("begin_list()");
1345
        self.require_active()?;
36✔
1346
        let frame = self.frames.last_mut().unwrap();
36✔
1347

1348
        match &frame.tracker {
36✔
1349
            Tracker::Uninit => {
28✔
1350
                // that's good, let's initialize it
28✔
1351
            }
28✔
1352
            Tracker::Init => {
1353
                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
1354
                frame.tracker = Tracker::List {
1✔
1355
                    is_initialized: true,
1✔
1356
                    current_child: false,
1✔
1357
                };
1✔
1358
                return Ok(self);
1✔
1359
            }
1360
            Tracker::List { is_initialized, .. } => {
1✔
1361
                if *is_initialized {
1✔
1362
                    // already initialized, nothing to do
1363
                    return Ok(self);
1✔
NEW
1364
                }
×
1365
            }
1366
            Tracker::SmartPointerSlice { .. } => {
1367
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
1368
                return Ok(self);
6✔
1369
            }
1370
            _ => {
NEW
1371
                return Err(ReflectError::UnexpectedTracker {
×
NEW
1372
                    message: "begin_list called but tracker isn't something list-like",
×
NEW
1373
                    current_tracker: frame.tracker.kind(),
×
NEW
1374
                });
×
1375
            }
1376
        };
1377

1378
        // Check that we have a List
1379
        let list_def = match &frame.shape.def {
28✔
1380
            Def::List(list_def) => list_def,
25✔
1381
            _ => {
1382
                return Err(ReflectError::OperationFailed {
3✔
1383
                    shape: frame.shape,
3✔
1384
                    operation: "begin_list can only be called on List types",
3✔
1385
                });
3✔
1386
            }
1387
        };
1388

1389
        // Check that we have init_in_place_with_capacity function
1390
        let init_fn = match list_def.vtable.init_in_place_with_capacity {
25✔
1391
            Some(f) => f,
25✔
1392
            None => {
NEW
1393
                return Err(ReflectError::OperationFailed {
×
NEW
1394
                    shape: frame.shape,
×
NEW
1395
                    operation: "list type does not support initialization with capacity",
×
NEW
1396
                });
×
1397
            }
1398
        };
1399

1400
        // Initialize the list with default capacity (0)
1401
        unsafe {
25✔
1402
            init_fn(frame.data, 0);
25✔
1403
        }
25✔
1404

1405
        // Update tracker to List state
1406
        frame.tracker = Tracker::List {
25✔
1407
            is_initialized: true,
25✔
1408
            current_child: false,
25✔
1409
        };
25✔
1410

1411
        Ok(self)
25✔
1412
    }
36✔
1413

1414
    /// Pushes an element to the list
1415
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
1416
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
72✔
1417
        crate::trace!("begin_list_item()");
1418
        self.require_active()?;
72✔
1419
        let frame = self.frames.last_mut().unwrap();
72✔
1420

1421
        // Check if we're building a smart pointer slice
1422
        if let Tracker::SmartPointerSlice {
1423
            building_item,
14✔
1424
            vtable: _,
1425
        } = &frame.tracker
72✔
1426
        {
1427
            if *building_item {
14✔
NEW
1428
                return Err(ReflectError::OperationFailed {
×
NEW
1429
                    shape: frame.shape,
×
NEW
1430
                    operation: "already building an item, call end() first",
×
NEW
1431
                });
×
1432
            }
14✔
1433

1434
            // Get the element type from the smart pointer's pointee
1435
            let element_shape = match &frame.shape.def {
14✔
1436
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
14✔
1437
                    Some(pointee_shape) => match &pointee_shape.ty {
14✔
1438
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
14✔
1439
                        _ => {
NEW
1440
                            return Err(ReflectError::OperationFailed {
×
NEW
1441
                                shape: frame.shape,
×
NEW
1442
                                operation: "smart pointer pointee is not a slice",
×
NEW
1443
                            });
×
1444
                        }
1445
                    },
1446
                    None => {
NEW
1447
                        return Err(ReflectError::OperationFailed {
×
NEW
1448
                            shape: frame.shape,
×
NEW
1449
                            operation: "smart pointer has no pointee",
×
NEW
1450
                        });
×
1451
                    }
1452
                },
1453
                _ => {
NEW
1454
                    return Err(ReflectError::OperationFailed {
×
NEW
1455
                        shape: frame.shape,
×
NEW
1456
                        operation: "expected smart pointer definition",
×
NEW
1457
                    });
×
1458
                }
1459
            };
1460

1461
            // Allocate space for the element
1462
            crate::trace!("Pointee is a slice of {element_shape}");
1463
            let element_layout = match element_shape.layout.sized_layout() {
14✔
1464
                Ok(layout) => layout,
14✔
1465
                Err(_) => {
NEW
1466
                    return Err(ReflectError::OperationFailed {
×
NEW
1467
                        shape: element_shape,
×
NEW
1468
                        operation: "cannot allocate unsized element",
×
NEW
1469
                    });
×
1470
                }
1471
            };
1472

1473
            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
14✔
1474
            if element_ptr.is_null() {
14✔
NEW
1475
                alloc::alloc::handle_alloc_error(element_layout);
×
1476
            }
14✔
1477

1478
            // Create and push the element frame
1479
            crate::trace!("Pushing element frame, which we just allocated");
1480
            let element_frame = Frame::new(
14✔
1481
                PtrUninit::new(element_ptr),
14✔
1482
                element_shape,
14✔
1483
                FrameOwnership::Owned,
14✔
1484
            );
1485
            self.frames.push(element_frame);
14✔
1486

1487
            // Mark that we're building an item
1488
            // We need to update the tracker after pushing the frame
1489
            let parent_idx = self.frames.len() - 2;
14✔
1490
            if let Tracker::SmartPointerSlice { building_item, .. } =
14✔
1491
                &mut self.frames[parent_idx].tracker
14✔
1492
            {
14✔
1493
                crate::trace!("Marking element frame as building item");
14✔
1494
                *building_item = true;
14✔
1495
            }
14✔
1496

1497
            return Ok(self);
14✔
1498
        }
58✔
1499

1500
        // Check that we have a List that's been initialized
1501
        let list_def = match &frame.shape.def {
58✔
1502
            Def::List(list_def) => list_def,
57✔
1503
            _ => {
1504
                return Err(ReflectError::OperationFailed {
1✔
1505
                    shape: frame.shape,
1✔
1506
                    operation: "push can only be called on List types",
1✔
1507
                });
1✔
1508
            }
1509
        };
1510

1511
        // Verify the tracker is in List state and initialized
1512
        match &mut frame.tracker {
57✔
1513
            Tracker::List {
1514
                is_initialized: true,
1515
                current_child,
57✔
1516
            } => {
1517
                if *current_child {
57✔
NEW
1518
                    return Err(ReflectError::OperationFailed {
×
NEW
1519
                        shape: frame.shape,
×
NEW
1520
                        operation: "already pushing an element, call pop() first",
×
NEW
1521
                    });
×
1522
                }
57✔
1523
                *current_child = true;
57✔
1524
            }
1525
            _ => {
NEW
1526
                return Err(ReflectError::OperationFailed {
×
NEW
1527
                    shape: frame.shape,
×
NEW
1528
                    operation: "must call begin_list() before push()",
×
NEW
1529
                });
×
1530
            }
1531
        }
1532

1533
        // Get the element shape
1534
        let element_shape = list_def.t();
57✔
1535

1536
        // Allocate space for the new element
1537
        let element_layout = match element_shape.layout.sized_layout() {
57✔
1538
            Ok(layout) => layout,
57✔
1539
            Err(_) => {
NEW
1540
                return Err(ReflectError::Unsized {
×
NEW
1541
                    shape: element_shape,
×
NEW
1542
                    operation: "begin_list_item: calculating element layout",
×
NEW
1543
                });
×
1544
            }
1545
        };
1546
        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
57✔
1547

1548
        if element_ptr.is_null() {
57✔
NEW
1549
            return Err(ReflectError::OperationFailed {
×
NEW
1550
                shape: frame.shape,
×
NEW
1551
                operation: "failed to allocate memory for list element",
×
NEW
1552
            });
×
1553
        }
57✔
1554

1555
        // Push a new frame for the element
1556
        self.frames.push(Frame::new(
57✔
1557
            PtrUninit::new(element_ptr),
57✔
1558
            element_shape,
57✔
1559
            FrameOwnership::Owned,
57✔
1560
        ));
1561

1562
        Ok(self)
57✔
1563
    }
72✔
1564
}
1565

1566
////////////////////////////////////////////////////////////////////////////////////////////////////
1567
// Maps
1568
////////////////////////////////////////////////////////////////////////////////////////////////////
1569
impl Partial<'_> {
1570
    /// Begins a map initialization operation
1571
    ///
1572
    /// This initializes the map with default capacity and allows inserting key-value pairs
1573
    /// It does _not_ push a new frame onto the stack.
1574
    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
12✔
1575
        self.require_active()?;
12✔
1576
        let frame = self.frames.last_mut().unwrap();
12✔
1577

1578
        // Check that we have a Map
1579
        let map_def = match &frame.shape.def {
12✔
1580
            Def::Map(map_def) => map_def,
12✔
1581
            _ => {
NEW
1582
                return Err(ReflectError::OperationFailed {
×
NEW
1583
                    shape: frame.shape,
×
NEW
1584
                    operation: "begin_map can only be called on Map types",
×
NEW
1585
                });
×
1586
            }
1587
        };
1588

1589
        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
12✔
1590

1591
        // Initialize the map with default capacity (0)
1592
        unsafe {
12✔
1593
            init_fn(frame.data, 0);
12✔
1594
        }
12✔
1595

1596
        // Update tracker to Map state
1597
        frame.tracker = Tracker::Map {
12✔
1598
            is_initialized: true,
12✔
1599
            insert_state: MapInsertState::Idle,
12✔
1600
        };
12✔
1601

1602
        Ok(self)
12✔
1603
    }
12✔
1604

1605
    /// Pushes a frame for the map key. After that, `set()` should be called
1606
    /// (or the key should be initialized somehow) and `end()` should be called
1607
    /// to pop the frame.
1608
    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
13✔
1609
        self.require_active()?;
13✔
1610
        let frame = self.frames.last_mut().unwrap();
13✔
1611

1612
        // Check that we have a Map and set up for key insertion
1613
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
13✔
1614
            (
1615
                Def::Map(map_def),
13✔
1616
                Tracker::Map {
1617
                    is_initialized: true,
1618
                    insert_state,
13✔
1619
                },
1620
            ) => {
1621
                match insert_state {
13✔
1622
                    MapInsertState::Idle => {
13✔
1623
                        // Start a new insert automatically
13✔
1624
                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
13✔
1625
                    }
13✔
NEW
1626
                    MapInsertState::PushingKey { key_ptr } => {
×
NEW
1627
                        if key_ptr.is_some() {
×
NEW
1628
                            return Err(ReflectError::OperationFailed {
×
NEW
1629
                                shape: frame.shape,
×
NEW
1630
                                operation: "already pushing a key, call end() first",
×
NEW
1631
                            });
×
NEW
1632
                        }
×
1633
                    }
1634
                    _ => {
NEW
1635
                        return Err(ReflectError::OperationFailed {
×
NEW
1636
                            shape: frame.shape,
×
NEW
1637
                            operation: "must complete current operation before begin_key()",
×
NEW
1638
                        });
×
1639
                    }
1640
                }
1641
                map_def
13✔
1642
            }
1643
            _ => {
NEW
1644
                return Err(ReflectError::OperationFailed {
×
NEW
1645
                    shape: frame.shape,
×
NEW
1646
                    operation: "must call begin_map() before begin_key()",
×
NEW
1647
                });
×
1648
            }
1649
        };
1650

1651
        // Get the key shape
1652
        let key_shape = map_def.k();
13✔
1653

1654
        // Allocate space for the key
1655
        let key_layout = match key_shape.layout.sized_layout() {
13✔
1656
            Ok(layout) => layout,
13✔
1657
            Err(_) => {
NEW
1658
                return Err(ReflectError::Unsized {
×
NEW
1659
                    shape: key_shape,
×
NEW
1660
                    operation: "begin_key allocating key",
×
NEW
1661
                });
×
1662
            }
1663
        };
1664
        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
13✔
1665
        if key_ptr_raw.is_null() {
13✔
NEW
1666
            return Err(ReflectError::OperationFailed {
×
NEW
1667
                shape: frame.shape,
×
NEW
1668
                operation: "failed to allocate memory for map key",
×
NEW
1669
            });
×
1670
        }
13✔
1671

1672
        // Store the key pointer in the insert state
1673
        match &mut frame.tracker {
13✔
1674
            Tracker::Map {
1675
                insert_state: MapInsertState::PushingKey { key_ptr: kp },
13✔
1676
                ..
1677
            } => {
13✔
1678
                *kp = Some(PtrUninit::new(key_ptr_raw));
13✔
1679
            }
13✔
NEW
1680
            _ => unreachable!(),
×
1681
        }
1682

1683
        // Push a new frame for the key
1684
        self.frames.push(Frame::new(
13✔
1685
            PtrUninit::new(key_ptr_raw),
13✔
1686
            key_shape,
13✔
1687
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
13✔
1688
        ));
1689

1690
        Ok(self)
13✔
1691
    }
13✔
1692

1693
    /// Pushes a frame for the map value
1694
    /// Must be called after the key has been set and popped
1695
    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
10✔
1696
        self.require_active()?;
10✔
1697
        let frame = self.frames.last_mut().unwrap();
10✔
1698

1699
        // Check that we have a Map in PushingValue state
1700
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
10✔
1701
            (
1702
                Def::Map(map_def),
10✔
1703
                Tracker::Map {
1704
                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
10✔
1705
                    ..
1706
                },
1707
            ) => {
1708
                if value_ptr.is_some() {
10✔
NEW
1709
                    return Err(ReflectError::OperationFailed {
×
NEW
1710
                        shape: frame.shape,
×
NEW
1711
                        operation: "already pushing a value, call pop() first",
×
NEW
1712
                    });
×
1713
                }
10✔
1714
                map_def
10✔
1715
            }
1716
            _ => {
NEW
1717
                return Err(ReflectError::OperationFailed {
×
NEW
1718
                    shape: frame.shape,
×
NEW
1719
                    operation: "must complete key before push_value()",
×
NEW
1720
                });
×
1721
            }
1722
        };
1723

1724
        // Get the value shape
1725
        let value_shape = map_def.v();
10✔
1726

1727
        // Allocate space for the value
1728
        let value_layout = match value_shape.layout.sized_layout() {
10✔
1729
            Ok(layout) => layout,
10✔
1730
            Err(_) => {
NEW
1731
                return Err(ReflectError::Unsized {
×
NEW
1732
                    shape: value_shape,
×
NEW
1733
                    operation: "begin_value allocating value",
×
NEW
1734
                });
×
1735
            }
1736
        };
1737
        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
10✔
1738

1739
        if value_ptr_raw.is_null() {
10✔
NEW
1740
            return Err(ReflectError::OperationFailed {
×
NEW
1741
                shape: frame.shape,
×
NEW
1742
                operation: "failed to allocate memory for map value",
×
NEW
1743
            });
×
1744
        }
10✔
1745

1746
        // Store the value pointer in the insert state
1747
        match &mut frame.tracker {
10✔
1748
            Tracker::Map {
1749
                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
10✔
1750
                ..
1751
            } => {
10✔
1752
                *vp = Some(PtrUninit::new(value_ptr_raw));
10✔
1753
            }
10✔
NEW
1754
            _ => unreachable!(),
×
1755
        }
1756

1757
        // Push a new frame for the value
1758
        self.frames.push(Frame::new(
10✔
1759
            PtrUninit::new(value_ptr_raw),
10✔
1760
            value_shape,
10✔
1761
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
10✔
1762
        ));
1763

1764
        Ok(self)
10✔
1765
    }
10✔
1766
}
1767

1768
////////////////////////////////////////////////////////////////////////////////////////////////////
1769
// Option / inner
1770
////////////////////////////////////////////////////////////////////////////////////////////////////
1771
impl Partial<'_> {
1772
    /// Begin building the Some variant of an Option
1773
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1✔
1774
        self.require_active()?;
1✔
1775
        let frame = self.frames.last_mut().unwrap();
1✔
1776

1777
        // Verify we're working with an Option
1778
        let option_def = match frame.shape.def {
1✔
1779
            Def::Option(def) => def,
1✔
1780
            _ => {
NEW
1781
                return Err(ReflectError::WasNotA {
×
NEW
1782
                    expected: "Option",
×
NEW
1783
                    actual: frame.shape,
×
NEW
1784
                });
×
1785
            }
1786
        };
1787

1788
        // Initialize the tracker for Option building
1789
        if matches!(frame.tracker, Tracker::Uninit) {
1✔
1790
            frame.tracker = Tracker::Option {
1✔
1791
                building_inner: true,
1✔
1792
            };
1✔
1793
        }
1✔
1794

1795
        // Get the inner type shape
1796
        let inner_shape = option_def.t;
1✔
1797

1798
        // Allocate memory for the inner value
1799
        let inner_layout =
1✔
1800
            inner_shape
1✔
1801
                .layout
1✔
1802
                .sized_layout()
1✔
1803
                .map_err(|_| ReflectError::Unsized {
1✔
NEW
1804
                    shape: inner_shape,
×
1805
                    operation: "begin_some, allocating Option inner value",
NEW
1806
                })?;
×
1807

1808
        let inner_data = if inner_layout.size() == 0 {
1✔
1809
            // For ZST, use a non-null but unallocated pointer
NEW
1810
            PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
1811
        } else {
1812
            // Allocate memory for the inner value
1813
            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1✔
1814
            if ptr.is_null() {
1✔
NEW
1815
                alloc::alloc::handle_alloc_error(inner_layout);
×
1816
            }
1✔
1817
            PtrUninit::new(ptr)
1✔
1818
        };
1819

1820
        // Create a new frame for the inner value
1821
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1✔
1822
        self.frames.push(inner_frame);
1✔
1823

1824
        Ok(self)
1✔
1825
    }
1✔
1826

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

1831
        // Get the inner shape and check for try_from
NEW
1832
        let (inner_shape, has_try_from, parent_shape) = {
×
NEW
1833
            let frame = self.frames.last().unwrap();
×
NEW
1834
            if let Some(inner_fn) = frame.shape.inner {
×
NEW
1835
                let inner_shape = inner_fn();
×
NEW
1836
                let has_try_from = frame
×
NEW
1837
                    .shape
×
NEW
1838
                    .vtable
×
NEW
1839
                    .sized()
×
NEW
1840
                    .and_then(|v| (v.try_from)())
×
NEW
1841
                    .is_some();
×
NEW
1842
                (Some(inner_shape), has_try_from, frame.shape)
×
1843
            } else {
NEW
1844
                (None, false, frame.shape)
×
1845
            }
1846
        };
1847

NEW
1848
        if let Some(inner_shape) = inner_shape {
×
NEW
1849
            if has_try_from {
×
1850
                // Create a conversion frame with the inner shape
1851

1852
                // For conversion frames, we leave the parent tracker unchanged
1853
                // This allows automatic conversion detection to work properly
1854

1855
                // Allocate memory for the inner value (conversion source)
NEW
1856
                let inner_layout =
×
NEW
1857
                    inner_shape
×
NEW
1858
                        .layout
×
NEW
1859
                        .sized_layout()
×
NEW
1860
                        .map_err(|_| ReflectError::Unsized {
×
NEW
1861
                            shape: inner_shape,
×
1862
                            operation: "begin_inner, getting inner layout",
NEW
1863
                        })?;
×
1864

NEW
1865
                let inner_data = if inner_layout.size() == 0 {
×
1866
                    // For ZST, use a non-null but unallocated pointer
NEW
1867
                    PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
1868
                } else {
1869
                    // Allocate memory for the inner value
NEW
1870
                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
×
NEW
1871
                    if ptr.is_null() {
×
NEW
1872
                        alloc::alloc::handle_alloc_error(inner_layout);
×
NEW
1873
                    }
×
NEW
1874
                    PtrUninit::new(ptr)
×
1875
                };
1876

1877
                // For conversion frames, we create a frame directly with the inner shape
1878
                // This allows setting values of the inner type which will be converted
1879
                // The automatic conversion detection in end() will handle the conversion
1880
                trace!(
1881
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
1882
                );
NEW
1883
                self.frames
×
NEW
1884
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
×
1885

NEW
1886
                Ok(self)
×
1887
            } else {
1888
                // For wrapper types without try_from, navigate to the first field
1889
                // This is a common pattern for newtype wrappers
1890
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
NEW
1891
                self.begin_nth_field(0)
×
1892
            }
1893
        } else {
NEW
1894
            Err(ReflectError::OperationFailed {
×
NEW
1895
                shape: parent_shape,
×
NEW
1896
                operation: "type does not have an inner value",
×
NEW
1897
            })
×
1898
        }
NEW
1899
    }
×
1900
}
1901

1902
////////////////////////////////////////////////////////////////////////////////////////////////////
1903
// Shorthands
1904
////////////////////////////////////////////////////////////////////////////////////////////////////
1905
impl<'facet> Partial<'facet> {
1906
    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
1907
    ///
1908
    /// Works on structs, enums (after selecting a variant) and arrays.
1909
    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
45✔
1910
    where
45✔
1911
        U: Facet<'facet>,
45✔
1912
    {
1913
        self.begin_nth_field(idx)?.set(value)?.end()
45✔
1914
    }
45✔
1915

1916
    /// Convenience shortcut: sets the named field to value, popping after.
1917
    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
70✔
1918
    where
70✔
1919
        U: Facet<'facet>,
70✔
1920
    {
1921
        self.begin_field(field_name)?.set(value)?.end()
70✔
1922
    }
70✔
1923

1924
    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
1925
    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2✔
1926
    where
2✔
1927
        U: Facet<'facet>,
2✔
1928
    {
1929
        self.begin_key()?.set(value)?.end()
2✔
1930
    }
2✔
1931

1932
    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
NEW
1933
    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
×
NEW
1934
    where
×
NEW
1935
        U: Facet<'facet>,
×
1936
    {
NEW
1937
        self.begin_value()?.set(value)?.end()
×
NEW
1938
    }
×
1939

1940
    /// Shorthand for: begin_list_item(), set(), end()
1941
    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
27✔
1942
    where
27✔
1943
        U: Facet<'facet>,
27✔
1944
    {
1945
        self.begin_list_item()?.set(value)?.end()
27✔
1946
    }
27✔
1947
}
1948

1949
////////////////////////////////////////////////////////////////////////////////////////////////////
1950
// Internal methods
1951
////////////////////////////////////////////////////////////////////////////////////////////////////
1952
impl<'facet> Partial<'facet> {
1953
    /// Preconditions:
1954
    ///
1955
    /// - `require_active()` check was made
1956
    /// - frame.shape.ty is an Enum
1957
    /// - `discriminant` is a valid discriminant
1958
    ///
1959
    /// Panics if current tracker is anything other than `Uninit`
1960
    /// (switching variants is not supported for now).
1961
    fn select_variant_internal(
38✔
1962
        &mut self,
38✔
1963
        enum_type: &EnumType,
38✔
1964
        variant: &'static Variant,
38✔
1965
    ) -> Result<(), ReflectError> {
38✔
1966
        // Check all invariants early before making any changes
1967
        let frame = self.frames.last().unwrap();
38✔
1968

1969
        // Check enum representation early
1970
        match enum_type.enum_repr {
38✔
1971
            EnumRepr::RustNPO => {
NEW
1972
                return Err(ReflectError::OperationFailed {
×
NEW
1973
                    shape: frame.shape,
×
NEW
1974
                    operation: "RustNPO enums are not supported for incremental building",
×
NEW
1975
                });
×
1976
            }
1977
            EnumRepr::U8
1978
            | EnumRepr::U16
1979
            | EnumRepr::U32
1980
            | EnumRepr::U64
1981
            | EnumRepr::I8
1982
            | EnumRepr::I16
1983
            | EnumRepr::I32
1984
            | EnumRepr::I64
1985
            | EnumRepr::USize
1986
            | EnumRepr::ISize => {
38✔
1987
                // These are supported, continue
38✔
1988
            }
38✔
1989
        }
1990

1991
        let Some(discriminant) = variant.discriminant else {
38✔
NEW
1992
            return Err(ReflectError::OperationFailed {
×
NEW
1993
                shape: frame.shape,
×
NEW
1994
                operation: "trying to select an enum variant without a discriminant",
×
NEW
1995
            });
×
1996
        };
1997

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

2001
        // Write the discriminant to memory
2002
        unsafe {
2003
            match enum_type.enum_repr {
38✔
2004
                EnumRepr::U8 => {
24✔
2005
                    let ptr = fr.data.as_mut_byte_ptr();
24✔
2006
                    *ptr = discriminant as u8;
24✔
2007
                }
24✔
2008
                EnumRepr::U16 => {
1✔
2009
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
1✔
2010
                    *ptr = discriminant as u16;
1✔
2011
                }
1✔
2012
                EnumRepr::U32 => {
8✔
2013
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
8✔
2014
                    *ptr = discriminant as u32;
8✔
2015
                }
8✔
NEW
2016
                EnumRepr::U64 => {
×
NEW
2017
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
NEW
2018
                    *ptr = discriminant as u64;
×
NEW
2019
                }
×
NEW
2020
                EnumRepr::I8 => {
×
NEW
2021
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
NEW
2022
                    *ptr = discriminant as i8;
×
NEW
2023
                }
×
2024
                EnumRepr::I16 => {
4✔
2025
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
2026
                    *ptr = discriminant as i16;
4✔
2027
                }
4✔
2028
                EnumRepr::I32 => {
1✔
2029
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
2030
                    *ptr = discriminant as i32;
1✔
2031
                }
1✔
NEW
2032
                EnumRepr::I64 => {
×
NEW
2033
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
NEW
2034
                    *ptr = discriminant;
×
NEW
2035
                }
×
NEW
2036
                EnumRepr::USize => {
×
NEW
2037
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
NEW
2038
                    *ptr = discriminant as usize;
×
NEW
2039
                }
×
NEW
2040
                EnumRepr::ISize => {
×
NEW
2041
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
NEW
2042
                    *ptr = discriminant as isize;
×
NEW
2043
                }
×
NEW
2044
                _ => unreachable!("Already checked enum representation above"),
×
2045
            }
2046
        }
2047

2048
        // Update tracker to track the variant
2049
        fr.tracker = Tracker::Enum {
38✔
2050
            variant,
38✔
2051
            data: ISet::new(variant.data.fields.len()),
38✔
2052
            current_child: None,
38✔
2053
        };
38✔
2054

2055
        Ok(())
38✔
2056
    }
38✔
2057

2058
    /// Used by `begin_field` etc. to get a list of fields to look through, errors out
2059
    /// if we're not pointing to a struct or an enum with an already-selected variant
2060
    fn get_fields(&self) -> Result<&'static [Field], ReflectError> {
162✔
2061
        let frame = self.frames.last().unwrap();
162✔
2062
        match frame.shape.ty {
162✔
NEW
2063
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
×
NEW
2064
                shape: frame.shape,
×
NEW
2065
                operation: "cannot select a field from a primitive type",
×
NEW
2066
            }),
×
NEW
2067
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
NEW
2068
                shape: frame.shape,
×
NEW
2069
                operation: "cannot select a field from a sequence type",
×
NEW
2070
            }),
×
2071
            Type::User(user_type) => match user_type {
162✔
2072
                UserType::Struct(struct_type) => Ok(struct_type.fields),
138✔
2073
                UserType::Enum(_) => {
2074
                    let Tracker::Enum { variant, .. } = &frame.tracker else {
23✔
2075
                        return Err(ReflectError::OperationFailed {
1✔
2076
                            shape: frame.shape,
1✔
2077
                            operation: "must select variant before selecting enum fields",
1✔
2078
                        });
1✔
2079
                    };
2080
                    Ok(variant.data.fields)
22✔
2081
                }
NEW
2082
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
2083
                    shape: frame.shape,
×
NEW
2084
                    operation: "cannot select a field from a union type",
×
NEW
2085
                }),
×
2086
                UserType::Opaque => Err(ReflectError::OperationFailed {
1✔
2087
                    shape: frame.shape,
1✔
2088
                    operation: "opaque types cannot be reflected upon",
1✔
2089
                }),
1✔
2090
            },
NEW
2091
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
NEW
2092
                shape: frame.shape,
×
NEW
2093
                operation: "cannot select a field from a pointer type",
×
NEW
2094
            }),
×
2095
        }
2096
    }
162✔
2097

2098
    /// Selects the nth field of a struct by index
2099
    fn begin_nth_struct_field(
174✔
2100
        frame: &mut Frame,
174✔
2101
        struct_type: StructType,
174✔
2102
        idx: usize,
174✔
2103
    ) -> Result<Frame, ReflectError> {
174✔
2104
        if idx >= struct_type.fields.len() {
174✔
NEW
2105
            return Err(ReflectError::OperationFailed {
×
NEW
2106
                shape: frame.shape,
×
NEW
2107
                operation: "field index out of bounds",
×
NEW
2108
            });
×
2109
        }
174✔
2110
        let field = &struct_type.fields[idx];
174✔
2111

2112
        if !matches!(frame.tracker, Tracker::Struct { .. }) {
174✔
2113
            frame.tracker = Tracker::Struct {
102✔
2114
                iset: ISet::new(struct_type.fields.len()),
102✔
2115
                current_child: None,
102✔
2116
            }
102✔
2117
        }
72✔
2118

2119
        let was_field_init = match &mut frame.tracker {
174✔
2120
            Tracker::Struct {
2121
                iset,
174✔
2122
                current_child,
174✔
2123
            } => {
2124
                *current_child = Some(idx);
174✔
2125
                iset.get(idx)
174✔
2126
            }
NEW
2127
            _ => unreachable!(),
×
2128
        };
2129

2130
        // Push a new frame for this field onto the frames stack.
2131
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
174✔
2132
        let field_shape = field.shape;
174✔
2133

2134
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
174✔
2135
        if was_field_init {
174✔
2136
            unsafe {
3✔
2137
                // the struct field tracker said so!
3✔
2138
                next_frame.mark_as_init();
3✔
2139
            }
3✔
2140
        }
171✔
2141

2142
        Ok(next_frame)
174✔
2143
    }
174✔
2144

2145
    /// Selects the nth element of an array by index
2146
    fn begin_nth_array_element(
38✔
2147
        frame: &mut Frame,
38✔
2148
        array_type: ArrayType,
38✔
2149
        idx: usize,
38✔
2150
    ) -> Result<Frame, ReflectError> {
38✔
2151
        if idx >= array_type.n {
38✔
2152
            return Err(ReflectError::OperationFailed {
1✔
2153
                shape: frame.shape,
1✔
2154
                operation: "array index out of bounds",
1✔
2155
            });
1✔
2156
        }
37✔
2157

2158
        if array_type.n > 63 {
37✔
NEW
2159
            return Err(ReflectError::OperationFailed {
×
NEW
2160
                shape: frame.shape,
×
NEW
2161
                operation: "arrays larger than 63 elements are not yet supported",
×
NEW
2162
            });
×
2163
        }
37✔
2164

2165
        // Ensure frame is in Array state
2166
        match &frame.tracker {
37✔
2167
            Tracker::Uninit => {
14✔
2168
                // this is fine
14✔
2169
                frame.tracker = Tracker::Array {
14✔
2170
                    iset: ISet::default(),
14✔
2171
                    current_child: None,
14✔
2172
                };
14✔
2173
            }
14✔
2174
            Tracker::Array { .. } => {
23✔
2175
                // fine too
23✔
2176
            }
23✔
NEW
2177
            _other => {
×
NEW
2178
                return Err(ReflectError::OperationFailed {
×
NEW
2179
                    shape: frame.shape,
×
NEW
2180
                    operation: "unexpected tracker state: expected Uninit or Array",
×
NEW
2181
                });
×
2182
            }
2183
        }
2184

2185
        match &mut frame.tracker {
37✔
2186
            Tracker::Array {
2187
                iset,
37✔
2188
                current_child,
37✔
2189
            } => {
2190
                *current_child = Some(idx);
37✔
2191
                let was_field_init = iset.get(idx);
37✔
2192

2193
                // Calculate the offset for this array element
2194
                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
37✔
NEW
2195
                    return Err(ReflectError::Unsized {
×
NEW
2196
                        shape: array_type.t,
×
NEW
2197
                        operation: "begin_nth_element, calculating array element offset",
×
NEW
2198
                    });
×
2199
                };
2200
                let offset = element_layout.size() * idx;
37✔
2201
                let element_data = unsafe { frame.data.field_uninit_at(offset) };
37✔
2202

2203
                let mut next_frame = Frame::new(element_data, array_type.t, FrameOwnership::Field);
37✔
2204
                if was_field_init {
37✔
2205
                    // safety: `iset` said it was initialized already
2206
                    unsafe {
1✔
2207
                        next_frame.mark_as_init();
1✔
2208
                    }
1✔
2209
                }
36✔
2210
                Ok(next_frame)
37✔
2211
            }
NEW
2212
            _ => unreachable!(),
×
2213
        }
2214
    }
38✔
2215

2216
    /// Selects the nth field of an enum variant by index
2217
    fn begin_nth_enum_field(
42✔
2218
        frame: &mut Frame,
42✔
2219
        variant: &'static Variant,
42✔
2220
        idx: usize,
42✔
2221
    ) -> Result<Frame, ReflectError> {
42✔
2222
        if idx >= variant.data.fields.len() {
42✔
NEW
2223
            return Err(ReflectError::OperationFailed {
×
NEW
2224
                shape: frame.shape,
×
NEW
2225
                operation: "enum field index out of bounds",
×
NEW
2226
            });
×
2227
        }
42✔
2228

2229
        let field = &variant.data.fields[idx];
42✔
2230

2231
        // Update tracker
2232
        let was_field_init = match &mut frame.tracker {
42✔
2233
            Tracker::Enum {
2234
                data,
42✔
2235
                current_child,
42✔
2236
                ..
2237
            } => {
2238
                *current_child = Some(idx);
42✔
2239
                data.get(idx)
42✔
2240
            }
2241
            _ => {
NEW
2242
                return Err(ReflectError::OperationFailed {
×
NEW
2243
                    shape: frame.shape,
×
NEW
2244
                    operation: "selecting a field on an enum requires selecting a variant first",
×
NEW
2245
                });
×
2246
            }
2247
        };
2248

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

2254
        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
42✔
2255
        if was_field_init {
42✔
2256
            // SAFETY: `ISet` told us the field was initialized
2257
            unsafe {
1✔
2258
                next_frame.mark_as_init();
1✔
2259
            }
1✔
2260
        }
41✔
2261

2262
        Ok(next_frame)
42✔
2263
    }
42✔
2264

2265
    /// Require that the partial is active
2266
    #[inline]
2267
    fn require_active(&self) -> Result<(), ReflectError> {
1,755✔
2268
        if self.state == PartialState::Active {
1,755✔
2269
            Ok(())
1,754✔
2270
        } else {
2271
            Err(ReflectError::InvariantViolation {
1✔
2272
                invariant: "Cannot use Partial after it has been built or poisoned",
1✔
2273
            })
1✔
2274
        }
2275
    }
1,755✔
2276
}
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