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

facet-rs / facet / 17649090059

11 Sep 2025 03:14PM UTC coverage: 54.555% (+0.2%) from 54.357%
17649090059

Pull #882

github

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

1072 of 1734 new or added lines in 3 files covered. (61.82%)

2 existing lines in 1 file now uncovered.

4791 of 8782 relevant lines covered (54.55%)

35.76 hits per line

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

59.13
/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
    Def, EnumRepr, Facet, KnownPointer, PtrConst, PtrMut, PtrUninit, SequenceType, Shape, Type,
12
    UserType, Variant,
13
};
14

15
impl<'facet> Partial<'facet> {
16
    /// Allocates a new Partial instance with the given shape
17
    pub fn alloc_shape(shape: &'static Shape) -> Result<Self, ReflectError> {
223✔
18
        crate::trace!(
19
            "alloc_shape({:?}), with layout {:?}",
20
            shape,
21
            shape.layout.sized_layout()
22
        );
23

24
        let data = shape.allocate().map_err(|_| ReflectError::Unsized {
223✔
NEW
25
            shape,
×
26
            operation: "alloc_shape",
NEW
27
        })?;
×
28

29
        // Preallocate a couple of frames. The cost of allocating 4 frames is
30
        // basically identical to allocating 1 frame, so for every type that
31
        // has at least 1 level of nesting, this saves at least one guaranteed reallocation.
32
        let mut frames = Vec::with_capacity(4);
223✔
33
        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
223✔
34

35
        Ok(Self {
223✔
36
            frames,
223✔
37
            state: PartialState::Active,
223✔
38
            invariant: PhantomData,
223✔
39
        })
223✔
40
    }
223✔
41

42
    /// Allocates a new TypedPartial instance with the given shape and type
43
    pub fn alloc<T>() -> Result<TypedPartial<'facet, T>, ReflectError>
208✔
44
    where
208✔
45
        T: Facet<'facet>,
208✔
46
    {
47
        Ok(TypedPartial {
48
            inner: Self::alloc_shape(T::SHAPE)?,
208✔
49
            phantom: PhantomData,
208✔
50
        })
51
    }
208✔
52

53
    /// Require that the partial is active
54
    #[inline]
55
    fn require_active(&self) -> Result<(), ReflectError> {
1,782✔
56
        if self.state == PartialState::Active {
1,782✔
57
            Ok(())
1,781✔
58
        } else {
59
            Err(ReflectError::InvariantViolation {
1✔
60
                invariant: "Cannot use Partial after it has been built or poisoned",
1✔
61
            })
1✔
62
        }
63
    }
1,782✔
64
}
65

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

81
    /// Sets a value wholesale into the current frame
82
    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
312✔
83
    where
312✔
84
        U: Facet<'facet>,
312✔
85
    {
86
        self.require_active()?;
312✔
87

88
        let ptr_const = PtrConst::new(&raw const value);
312✔
89
        unsafe {
90
            // Safety: We are calling set_shape with a valid shape and a valid pointer
91
            self.set_shape(ptr_const, U::SHAPE)?
312✔
92
        };
93

94
        // Prevent the value from being dropped since we've copied it
95
        core::mem::forget(value);
312✔
96
        Ok(self)
312✔
97
    }
312✔
98

99
    /// Sets a value into the current frame by shape, for shape-based operations
100
    ///
101
    /// If this returns Ok, then `src_value` has been moved out of
102
    ///
103
    /// # Safety
104
    ///
105
    /// The caller must ensure that `src_value` points to a valid instance of a value
106
    /// whose memory layout and type matches `src_shape`, and that this value can be
107
    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
108
    /// No automatic drop will be performed for any existing value, so calling this on an
109
    /// already-initialized destination may result in leaks or double drops if misused.
110
    /// After a successful call, the ownership of the value at `src_value` is effectively moved
111
    /// into the Partial (i.e., the destination), and the original value should not be used
112
    /// or dropped by the caller; consider using `core::mem::forget` on the passed value.
113
    /// If an error is returned, the destination remains unmodified and safe for future operations.
114
    #[inline]
115
    pub unsafe fn set_shape(
312✔
116
        &mut self,
312✔
117
        src_value: PtrConst<'_>,
312✔
118
        src_shape: &'static Shape,
312✔
119
    ) -> Result<&mut Self, ReflectError> {
312✔
120
        self.require_active()?;
312✔
121

122
        let fr = self.frames.last_mut().unwrap();
312✔
123
        crate::trace!("set_shape({src_shape:?})");
124

125
        if !fr.shape.is_shape(src_shape) {
312✔
NEW
126
            return Err(ReflectError::WrongShape {
×
NEW
127
                expected: fr.shape,
×
NEW
128
                actual: src_shape,
×
NEW
129
            });
×
130
        }
312✔
131

132
        if fr.shape.layout.sized_layout().is_err() {
312✔
NEW
133
            return Err(ReflectError::Unsized {
×
NEW
134
                shape: fr.shape,
×
NEW
135
                operation: "set_shape",
×
NEW
136
            });
×
137
        }
312✔
138

139
        fr.deinit();
312✔
140
        unsafe {
312✔
141
            fr.data.copy_from(src_value, fr.shape).unwrap();
312✔
142
        }
312✔
143
        fr.tracker = Tracker::Init;
312✔
144

145
        Ok(self)
312✔
146
    }
312✔
147

148
    /// Sets the current frame to its default value
149
    #[inline]
150
    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
5✔
151
        let frame = self.frames.last().unwrap(); // Get frame to access vtable
5✔
152

153
        if let Some(default_fn) = frame
5✔
154
            .shape
5✔
155
            .vtable
5✔
156
            .sized()
5✔
157
            .and_then(|v| (v.default_in_place)())
5✔
158
        {
159
            // Initialize with default value using set_from_function
160
            //
161
            // # Safety
162
            //
163
            // set_from_function handles the active check, dropping,
164
            // and setting tracker. The closure passes the correct pointer type
165
            // and casts to 'static which is safe within the context of calling
166
            // the vtable function. The closure returns Ok(()) because the
167
            // default_in_place function does not return errors.
168
            unsafe {
169
                self.set_from_function(move |ptr: PtrUninit<'_>| {
4✔
170
                    default_fn(PtrUninit::new(ptr.as_mut_byte_ptr()));
4✔
171
                    Ok(())
4✔
172
                })
4✔
173
            }
174
        } else {
175
            Err(ReflectError::OperationFailed {
1✔
176
                shape: frame.shape,
1✔
177
                operation: "type does not implement Default",
1✔
178
            })
1✔
179
        }
180
    }
5✔
181

182
    /// Sets the current frame using a function that initializes the value
183
    ///
184
    /// # Safety
185
    ///
186
    /// `f` must initialize the passed pointer fully and with a value of the right type
187
    pub unsafe fn set_from_function<F>(&mut self, f: F) -> Result<&mut Self, ReflectError>
4✔
188
    where
4✔
189
        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
4✔
190
    {
191
        self.require_active()?;
4✔
192

193
        let frame = self.frames.last_mut().unwrap();
4✔
194

195
        // Check if we need to drop an existing value
196
        // FIXME: there are other ways for values to be initialized /
197
        // partially initialized, so this is actually a minefield
198
        if matches!(frame.tracker, Tracker::Init) {
4✔
199
            if let Some(drop_fn) = frame.shape.vtable.sized().and_then(|v| (v.drop_in_place)()) {
1✔
200
                unsafe { drop_fn(PtrMut::new(frame.data.as_mut_byte_ptr())) };
1✔
201
            }
1✔
202
        }
3✔
203

204
        // Don't allow overwriting when building an Option's inner value
NEW
205
        if matches!(
×
206
            frame.tracker,
4✔
207
            Tracker::Option {
208
                building_inner: true
209
            }
210
        ) {
NEW
211
            return Err(ReflectError::OperationFailed {
×
NEW
212
                shape: frame.shape,
×
NEW
213
                operation: "Cannot overwrite while building Option inner value",
×
NEW
214
            });
×
215
        }
4✔
216

217
        // Call the function to initialize the value
218
        match f(frame.data) {
4✔
219
            Ok(()) => {
220
                // FIXME: what about finding out the discriminant of enums?
221
                frame.tracker = Tracker::Init;
4✔
222
                Ok(self)
4✔
223
            }
NEW
224
            Err(e) => Err(e),
×
225
        }
226
    }
4✔
227

228
    /// Parses a string value into the current frame using the type's ParseFn from the vtable
229
    pub fn parse_from_str(&mut self, s: &str) -> Result<&mut Self, ReflectError> {
2✔
230
        self.require_active()?;
2✔
231

232
        let frame = self.frames.last_mut().unwrap();
2✔
233

234
        // Check if the type has a parse function
235
        let parse_fn = match frame.shape.vtable.sized().and_then(|v| (v.parse)()) {
2✔
236
            Some(parse_fn) => parse_fn,
2✔
237
            None => {
NEW
238
                return Err(ReflectError::OperationFailed {
×
NEW
239
                    shape: frame.shape,
×
NEW
240
                    operation: "Type does not support parsing from string",
×
NEW
241
                });
×
242
            }
243
        };
244

245
        // Check if we need to drop an existing value
246
        if matches!(frame.tracker, Tracker::Init) {
2✔
NEW
247
            if let Some(drop_fn) = frame.shape.vtable.sized().and_then(|v| (v.drop_in_place)()) {
×
NEW
248
                unsafe { drop_fn(PtrMut::new(frame.data.as_mut_byte_ptr())) };
×
NEW
249
            }
×
250
        }
2✔
251

252
        // Don't allow overwriting when building an Option's inner value
NEW
253
        if matches!(
×
254
            frame.tracker,
2✔
255
            Tracker::Option {
256
                building_inner: true
257
            }
258
        ) {
NEW
259
            return Err(ReflectError::OperationFailed {
×
NEW
260
                shape: frame.shape,
×
NEW
261
                operation: "Cannot overwrite while building Option inner value",
×
NEW
262
            });
×
263
        }
2✔
264

265
        // Parse the string value using the type's parse function
266
        let result = unsafe { parse_fn(s, frame.data) };
2✔
267
        match result {
2✔
268
            Ok(_) => {
269
                frame.tracker = Tracker::Init;
1✔
270
                Ok(self)
1✔
271
            }
272
            Err(_parse_error) => Err(ReflectError::OperationFailed {
1✔
273
                shape: frame.shape,
1✔
274
                operation: "Failed to parse string value",
1✔
275
            }),
1✔
276
        }
277
    }
2✔
278

279
    /// Pushes a variant for enum initialization by name
280
    pub fn select_variant_named(&mut self, variant_name: &str) -> Result<&mut Self, ReflectError> {
30✔
281
        self.require_active()?;
30✔
282

283
        let fr = self.frames.last_mut().unwrap();
30✔
284

285
        // Check that we're dealing with an enum
286
        let enum_type = match fr.shape.ty {
30✔
287
            Type::User(UserType::Enum(e)) => e,
30✔
288
            _ => {
NEW
289
                return Err(ReflectError::OperationFailed {
×
NEW
290
                    shape: fr.shape,
×
NEW
291
                    operation: "push_variant_named requires an enum type",
×
NEW
292
                });
×
293
            }
294
        };
295

296
        // Find the variant with the matching name
297
        let variant = match enum_type.variants.iter().find(|v| v.name == variant_name) {
69✔
298
            Some(v) => v,
28✔
299
            None => {
300
                return Err(ReflectError::OperationFailed {
2✔
301
                    shape: fr.shape,
2✔
302
                    operation: "No variant found with the given name",
2✔
303
                });
2✔
304
            }
305
        };
306

307
        // Get the discriminant value
308
        let discriminant = match variant.discriminant {
28✔
309
            Some(d) => d,
28✔
310
            None => {
NEW
311
                return Err(ReflectError::OperationFailed {
×
NEW
312
                    shape: fr.shape,
×
NEW
313
                    operation: "Variant has no discriminant value",
×
NEW
314
                });
×
315
            }
316
        };
317

318
        // Delegate to push_variant
319
        self.select_variant(discriminant)
28✔
320
    }
30✔
321

322
    /// Pushes a variant for enum initialization
323
    pub fn select_variant(&mut self, discriminant: i64) -> Result<&mut Self, ReflectError> {
38✔
324
        self.require_active()?;
38✔
325

326
        // Check all invariants early before making any changes
327
        let fr = self.frames.last().unwrap();
38✔
328

329
        // Check that we're dealing with an enum
330
        let enum_type = match fr.shape.ty {
38✔
331
            Type::User(UserType::Enum(e)) => e,
38✔
332
            _ => {
NEW
333
                return Err(ReflectError::WasNotA {
×
NEW
334
                    expected: "enum",
×
NEW
335
                    actual: fr.shape,
×
NEW
336
                });
×
337
            }
338
        };
339

340
        // Find the variant with the matching discriminant
341
        let variant = match enum_type
38✔
342
            .variants
38✔
343
            .iter()
38✔
344
            .find(|v| v.discriminant == Some(discriminant))
79✔
345
        {
346
            Some(v) => v,
38✔
347
            None => {
NEW
348
                return Err(ReflectError::OperationFailed {
×
NEW
349
                    shape: fr.shape,
×
NEW
350
                    operation: "No variant found with the given discriminant",
×
NEW
351
                });
×
352
            }
353
        };
354

355
        // Check enum representation early
356
        match enum_type.enum_repr {
38✔
357
            EnumRepr::RustNPO => {
NEW
358
                return Err(ReflectError::OperationFailed {
×
NEW
359
                    shape: fr.shape,
×
NEW
360
                    operation: "RustNPO enums are not supported for incremental building",
×
NEW
361
                });
×
362
            }
363
            EnumRepr::U8
364
            | EnumRepr::U16
365
            | EnumRepr::U32
366
            | EnumRepr::U64
367
            | EnumRepr::I8
368
            | EnumRepr::I16
369
            | EnumRepr::I32
370
            | EnumRepr::I64
371
            | EnumRepr::USize
372
            | EnumRepr::ISize => {
38✔
373
                // These are supported, continue
38✔
374
            }
38✔
375
        }
376

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

380
        // Write the discriminant to memory
381
        unsafe {
382
            match enum_type.enum_repr {
38✔
383
                EnumRepr::U8 => {
24✔
384
                    let ptr = fr.data.as_mut_byte_ptr();
24✔
385
                    *ptr = discriminant as u8;
24✔
386
                }
24✔
387
                EnumRepr::U16 => {
1✔
388
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
1✔
389
                    *ptr = discriminant as u16;
1✔
390
                }
1✔
391
                EnumRepr::U32 => {
8✔
392
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
8✔
393
                    *ptr = discriminant as u32;
8✔
394
                }
8✔
NEW
395
                EnumRepr::U64 => {
×
NEW
396
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
NEW
397
                    *ptr = discriminant as u64;
×
NEW
398
                }
×
NEW
399
                EnumRepr::I8 => {
×
NEW
400
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
NEW
401
                    *ptr = discriminant as i8;
×
NEW
402
                }
×
403
                EnumRepr::I16 => {
4✔
404
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
405
                    *ptr = discriminant as i16;
4✔
406
                }
4✔
407
                EnumRepr::I32 => {
1✔
408
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
409
                    *ptr = discriminant as i32;
1✔
410
                }
1✔
NEW
411
                EnumRepr::I64 => {
×
NEW
412
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
NEW
413
                    *ptr = discriminant;
×
NEW
414
                }
×
NEW
415
                EnumRepr::USize => {
×
NEW
416
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
NEW
417
                    *ptr = discriminant as usize;
×
NEW
418
                }
×
NEW
419
                EnumRepr::ISize => {
×
NEW
420
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
NEW
421
                    *ptr = discriminant as isize;
×
NEW
422
                }
×
NEW
423
                _ => unreachable!("Already checked enum representation above"),
×
424
            }
425
        }
426

427
        // Update tracker to track the variant
428
        fr.tracker = Tracker::Enum {
38✔
429
            variant,
38✔
430
            data: ISet::new(variant.data.fields.len()),
38✔
431
            current_child: None,
38✔
432
        };
38✔
433

434
        Ok(self)
38✔
435
    }
38✔
436

437
    /// Selects a variant for enum initialization, by variant index in the enum's variant list (0-based)
438
    pub fn select_nth_variant(&mut self, index: usize) -> Result<&mut Self, ReflectError> {
2✔
439
        self.require_active()?;
2✔
440

441
        let fr = self.frames.last().unwrap();
2✔
442

443
        // Check that we're dealing with an enum
444
        let enum_type = match fr.shape.ty {
2✔
445
            Type::User(UserType::Enum(e)) => e,
2✔
446
            _ => {
NEW
447
                return Err(ReflectError::OperationFailed {
×
NEW
448
                    shape: fr.shape,
×
NEW
449
                    operation: "select_nth_variant requires an enum type",
×
NEW
450
                });
×
451
            }
452
        };
453

454
        if index >= enum_type.variants.len() {
2✔
NEW
455
            return Err(ReflectError::OperationFailed {
×
NEW
456
                shape: fr.shape,
×
NEW
457
                operation: "variant index out of bounds",
×
NEW
458
            });
×
459
        }
2✔
460
        let variant = &enum_type.variants[index];
2✔
461

462
        // Get the discriminant value
463
        let discriminant = match variant.discriminant {
2✔
464
            Some(d) => d,
2✔
465
            None => {
NEW
466
                return Err(ReflectError::OperationFailed {
×
NEW
467
                    shape: fr.shape,
×
NEW
468
                    operation: "Variant has no discriminant value",
×
NEW
469
                });
×
470
            }
471
        };
472

473
        // Delegate to select_variant
474
        self.select_variant(discriminant)
2✔
475
    }
2✔
476

477
    /// Selects a field of a struct with a given name
478
    pub fn begin_field(&mut self, field_name: &str) -> Result<&mut Self, ReflectError> {
162✔
479
        self.require_active()?;
162✔
480

481
        let frame = self.frames.last_mut().unwrap();
162✔
482
        match frame.shape.ty {
162✔
NEW
483
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
×
NEW
484
                shape: frame.shape,
×
NEW
485
                operation: "cannot select a field from a primitive type",
×
NEW
486
            }),
×
NEW
487
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
NEW
488
                shape: frame.shape,
×
NEW
489
                operation: "cannot select a field from a sequence type",
×
NEW
490
            }),
×
491
            Type::User(user_type) => match user_type {
162✔
492
                UserType::Struct(struct_type) => {
138✔
493
                    let idx = struct_type.fields.iter().position(|f| f.name == field_name);
206✔
494
                    let idx = match idx {
138✔
495
                        Some(idx) => idx,
137✔
496
                        None => {
497
                            return Err(ReflectError::OperationFailed {
1✔
498
                                shape: frame.shape,
1✔
499
                                operation: "field not found",
1✔
500
                            });
1✔
501
                        }
502
                    };
503
                    self.begin_nth_field(idx)
137✔
504
                }
505
                UserType::Enum(_) => {
506
                    // Check if we have a variant selected
507
                    match &frame.tracker {
23✔
508
                        Tracker::Enum { variant, .. } => {
22✔
509
                            let idx = variant
22✔
510
                                .data
22✔
511
                                .fields
22✔
512
                                .iter()
22✔
513
                                .position(|f| f.name == field_name);
33✔
514
                            let idx = match idx {
22✔
515
                                Some(idx) => idx,
20✔
516
                                None => {
517
                                    return Err(ReflectError::OperationFailed {
2✔
518
                                        shape: frame.shape,
2✔
519
                                        operation: "field not found in current enum variant",
2✔
520
                                    });
2✔
521
                                }
522
                            };
523
                            self.begin_nth_enum_field(idx)
20✔
524
                        }
525
                        _ => Err(ReflectError::OperationFailed {
1✔
526
                            shape: frame.shape,
1✔
527
                            operation: "must call push_variant before selecting enum fields",
1✔
528
                        }),
1✔
529
                    }
530
                }
NEW
531
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
532
                    shape: frame.shape,
×
NEW
533
                    operation: "unions are not supported",
×
NEW
534
                }),
×
535
                UserType::Opaque => Err(ReflectError::OperationFailed {
1✔
536
                    shape: frame.shape,
1✔
537
                    operation: "opaque types cannot be reflected upon",
1✔
538
                }),
1✔
539
            },
NEW
540
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
NEW
541
                shape: frame.shape,
×
NEW
542
                operation: "cannot select a field from a pointer type",
×
NEW
543
            }),
×
544
        }
545
    }
162✔
546

547
    /// Selects the nth field of a struct by index
548
    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
174✔
549
        self.require_active()?;
174✔
550
        let frame = self.frames.last_mut().unwrap();
174✔
551
        match frame.shape.ty {
174✔
552
            Type::User(user_type) => match user_type {
174✔
553
                UserType::Struct(struct_type) => {
174✔
554
                    if idx >= struct_type.fields.len() {
174✔
NEW
555
                        return Err(ReflectError::OperationFailed {
×
NEW
556
                            shape: frame.shape,
×
NEW
557
                            operation: "field index out of bounds",
×
NEW
558
                        });
×
559
                    }
174✔
560
                    let field = &struct_type.fields[idx];
174✔
561
                    let mut is_field_init = false;
174✔
562

563
                    match &mut frame.tracker {
174✔
564
                        Tracker::Uninit => {
565
                            frame.tracker = Tracker::Struct {
102✔
566
                                iset: ISet::new(struct_type.fields.len()),
102✔
567
                                current_child: Some(idx),
102✔
568
                            }
102✔
569
                        }
570
                        Tracker::Struct {
571
                            iset,
72✔
572
                            current_child,
72✔
573
                        } => {
574
                            // Check if this field was already initialized
575
                            if iset.get(idx) {
72✔
576
                                is_field_init = true;
3✔
577
                            }
69✔
578
                            *current_child = Some(idx);
72✔
579
                        }
NEW
580
                        _ => unreachable!(),
×
581
                    }
582

583
                    // Push a new frame for this field onto the frames stack.
584
                    let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
174✔
585
                    let field_shape = field.shape;
174✔
586
                    let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
174✔
587
                    if is_field_init {
174✔
588
                        next_frame.tracker = Tracker::Init;
3✔
589
                    }
171✔
590
                    self.frames.push(next_frame);
174✔
591

592
                    Ok(self)
174✔
593
                }
594
                UserType::Enum(_) => {
595
                    // Check if we have a variant selected
NEW
596
                    match &frame.tracker {
×
NEW
597
                        Tracker::Enum { variant, .. } => {
×
NEW
598
                            if idx >= variant.data.fields.len() {
×
NEW
599
                                return Err(ReflectError::OperationFailed {
×
NEW
600
                                    shape: frame.shape,
×
NEW
601
                                    operation: "enum field index out of bounds",
×
NEW
602
                                });
×
NEW
603
                            }
×
NEW
604
                            self.begin_nth_enum_field(idx)
×
605
                        }
NEW
606
                        _ => Err(ReflectError::OperationFailed {
×
NEW
607
                            shape: frame.shape,
×
NEW
608
                            operation: "must call select_variant before selecting enum fields",
×
NEW
609
                        }),
×
610
                    }
611
                }
NEW
612
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
613
                    shape: frame.shape,
×
NEW
614
                    operation: "unions are not supported",
×
NEW
615
                }),
×
NEW
616
                UserType::Opaque => Err(ReflectError::OperationFailed {
×
NEW
617
                    shape: frame.shape,
×
NEW
618
                    operation: "opaque types cannot be reflected upon",
×
NEW
619
                }),
×
620
            },
NEW
621
            _ => Err(ReflectError::OperationFailed {
×
NEW
622
                shape: frame.shape,
×
NEW
623
                operation: "cannot select a field from this type",
×
NEW
624
            }),
×
625
        }
626
    }
174✔
627

628
    /// Selects the nth element of an array by index
629
    pub fn begin_nth_element(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
38✔
630
        self.require_active()?;
38✔
631
        let frame = self.frames.last_mut().unwrap();
38✔
632
        match frame.shape.ty {
38✔
633
            Type::Sequence(seq_type) => match seq_type {
38✔
634
                facet_core::SequenceType::Array(array_def) => {
38✔
635
                    if idx >= array_def.n {
38✔
636
                        return Err(ReflectError::OperationFailed {
1✔
637
                            shape: frame.shape,
1✔
638
                            operation: "array index out of bounds",
1✔
639
                        });
1✔
640
                    }
37✔
641

642
                    if array_def.n > 63 {
37✔
NEW
643
                        return Err(ReflectError::OperationFailed {
×
NEW
644
                            shape: frame.shape,
×
NEW
645
                            operation: "arrays larger than 63 elements are not yet supported",
×
NEW
646
                        });
×
647
                    }
37✔
648

649
                    // Ensure frame is in Array state
650
                    if matches!(frame.tracker, Tracker::Uninit) {
37✔
651
                        frame.tracker = Tracker::Array {
14✔
652
                            iset: ISet::default(),
14✔
653
                            current_child: None,
14✔
654
                        };
14✔
655
                    }
23✔
656

657
                    match &mut frame.tracker {
37✔
658
                        Tracker::Array {
659
                            iset,
37✔
660
                            current_child,
37✔
661
                        } => {
662
                            // Calculate the offset for this array element
663
                            let element_layout = match array_def.t.layout.sized_layout() {
37✔
664
                                Ok(layout) => layout,
37✔
665
                                Err(_) => {
NEW
666
                                    return Err(ReflectError::Unsized {
×
NEW
667
                                        shape: array_def.t,
×
NEW
668
                                        operation: "begin_nth_element, calculating array element offset",
×
NEW
669
                                    });
×
670
                                }
671
                            };
672
                            let offset = element_layout.size() * idx;
37✔
673

674
                            // Check if this element was already initialized
675
                            if iset.get(idx) {
37✔
676
                                // Drop the existing value before re-initializing
677
                                let element_ptr = unsafe { frame.data.field_init_at(offset) };
1✔
678
                                if let Some(drop_fn) =
1✔
679
                                    array_def.t.vtable.sized().and_then(|v| (v.drop_in_place)())
1✔
680
                                {
1✔
681
                                    unsafe { drop_fn(element_ptr) };
1✔
682
                                }
1✔
683
                                // Unset the bit so we can re-initialize
684
                                iset.unset(idx);
1✔
685
                            }
36✔
686

687
                            *current_child = Some(idx);
37✔
688

689
                            // Create a new frame for the array element
690
                            let element_data = unsafe { frame.data.field_uninit_at(offset) };
37✔
691
                            self.frames.push(Frame::new(
37✔
692
                                element_data,
37✔
693
                                array_def.t,
37✔
694
                                FrameOwnership::Field,
37✔
695
                            ));
696

697
                            Ok(self)
37✔
698
                        }
NEW
699
                        _ => Err(ReflectError::OperationFailed {
×
NEW
700
                            shape: frame.shape,
×
NEW
701
                            operation: "expected array tracker state",
×
NEW
702
                        }),
×
703
                    }
704
                }
NEW
705
                _ => Err(ReflectError::OperationFailed {
×
NEW
706
                    shape: frame.shape,
×
NEW
707
                    operation: "can only select elements from arrays",
×
NEW
708
                }),
×
709
            },
NEW
710
            _ => Err(ReflectError::OperationFailed {
×
NEW
711
                shape: frame.shape,
×
NEW
712
                operation: "cannot select an element from this type",
×
NEW
713
            }),
×
714
        }
715
    }
38✔
716

717
    /// Selects the nth field of an enum variant by index
718
    pub fn begin_nth_enum_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
42✔
719
        self.require_active()?;
42✔
720
        let frame = self.frames.last_mut().unwrap();
42✔
721

722
        // Ensure we're in an enum with a variant selected
723
        let (variant, enum_type) = match (&frame.tracker, &frame.shape.ty) {
42✔
724
            (Tracker::Enum { variant, .. }, Type::User(UserType::Enum(e))) => (variant, e),
42✔
725
            _ => {
NEW
726
                return Err(ReflectError::OperationFailed {
×
NEW
727
                    shape: frame.shape,
×
NEW
728
                    operation: "push_nth_enum_field requires an enum with a variant selected",
×
NEW
729
                });
×
730
            }
731
        };
732

733
        // Check bounds
734
        if idx >= variant.data.fields.len() {
42✔
NEW
735
            return Err(ReflectError::OperationFailed {
×
NEW
736
                shape: frame.shape,
×
NEW
737
                operation: "enum field index out of bounds",
×
NEW
738
            });
×
739
        }
42✔
740

741
        let field = &variant.data.fields[idx];
42✔
742

743
        // Update tracker
744
        match &mut frame.tracker {
42✔
745
            Tracker::Enum {
746
                data,
42✔
747
                current_child,
42✔
748
                ..
749
            } => {
750
                // Check if field was already initialized and drop if needed
751
                if data.get(idx) {
42✔
752
                    // Calculate the field offset, taking into account the discriminant
753
                    let _discriminant_size = match enum_type.enum_repr {
1✔
NEW
754
                        EnumRepr::U8 | EnumRepr::I8 => 1,
×
755
                        EnumRepr::U16 | EnumRepr::I16 => 2,
1✔
NEW
756
                        EnumRepr::U32 | EnumRepr::I32 => 4,
×
NEW
757
                        EnumRepr::U64 | EnumRepr::I64 => 8,
×
NEW
758
                        EnumRepr::USize | EnumRepr::ISize => core::mem::size_of::<usize>(),
×
759
                        EnumRepr::RustNPO => {
NEW
760
                            return Err(ReflectError::OperationFailed {
×
NEW
761
                                shape: frame.shape,
×
NEW
762
                                operation: "RustNPO enums are not supported",
×
NEW
763
                            });
×
764
                        }
765
                    };
766

767
                    // The field offset already includes the discriminant offset
768
                    let field_ptr = unsafe { frame.data.as_mut_byte_ptr().add(field.offset) };
1✔
769

NEW
770
                    if let Some(drop_fn) =
×
771
                        field.shape.vtable.sized().and_then(|v| (v.drop_in_place)())
1✔
NEW
772
                    {
×
NEW
773
                        unsafe { drop_fn(PtrMut::new(field_ptr)) };
×
774
                    }
1✔
775

776
                    // Unset the bit so we can re-initialize
777
                    data.unset(idx);
1✔
778
                }
41✔
779

780
                // Set current_child to track which field we're initializing
781
                *current_child = Some(idx);
42✔
782
            }
NEW
783
            _ => unreachable!("Already checked that we have Enum tracker"),
×
784
        }
785

786
        // Extract data we need before pushing frame
787
        let field_ptr = unsafe { frame.data.as_mut_byte_ptr().add(field.offset) };
42✔
788
        let field_shape = field.shape;
42✔
789

790
        // Push new frame for the field
791
        self.frames.push(Frame::new(
42✔
792
            PtrUninit::new(field_ptr),
42✔
793
            field_shape,
42✔
794
            FrameOwnership::Field,
42✔
795
        ));
796

797
        Ok(self)
42✔
798
    }
42✔
799

800
    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
801
    pub fn begin_smart_ptr(&mut self) -> Result<&mut Self, ReflectError> {
21✔
802
        crate::trace!("begin_smart_ptr()");
803
        self.require_active()?;
21✔
804
        let frame = self.frames.last_mut().unwrap();
21✔
805

806
        // Check that we have a SmartPointer
807
        match &frame.shape.def {
21✔
808
            Def::Pointer(smart_ptr_def) => {
21✔
809
                // Check for supported smart pointer types
810
                match smart_ptr_def.known {
21✔
811
                    Some(KnownPointer::Box)
812
                    | Some(KnownPointer::Rc)
813
                    | Some(KnownPointer::Arc)
814
                    | Some(KnownPointer::SharedReference) => {
21✔
815
                        // Supported types, continue
21✔
816
                    }
21✔
817
                    _ => {
NEW
818
                        return Err(ReflectError::OperationFailed {
×
NEW
819
                            shape: frame.shape,
×
NEW
820
                            operation: "only the following pointers are currently supported: Box<T>, Rc<T>, Arc<T>, and &T",
×
NEW
821
                        });
×
822
                    }
823
                }
824

825
                // Get the pointee shape
826
                let pointee_shape = match smart_ptr_def.pointee() {
21✔
827
                    Some(shape) => shape,
21✔
828
                    None => {
NEW
829
                        return Err(ReflectError::OperationFailed {
×
NEW
830
                            shape: frame.shape,
×
NEW
831
                            operation: "Box must have a pointee shape",
×
NEW
832
                        });
×
833
                    }
834
                };
835

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

840
                    if matches!(frame.tracker, Tracker::Uninit) {
7✔
841
                        frame.tracker = Tracker::SmartPointer {
7✔
842
                            is_initialized: false,
7✔
843
                        };
7✔
844
                    }
7✔
845

846
                    let inner_layout = match pointee_shape.layout.sized_layout() {
7✔
847
                        Ok(layout) => layout,
7✔
848
                        Err(_) => {
NEW
849
                            return Err(ReflectError::Unsized {
×
NEW
850
                                shape: pointee_shape,
×
NEW
851
                                operation: "begin_smart_ptr, calculating inner value layout",
×
NEW
852
                            });
×
853
                        }
854
                    };
855
                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
7✔
856
                    if inner_ptr.is_null() {
7✔
NEW
857
                        return Err(ReflectError::OperationFailed {
×
NEW
858
                            shape: frame.shape,
×
NEW
859
                            operation: "failed to allocate memory for smart pointer inner value",
×
NEW
860
                        });
×
861
                    }
7✔
862

863
                    // Push a new frame for the inner value
864
                    self.frames.push(Frame::new(
7✔
865
                        PtrUninit::new(inner_ptr),
7✔
866
                        pointee_shape,
7✔
867
                        FrameOwnership::Owned,
7✔
868
                    ));
869
                } else {
870
                    // pointee is unsized, we only support a handful of cases there
871
                    if pointee_shape == str::SHAPE {
14✔
872
                        crate::trace!("Pointee is str");
873

874
                        // Allocate space for a String
875
                        let string_layout = String::SHAPE
8✔
876
                            .layout
8✔
877
                            .sized_layout()
8✔
878
                            .expect("String must have a sized layout");
8✔
879
                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
8✔
880
                        if string_ptr.is_null() {
8✔
NEW
881
                            alloc::alloc::handle_alloc_error(string_layout);
×
882
                        }
8✔
883
                        let mut frame = Frame::new(
8✔
884
                            PtrUninit::new(string_ptr),
8✔
885
                            String::SHAPE,
886
                            FrameOwnership::Owned,
8✔
887
                        );
888
                        frame.tracker = Tracker::Uninit;
8✔
889
                        self.frames.push(frame);
8✔
890
                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
6✔
891
                        crate::trace!("Pointee is [{}]", _st.t);
892

893
                        // Get the slice builder vtable
894
                        let slice_builder_vtable = smart_ptr_def
6✔
895
                            .vtable
6✔
896
                            .slice_builder_vtable
6✔
897
                            .ok_or(ReflectError::OperationFailed {
6✔
898
                                shape: frame.shape,
6✔
899
                                operation: "smart pointer does not support slice building",
6✔
900
                            })?;
6✔
901

902
                        // Create a new builder
903
                        let builder_ptr = (slice_builder_vtable.new_fn)();
6✔
904

905
                        // Deallocate the original Arc allocation before replacing with slice builder
906
                        if let FrameOwnership::Owned = frame.ownership {
6✔
907
                            if let Ok(layout) = frame.shape.layout.sized_layout() {
6✔
908
                                if layout.size() > 0 {
6✔
909
                                    unsafe {
6✔
910
                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
6✔
911
                                    };
6✔
912
                                }
6✔
NEW
913
                            }
×
NEW
914
                        }
×
915

916
                        // Update the current frame to use the slice builder
917
                        frame.data = PtrUninit::new(builder_ptr.as_mut_byte_ptr());
6✔
918
                        frame.tracker = Tracker::SmartPointerSlice {
6✔
919
                            vtable: slice_builder_vtable,
6✔
920
                            building_item: false,
6✔
921
                        };
6✔
922
                        // The slice builder memory is managed by the vtable, not by us
923
                        frame.ownership = FrameOwnership::ManagedElsewhere;
6✔
924
                    } else {
NEW
925
                        todo!("unsupported unsize pointee shape: {}", pointee_shape)
×
926
                    }
927
                }
928

929
                Ok(self)
21✔
930
            }
NEW
931
            _ => Err(ReflectError::OperationFailed {
×
NEW
932
                shape: frame.shape,
×
NEW
933
                operation: "push_smart_ptr can only be called on compatible types",
×
NEW
934
            }),
×
935
        }
936
    }
21✔
937

938
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
939
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
940
    /// `push`.
941
    ///
942
    /// `begin_list` does not clear the list if it was previously initialized.
943
    /// `begin_list` does not push a new frame to the stack, and thus does not
944
    /// require `end` to be called afterwards.
945
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
36✔
946
        crate::trace!("begin_list()");
947
        self.require_active()?;
36✔
948
        let frame = self.frames.last_mut().unwrap();
36✔
949

950
        match &frame.tracker {
36✔
951
            Tracker::Uninit => {
28✔
952
                // that's good, let's initialize it
28✔
953
            }
28✔
954
            Tracker::Init => {
955
                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
956
                frame.tracker = Tracker::List {
1✔
957
                    is_initialized: true,
1✔
958
                    current_child: false,
1✔
959
                };
1✔
960
                return Ok(self);
1✔
961
            }
962
            Tracker::List { is_initialized, .. } => {
1✔
963
                if *is_initialized {
1✔
964
                    // already initialized, nothing to do
965
                    return Ok(self);
1✔
NEW
966
                }
×
967
            }
968
            Tracker::SmartPointerSlice { .. } => {
969
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
970
                return Ok(self);
6✔
971
            }
972
            _ => {
NEW
973
                return Err(ReflectError::UnexpectedTracker {
×
NEW
974
                    message: "begin_list called but tracker isn't something list-like",
×
NEW
975
                    current_tracker: frame.tracker.kind(),
×
NEW
976
                });
×
977
            }
978
        };
979

980
        // Check that we have a List
981
        let list_def = match &frame.shape.def {
28✔
982
            Def::List(list_def) => list_def,
25✔
983
            _ => {
984
                return Err(ReflectError::OperationFailed {
3✔
985
                    shape: frame.shape,
3✔
986
                    operation: "begin_list can only be called on List types",
3✔
987
                });
3✔
988
            }
989
        };
990

991
        // Check that we have init_in_place_with_capacity function
992
        let init_fn = match list_def.vtable.init_in_place_with_capacity {
25✔
993
            Some(f) => f,
25✔
994
            None => {
NEW
995
                return Err(ReflectError::OperationFailed {
×
NEW
996
                    shape: frame.shape,
×
NEW
997
                    operation: "list type does not support initialization with capacity",
×
NEW
998
                });
×
999
            }
1000
        };
1001

1002
        // Initialize the list with default capacity (0)
1003
        unsafe {
25✔
1004
            init_fn(frame.data, 0);
25✔
1005
        }
25✔
1006

1007
        // Update tracker to List state
1008
        frame.tracker = Tracker::List {
25✔
1009
            is_initialized: true,
25✔
1010
            current_child: false,
25✔
1011
        };
25✔
1012

1013
        Ok(self)
25✔
1014
    }
36✔
1015

1016
    /// Pushes an element to the list
1017
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
1018
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
72✔
1019
        crate::trace!("begin_list_item()");
1020
        self.require_active()?;
72✔
1021
        let frame = self.frames.last_mut().unwrap();
72✔
1022

1023
        // Check if we're building a smart pointer slice
1024
        if let Tracker::SmartPointerSlice {
1025
            building_item,
14✔
1026
            vtable: _,
1027
        } = &frame.tracker
72✔
1028
        {
1029
            if *building_item {
14✔
NEW
1030
                return Err(ReflectError::OperationFailed {
×
NEW
1031
                    shape: frame.shape,
×
NEW
1032
                    operation: "already building an item, call end() first",
×
NEW
1033
                });
×
1034
            }
14✔
1035

1036
            // Get the element type from the smart pointer's pointee
1037
            let element_shape = match &frame.shape.def {
14✔
1038
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
14✔
1039
                    Some(pointee_shape) => match &pointee_shape.ty {
14✔
1040
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
14✔
1041
                        _ => {
NEW
1042
                            return Err(ReflectError::OperationFailed {
×
NEW
1043
                                shape: frame.shape,
×
NEW
1044
                                operation: "smart pointer pointee is not a slice",
×
NEW
1045
                            });
×
1046
                        }
1047
                    },
1048
                    None => {
NEW
1049
                        return Err(ReflectError::OperationFailed {
×
NEW
1050
                            shape: frame.shape,
×
NEW
1051
                            operation: "smart pointer has no pointee",
×
NEW
1052
                        });
×
1053
                    }
1054
                },
1055
                _ => {
NEW
1056
                    return Err(ReflectError::OperationFailed {
×
NEW
1057
                        shape: frame.shape,
×
NEW
1058
                        operation: "expected smart pointer definition",
×
NEW
1059
                    });
×
1060
                }
1061
            };
1062

1063
            // Allocate space for the element
1064
            crate::trace!("Pointee is a slice of {element_shape}");
1065
            let element_layout = match element_shape.layout.sized_layout() {
14✔
1066
                Ok(layout) => layout,
14✔
1067
                Err(_) => {
NEW
1068
                    return Err(ReflectError::OperationFailed {
×
NEW
1069
                        shape: element_shape,
×
NEW
1070
                        operation: "cannot allocate unsized element",
×
NEW
1071
                    });
×
1072
                }
1073
            };
1074

1075
            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
14✔
1076
            if element_ptr.is_null() {
14✔
NEW
1077
                alloc::alloc::handle_alloc_error(element_layout);
×
1078
            }
14✔
1079

1080
            // Create and push the element frame
1081
            crate::trace!("Pushing element frame, which we just allocated");
1082
            let element_frame = Frame::new(
14✔
1083
                PtrUninit::new(element_ptr),
14✔
1084
                element_shape,
14✔
1085
                FrameOwnership::Owned,
14✔
1086
            );
1087
            self.frames.push(element_frame);
14✔
1088

1089
            // Mark that we're building an item
1090
            // We need to update the tracker after pushing the frame
1091
            let parent_idx = self.frames.len() - 2;
14✔
1092
            if let Tracker::SmartPointerSlice { building_item, .. } =
14✔
1093
                &mut self.frames[parent_idx].tracker
14✔
1094
            {
14✔
1095
                crate::trace!("Marking element frame as building item");
14✔
1096
                *building_item = true;
14✔
1097
            }
14✔
1098

1099
            return Ok(self);
14✔
1100
        }
58✔
1101

1102
        // Check that we have a List that's been initialized
1103
        let list_def = match &frame.shape.def {
58✔
1104
            Def::List(list_def) => list_def,
57✔
1105
            _ => {
1106
                return Err(ReflectError::OperationFailed {
1✔
1107
                    shape: frame.shape,
1✔
1108
                    operation: "push can only be called on List types",
1✔
1109
                });
1✔
1110
            }
1111
        };
1112

1113
        // Verify the tracker is in List state and initialized
1114
        match &mut frame.tracker {
57✔
1115
            Tracker::List {
1116
                is_initialized: true,
1117
                current_child,
57✔
1118
            } => {
1119
                if *current_child {
57✔
NEW
1120
                    return Err(ReflectError::OperationFailed {
×
NEW
1121
                        shape: frame.shape,
×
NEW
1122
                        operation: "already pushing an element, call pop() first",
×
NEW
1123
                    });
×
1124
                }
57✔
1125
                *current_child = true;
57✔
1126
            }
1127
            _ => {
NEW
1128
                return Err(ReflectError::OperationFailed {
×
NEW
1129
                    shape: frame.shape,
×
NEW
1130
                    operation: "must call begin_list() before push()",
×
NEW
1131
                });
×
1132
            }
1133
        }
1134

1135
        // Get the element shape
1136
        let element_shape = list_def.t();
57✔
1137

1138
        // Allocate space for the new element
1139
        let element_layout = match element_shape.layout.sized_layout() {
57✔
1140
            Ok(layout) => layout,
57✔
1141
            Err(_) => {
NEW
1142
                return Err(ReflectError::Unsized {
×
NEW
1143
                    shape: element_shape,
×
NEW
1144
                    operation: "begin_list_item: calculating element layout",
×
NEW
1145
                });
×
1146
            }
1147
        };
1148
        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
57✔
1149

1150
        if element_ptr.is_null() {
57✔
NEW
1151
            return Err(ReflectError::OperationFailed {
×
NEW
1152
                shape: frame.shape,
×
NEW
1153
                operation: "failed to allocate memory for list element",
×
NEW
1154
            });
×
1155
        }
57✔
1156

1157
        // Push a new frame for the element
1158
        self.frames.push(Frame::new(
57✔
1159
            PtrUninit::new(element_ptr),
57✔
1160
            element_shape,
57✔
1161
            FrameOwnership::Owned,
57✔
1162
        ));
1163

1164
        Ok(self)
57✔
1165
    }
72✔
1166

1167
    /// Begins a map initialization operation
1168
    /// This initializes the map with default capacity and allows inserting key-value pairs
1169
    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
12✔
1170
        self.require_active()?;
12✔
1171
        let frame = self.frames.last_mut().unwrap();
12✔
1172

1173
        // Check that we have a Map
1174
        let map_def = match &frame.shape.def {
12✔
1175
            Def::Map(map_def) => map_def,
12✔
1176
            _ => {
NEW
1177
                return Err(ReflectError::OperationFailed {
×
NEW
1178
                    shape: frame.shape,
×
NEW
1179
                    operation: "begin_map can only be called on Map types",
×
NEW
1180
                });
×
1181
            }
1182
        };
1183

1184
        // Check that we have init_in_place_with_capacity function
1185
        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
12✔
1186

1187
        // Initialize the map with default capacity (0)
1188
        unsafe {
12✔
1189
            init_fn(frame.data, 0);
12✔
1190
        }
12✔
1191

1192
        // Update tracker to Map state
1193
        frame.tracker = Tracker::Map {
12✔
1194
            is_initialized: true,
12✔
1195
            insert_state: MapInsertState::Idle,
12✔
1196
        };
12✔
1197

1198
        Ok(self)
12✔
1199
    }
12✔
1200

1201
    /// Pushes a frame for the map key
1202
    /// Automatically starts a new insert if we're idle
1203
    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
13✔
1204
        self.require_active()?;
13✔
1205
        let frame = self.frames.last_mut().unwrap();
13✔
1206

1207
        // Check that we have a Map and set up for key insertion
1208
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
13✔
1209
            (
1210
                Def::Map(map_def),
13✔
1211
                Tracker::Map {
1212
                    is_initialized: true,
1213
                    insert_state,
13✔
1214
                },
1215
            ) => {
1216
                match insert_state {
13✔
1217
                    MapInsertState::Idle => {
13✔
1218
                        // Start a new insert automatically
13✔
1219
                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
13✔
1220
                    }
13✔
NEW
1221
                    MapInsertState::PushingKey { key_ptr } => {
×
NEW
1222
                        if key_ptr.is_some() {
×
NEW
1223
                            return Err(ReflectError::OperationFailed {
×
NEW
1224
                                shape: frame.shape,
×
NEW
1225
                                operation: "already pushing a key, call end() first",
×
NEW
1226
                            });
×
NEW
1227
                        }
×
1228
                    }
1229
                    _ => {
NEW
1230
                        return Err(ReflectError::OperationFailed {
×
NEW
1231
                            shape: frame.shape,
×
NEW
1232
                            operation: "must complete current operation before begin_key()",
×
NEW
1233
                        });
×
1234
                    }
1235
                }
1236
                map_def
13✔
1237
            }
1238
            _ => {
NEW
1239
                return Err(ReflectError::OperationFailed {
×
NEW
1240
                    shape: frame.shape,
×
NEW
1241
                    operation: "must call begin_map() before begin_key()",
×
NEW
1242
                });
×
1243
            }
1244
        };
1245

1246
        // Get the key shape
1247
        let key_shape = map_def.k();
13✔
1248

1249
        // Allocate space for the key
1250
        let key_layout = match key_shape.layout.sized_layout() {
13✔
1251
            Ok(layout) => layout,
13✔
1252
            Err(_) => {
NEW
1253
                return Err(ReflectError::Unsized {
×
NEW
1254
                    shape: key_shape,
×
NEW
1255
                    operation: "begin_key allocating key",
×
NEW
1256
                });
×
1257
            }
1258
        };
1259
        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
13✔
1260

1261
        if key_ptr_raw.is_null() {
13✔
NEW
1262
            return Err(ReflectError::OperationFailed {
×
NEW
1263
                shape: frame.shape,
×
NEW
1264
                operation: "failed to allocate memory for map key",
×
NEW
1265
            });
×
1266
        }
13✔
1267

1268
        // Store the key pointer in the insert state
1269
        match &mut frame.tracker {
13✔
1270
            Tracker::Map {
1271
                insert_state: MapInsertState::PushingKey { key_ptr: kp },
13✔
1272
                ..
1273
            } => {
13✔
1274
                *kp = Some(PtrUninit::new(key_ptr_raw));
13✔
1275
            }
13✔
NEW
1276
            _ => unreachable!(),
×
1277
        }
1278

1279
        // Push a new frame for the key
1280
        self.frames.push(Frame::new(
13✔
1281
            PtrUninit::new(key_ptr_raw),
13✔
1282
            key_shape,
13✔
1283
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
13✔
1284
        ));
1285

1286
        Ok(self)
13✔
1287
    }
13✔
1288

1289
    /// Pushes a frame for the map value
1290
    /// Must be called after the key has been set and popped
1291
    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
10✔
1292
        self.require_active()?;
10✔
1293
        let frame = self.frames.last_mut().unwrap();
10✔
1294

1295
        // Check that we have a Map in PushingValue state
1296
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
10✔
1297
            (
1298
                Def::Map(map_def),
10✔
1299
                Tracker::Map {
1300
                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
10✔
1301
                    ..
1302
                },
1303
            ) => {
1304
                if value_ptr.is_some() {
10✔
NEW
1305
                    return Err(ReflectError::OperationFailed {
×
NEW
1306
                        shape: frame.shape,
×
NEW
1307
                        operation: "already pushing a value, call pop() first",
×
NEW
1308
                    });
×
1309
                }
10✔
1310
                map_def
10✔
1311
            }
1312
            _ => {
NEW
1313
                return Err(ReflectError::OperationFailed {
×
NEW
1314
                    shape: frame.shape,
×
NEW
1315
                    operation: "must complete key before push_value()",
×
NEW
1316
                });
×
1317
            }
1318
        };
1319

1320
        // Get the value shape
1321
        let value_shape = map_def.v();
10✔
1322

1323
        // Allocate space for the value
1324
        let value_layout = match value_shape.layout.sized_layout() {
10✔
1325
            Ok(layout) => layout,
10✔
1326
            Err(_) => {
NEW
1327
                return Err(ReflectError::Unsized {
×
NEW
1328
                    shape: value_shape,
×
NEW
1329
                    operation: "begin_value allocating value",
×
NEW
1330
                });
×
1331
            }
1332
        };
1333
        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
10✔
1334

1335
        if value_ptr_raw.is_null() {
10✔
NEW
1336
            return Err(ReflectError::OperationFailed {
×
NEW
1337
                shape: frame.shape,
×
NEW
1338
                operation: "failed to allocate memory for map value",
×
NEW
1339
            });
×
1340
        }
10✔
1341

1342
        // Store the value pointer in the insert state
1343
        match &mut frame.tracker {
10✔
1344
            Tracker::Map {
1345
                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
10✔
1346
                ..
1347
            } => {
10✔
1348
                *vp = Some(PtrUninit::new(value_ptr_raw));
10✔
1349
            }
10✔
NEW
1350
            _ => unreachable!(),
×
1351
        }
1352

1353
        // Push a new frame for the value
1354
        self.frames.push(Frame::new(
10✔
1355
            PtrUninit::new(value_ptr_raw),
10✔
1356
            value_shape,
10✔
1357
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
10✔
1358
        ));
1359

1360
        Ok(self)
10✔
1361
    }
10✔
1362

1363
    /// Pops the current frame off the stack, indicating we're done initializing the current field
1364
    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
342✔
1365
        crate::trace!("end() called");
1366
        self.require_active()?;
342✔
1367

1368
        // Special handling for SmartPointerSlice - convert builder to Arc
1369
        if self.frames.len() == 1 {
342✔
1370
            if let Tracker::SmartPointerSlice {
1371
                vtable,
6✔
1372
                building_item,
6✔
1373
            } = &self.frames[0].tracker
6✔
1374
            {
1375
                if *building_item {
6✔
NEW
1376
                    return Err(ReflectError::OperationFailed {
×
NEW
1377
                        shape: self.frames[0].shape,
×
NEW
1378
                        operation: "still building an item, finish it first",
×
NEW
1379
                    });
×
1380
                }
6✔
1381

1382
                // Convert the builder to Arc<[T]>
1383
                let builder_ptr = unsafe { self.frames[0].data.assume_init() };
6✔
1384
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
6✔
1385

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

1392
                return Ok(self);
6✔
NEW
1393
            }
×
1394
        }
336✔
1395

1396
        if self.frames.len() <= 1 {
336✔
1397
            // Never pop the last/root frame.
NEW
1398
            return Err(ReflectError::InvariantViolation {
×
NEW
1399
                invariant: "Partial::end() called with only one frame on the stack",
×
NEW
1400
            });
×
1401
        }
336✔
1402

1403
        // Require that the top frame is fully initialized before popping.
1404
        {
1405
            let frame = self.frames.last().unwrap();
336✔
1406
            trace!(
1407
                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
1408
                frame.shape,
1409
                frame.tracker.kind()
1410
            );
1411
            frame.require_full_initialization()?
336✔
1412
        }
1413

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

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

1420
        trace!(
1421
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
1422
            popped_frame.shape,
1423
            popped_frame.tracker.kind(),
1424
            parent_frame.shape,
1425
            parent_frame.tracker.kind()
1426
        );
1427

1428
        // Check if we need to do a conversion - this happens when:
1429
        // 1. The parent frame has an inner type that matches the popped frame's shape
1430
        // 2. The parent frame has try_from
1431
        // 3. The parent frame is not yet initialized
1432
        let needs_conversion = matches!(parent_frame.tracker, Tracker::Uninit)
334✔
1433
            && parent_frame.shape.inner.is_some()
4✔
1434
            && parent_frame.shape.inner.unwrap()() == popped_frame.shape
4✔
NEW
1435
            && parent_frame
×
NEW
1436
                .shape
×
NEW
1437
                .vtable
×
NEW
1438
                .sized()
×
NEW
1439
                .and_then(|v| (v.try_from)())
×
NEW
1440
                .is_some();
×
1441

1442
        if needs_conversion {
334✔
1443
            trace!(
1444
                "Detected implicit conversion needed from {} to {}",
1445
                popped_frame.shape, parent_frame.shape
1446
            );
1447
            // Perform the conversion
NEW
1448
            if let Some(try_from_fn) = parent_frame
×
NEW
1449
                .shape
×
NEW
1450
                .vtable
×
NEW
1451
                .sized()
×
NEW
1452
                .and_then(|v| (v.try_from)())
×
1453
            {
NEW
1454
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
×
NEW
1455
                let inner_shape = popped_frame.shape;
×
1456

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

NEW
1460
                if let Err(e) = result {
×
1461
                    trace!("Conversion failed: {e:?}");
1462

1463
                    // Deallocate the inner value's memory since conversion failed
NEW
1464
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
1465
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
1466
                            if layout.size() > 0 {
×
1467
                                trace!(
1468
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
1469
                                    layout.size(),
1470
                                    layout.align()
1471
                                );
NEW
1472
                                unsafe {
×
NEW
1473
                                    alloc::alloc::dealloc(
×
NEW
1474
                                        popped_frame.data.as_mut_byte_ptr(),
×
NEW
1475
                                        layout,
×
NEW
1476
                                    );
×
NEW
1477
                                }
×
NEW
1478
                            }
×
NEW
1479
                        }
×
NEW
1480
                    }
×
1481

NEW
1482
                    return Err(ReflectError::TryFromError {
×
NEW
1483
                        src_shape: inner_shape,
×
NEW
1484
                        dst_shape: parent_frame.shape,
×
NEW
1485
                        inner: e,
×
NEW
1486
                    });
×
NEW
1487
                }
×
1488

1489
                trace!("Conversion succeeded, marking parent as initialized");
NEW
1490
                parent_frame.tracker = Tracker::Init;
×
1491

1492
                // Deallocate the inner value's memory since try_from consumed it
NEW
1493
                if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
1494
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
1495
                        if layout.size() > 0 {
×
1496
                            trace!(
1497
                                "Deallocating conversion frame memory: size={}, align={}",
1498
                                layout.size(),
1499
                                layout.align()
1500
                            );
NEW
1501
                            unsafe {
×
NEW
1502
                                alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
×
NEW
1503
                            }
×
NEW
1504
                        }
×
NEW
1505
                    }
×
NEW
1506
                }
×
1507

NEW
1508
                return Ok(self);
×
NEW
1509
            }
×
1510
        }
334✔
1511

1512
        match &mut parent_frame.tracker {
334✔
1513
            Tracker::Struct {
1514
                iset,
158✔
1515
                current_child,
158✔
1516
            } => {
1517
                if let Some(idx) = *current_child {
158✔
1518
                    iset.set(idx);
158✔
1519
                    *current_child = None;
158✔
1520
                }
158✔
1521
            }
1522
            Tracker::Array {
1523
                iset,
37✔
1524
                current_child,
37✔
1525
            } => {
1526
                if let Some(idx) = *current_child {
37✔
1527
                    iset.set(idx);
37✔
1528
                    *current_child = None;
37✔
1529
                }
37✔
1530
            }
1531
            Tracker::SmartPointer { is_initialized } => {
7✔
1532
                // We just popped the inner value frame, so now we need to create the smart pointer
1533
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
7✔
1534
                    if let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn {
7✔
1535
                        // The child frame contained the inner value
1536
                        let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
7✔
1537

1538
                        // Use new_into_fn to create the Box
1539
                        unsafe {
7✔
1540
                            new_into_fn(parent_frame.data, inner_ptr);
7✔
1541
                        }
7✔
1542

1543
                        // Deallocate the inner value's memory since new_into_fn moved it
1544
                        if let FrameOwnership::Owned = popped_frame.ownership {
7✔
1545
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
7✔
1546
                                if layout.size() > 0 {
7✔
1547
                                    unsafe {
7✔
1548
                                        alloc::alloc::dealloc(
7✔
1549
                                            popped_frame.data.as_mut_byte_ptr(),
7✔
1550
                                            layout,
7✔
1551
                                        );
7✔
1552
                                    }
7✔
NEW
1553
                                }
×
NEW
1554
                            }
×
NEW
1555
                        }
×
1556

1557
                        *is_initialized = true;
7✔
1558
                    } else {
NEW
1559
                        return Err(ReflectError::OperationFailed {
×
NEW
1560
                            shape: parent_frame.shape,
×
NEW
1561
                            operation: "SmartPointer missing new_into_fn",
×
NEW
1562
                        });
×
1563
                    }
NEW
1564
                }
×
1565
            }
1566
            Tracker::Enum {
1567
                data,
42✔
1568
                current_child,
42✔
1569
                ..
1570
            } => {
1571
                if let Some(idx) = *current_child {
42✔
1572
                    data.set(idx);
42✔
1573
                    *current_child = None;
42✔
1574
                }
42✔
1575
            }
1576
            Tracker::List {
1577
                is_initialized: true,
1578
                current_child,
51✔
1579
            } => {
1580
                if *current_child {
51✔
1581
                    // We just popped an element frame, now push it to the list
1582
                    if let Def::List(list_def) = parent_frame.shape.def {
51✔
1583
                        if let Some(push_fn) = list_def.vtable.push {
51✔
1584
                            // The child frame contained the element value
1585
                            let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
51✔
1586

1587
                            // Use push to add element to the list
1588
                            unsafe {
51✔
1589
                                push_fn(
51✔
1590
                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
51✔
1591
                                    element_ptr,
51✔
1592
                                );
51✔
1593
                            }
51✔
1594

1595
                            // Deallocate the element's memory since push moved it
1596
                            if let FrameOwnership::Owned = popped_frame.ownership {
51✔
1597
                                if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
51✔
1598
                                    if layout.size() > 0 {
51✔
1599
                                        unsafe {
51✔
1600
                                            alloc::alloc::dealloc(
51✔
1601
                                                popped_frame.data.as_mut_byte_ptr(),
51✔
1602
                                                layout,
51✔
1603
                                            );
51✔
1604
                                        }
51✔
NEW
1605
                                    }
×
NEW
1606
                                }
×
NEW
1607
                            }
×
1608

1609
                            *current_child = false;
51✔
1610
                        } else {
NEW
1611
                            return Err(ReflectError::OperationFailed {
×
NEW
1612
                                shape: parent_frame.shape,
×
NEW
1613
                                operation: "List missing push function",
×
NEW
1614
                            });
×
1615
                        }
NEW
1616
                    }
×
NEW
1617
                }
×
1618
            }
1619
            Tracker::Map {
1620
                is_initialized: true,
1621
                insert_state,
19✔
1622
            } => {
1623
                match insert_state {
19✔
1624
                    MapInsertState::PushingKey { key_ptr } => {
11✔
1625
                        // We just popped the key frame
1626
                        if let Some(key_ptr) = key_ptr {
11✔
1627
                            // Transition to PushingValue state
11✔
1628
                            *insert_state = MapInsertState::PushingValue {
11✔
1629
                                key_ptr: *key_ptr,
11✔
1630
                                value_ptr: None,
11✔
1631
                            };
11✔
1632
                        }
11✔
1633
                    }
1634
                    MapInsertState::PushingValue { key_ptr, value_ptr } => {
8✔
1635
                        // We just popped the value frame, now insert the pair
1636
                        if let (Some(value_ptr), Def::Map(map_def)) =
8✔
1637
                            (value_ptr, parent_frame.shape.def)
8✔
1638
                        {
1639
                            let insert_fn = map_def.vtable.insert_fn;
8✔
1640

1641
                            // Use insert to add key-value pair to the map
1642
                            unsafe {
8✔
1643
                                insert_fn(
8✔
1644
                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
8✔
1645
                                    PtrMut::new(key_ptr.as_mut_byte_ptr()),
8✔
1646
                                    PtrMut::new(value_ptr.as_mut_byte_ptr()),
8✔
1647
                                );
8✔
1648
                            }
8✔
1649

1650
                            // Note: We don't deallocate the key and value memory here.
1651
                            // The insert function has semantically moved the values into the map,
1652
                            // but we still need to deallocate the temporary buffers.
1653
                            // However, since we don't have frames for them anymore (they were popped),
1654
                            // we need to handle deallocation here.
1655
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
8✔
1656
                                if key_shape.size() > 0 {
8✔
1657
                                    unsafe {
8✔
1658
                                        alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
8✔
1659
                                    }
8✔
NEW
1660
                                }
×
NEW
1661
                            }
×
1662
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
8✔
1663
                                if value_shape.size() > 0 {
8✔
1664
                                    unsafe {
8✔
1665
                                        alloc::alloc::dealloc(
8✔
1666
                                            value_ptr.as_mut_byte_ptr(),
8✔
1667
                                            value_shape,
8✔
1668
                                        );
8✔
1669
                                    }
8✔
NEW
1670
                                }
×
NEW
1671
                            }
×
1672

1673
                            // Reset to idle state
1674
                            *insert_state = MapInsertState::Idle;
8✔
NEW
1675
                        }
×
1676
                    }
NEW
1677
                    MapInsertState::Idle => {
×
NEW
1678
                        // Nothing to do
×
NEW
1679
                    }
×
1680
                }
1681
            }
1682
            Tracker::Option { building_inner } => {
1✔
1683
                // We just popped the inner value frame for an Option's Some variant
1684
                if *building_inner {
1✔
1685
                    if let Def::Option(option_def) = parent_frame.shape.def {
1✔
1686
                        // Use the Option vtable to initialize Some(inner_value)
1687
                        let init_some_fn = option_def.vtable.init_some_fn;
1✔
1688

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

1692
                        // Initialize the Option as Some(inner_value)
1693
                        unsafe {
1✔
1694
                            init_some_fn(parent_frame.data, inner_value_ptr);
1✔
1695
                        }
1✔
1696

1697
                        // Deallocate the inner value's memory since init_some_fn moved it
1698
                        if let FrameOwnership::Owned = popped_frame.ownership {
1✔
1699
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
1✔
1700
                                if layout.size() > 0 {
1✔
1701
                                    unsafe {
1✔
1702
                                        alloc::alloc::dealloc(
1✔
1703
                                            popped_frame.data.as_mut_byte_ptr(),
1✔
1704
                                            layout,
1✔
1705
                                        );
1✔
1706
                                    }
1✔
NEW
1707
                                }
×
NEW
1708
                            }
×
NEW
1709
                        }
×
1710

1711
                        // Mark that we're no longer building the inner value
1712
                        *building_inner = false;
1✔
1713
                    } else {
NEW
1714
                        return Err(ReflectError::OperationFailed {
×
NEW
1715
                            shape: parent_frame.shape,
×
NEW
1716
                            operation: "Option frame without Option definition",
×
NEW
1717
                        });
×
1718
                    }
NEW
1719
                }
×
1720
            }
1721
            Tracker::Uninit | Tracker::Init => {
1722
                // the main case here is: the popped frame was a `String` and the
1723
                // parent frame is an `Arc<str>`, `Box<str>` etc.
1724
                match &parent_frame.shape.def {
5✔
1725
                    Def::Pointer(smart_ptr_def) => {
5✔
1726
                        let pointee =
5✔
1727
                            smart_ptr_def
5✔
1728
                                .pointee()
5✔
1729
                                .ok_or(ReflectError::InvariantViolation {
5✔
1730
                                    invariant: "pointer type doesn't have a pointee",
5✔
1731
                                })?;
5✔
1732

1733
                        if !pointee.is_shape(str::SHAPE) {
5✔
NEW
1734
                            return Err(ReflectError::InvariantViolation {
×
NEW
1735
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
NEW
1736
                            });
×
1737
                        }
5✔
1738

1739
                        if !popped_frame.shape.is_shape(String::SHAPE) {
5✔
NEW
1740
                            return Err(ReflectError::InvariantViolation {
×
NEW
1741
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
NEW
1742
                            });
×
1743
                        }
5✔
1744

1745
                        popped_frame.require_full_initialization()?;
5✔
1746

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

1754
                        let Some(known) = smart_ptr_def.known else {
5✔
NEW
1755
                            return Err(ReflectError::OperationFailed {
×
NEW
1756
                                shape: parent_shape,
×
NEW
1757
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
NEW
1758
                            });
×
1759
                        };
1760

1761
                        parent_frame.deinit();
5✔
1762

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

1767
                        match known {
5✔
1768
                            KnownPointer::Box => {
1769
                                let boxed: Box<str> = string_value.into_boxed_str();
1✔
1770
                                unsafe {
1✔
1771
                                    core::ptr::write(
1✔
1772
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1✔
1773
                                        boxed,
1✔
1774
                                    );
1✔
1775
                                }
1✔
1776
                            }
1777
                            KnownPointer::Arc => {
1778
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1✔
1779
                                unsafe {
1✔
1780
                                    core::ptr::write(
1✔
1781
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1✔
1782
                                        arc,
1✔
1783
                                    );
1✔
1784
                                }
1✔
1785
                            }
1786
                            KnownPointer::Rc => {
1787
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
3✔
1788
                                unsafe {
3✔
1789
                                    core::ptr::write(
3✔
1790
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
3✔
1791
                                        rc,
3✔
1792
                                    );
3✔
1793
                                }
3✔
1794
                            }
1795
                            _ => {
NEW
1796
                                return Err(ReflectError::OperationFailed {
×
NEW
1797
                                    shape: parent_shape,
×
NEW
1798
                                    operation: "Don't know how to build this pointer type",
×
NEW
1799
                                });
×
1800
                            }
1801
                        }
1802

1803
                        parent_frame.tracker = Tracker::Init;
5✔
1804

1805
                        popped_frame.tracker = Tracker::Uninit;
5✔
1806
                        popped_frame.dealloc();
5✔
1807
                    }
1808
                    _ => {
NEW
1809
                        unreachable!(
×
1810
                            "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"
1811
                        )
1812
                    }
1813
                }
1814
            }
1815
            Tracker::SmartPointerSlice {
1816
                vtable,
14✔
1817
                building_item,
14✔
1818
            } => {
1819
                if *building_item {
14✔
1820
                    // We just popped an element frame, now push it to the slice builder
1821
                    let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
14✔
1822

1823
                    // Use the slice builder's push_fn to add the element
1824
                    crate::trace!("Pushing element to slice builder");
1825
                    unsafe {
14✔
1826
                        let parent_ptr = parent_frame.data.assume_init();
14✔
1827
                        (vtable.push_fn)(parent_ptr, element_ptr);
14✔
1828
                    }
14✔
1829

1830
                    // Deallocate the element's memory since push_fn moved it
1831
                    if let FrameOwnership::Owned = popped_frame.ownership {
14✔
1832
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
14✔
1833
                            if layout.size() > 0 {
14✔
1834
                                unsafe {
14✔
1835
                                    alloc::alloc::dealloc(
14✔
1836
                                        popped_frame.data.as_mut_byte_ptr(),
14✔
1837
                                        layout,
14✔
1838
                                    );
14✔
1839
                                }
14✔
NEW
1840
                            }
×
NEW
1841
                        }
×
NEW
1842
                    }
×
1843

1844
                    if let Tracker::SmartPointerSlice {
1845
                        building_item: bi, ..
14✔
1846
                    } = &mut parent_frame.tracker
14✔
1847
                    {
14✔
1848
                        *bi = false;
14✔
1849
                    }
14✔
NEW
1850
                }
×
1851
            }
NEW
1852
            _ => {}
×
1853
        }
1854

1855
        Ok(self)
334✔
1856
    }
342✔
1857

1858
    /// Builds the value
1859
    pub fn build(&mut self) -> Result<HeapValue<'facet>, ReflectError> {
159✔
1860
        self.require_active()?;
159✔
1861
        if self.frames.len() != 1 {
158✔
1862
            self.state = PartialState::BuildFailed;
2✔
1863
            return Err(ReflectError::InvariantViolation {
2✔
1864
                invariant: "Partial::build() expects a single frame — call end() until that's the case",
2✔
1865
            });
2✔
1866
        }
156✔
1867

1868
        let frame = self.frames.pop().unwrap();
156✔
1869

1870
        // Check initialization before proceeding
1871
        if let Err(e) = frame.require_full_initialization() {
156✔
1872
            // Put the frame back so Drop can handle cleanup properly
1873
            self.frames.push(frame);
26✔
1874
            self.state = PartialState::BuildFailed;
26✔
1875
            return Err(e);
26✔
1876
        }
130✔
1877

1878
        // Check invariants if present
1879
        if let Some(invariants_fn) = frame.shape.vtable.sized().and_then(|v| (v.invariants)()) {
130✔
1880
            // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
1881
            let value_ptr = unsafe { frame.data.assume_init().as_const() };
6✔
1882
            let invariants_ok = unsafe { invariants_fn(value_ptr) };
6✔
1883

1884
            if !invariants_ok {
6✔
1885
                // Put the frame back so Drop can handle cleanup properly
1886
                self.frames.push(frame);
3✔
1887
                self.state = PartialState::BuildFailed;
3✔
1888
                return Err(ReflectError::InvariantViolation {
3✔
1889
                    invariant: "Type invariants check failed",
3✔
1890
                });
3✔
1891
            }
3✔
1892
        }
124✔
1893

1894
        // Mark as built to prevent reuse
1895
        self.state = PartialState::Built;
127✔
1896

1897
        match frame
127✔
1898
            .shape
127✔
1899
            .layout
127✔
1900
            .sized_layout()
127✔
1901
            .map_err(|_layout_err| ReflectError::Unsized {
127✔
NEW
1902
                shape: frame.shape,
×
1903
                operation: "build (final check for sized layout)",
NEW
1904
            }) {
×
1905
            Ok(layout) => Ok(HeapValue {
127✔
1906
                guard: Some(Guard {
127✔
1907
                    ptr: frame.data.as_mut_byte_ptr(),
127✔
1908
                    layout,
127✔
1909
                }),
127✔
1910
                shape: frame.shape,
127✔
1911
                phantom: PhantomData,
127✔
1912
            }),
127✔
NEW
1913
            Err(e) => {
×
1914
                // Put the frame back for proper cleanup
NEW
1915
                self.frames.push(frame);
×
NEW
1916
                self.state = PartialState::BuildFailed;
×
NEW
1917
                Err(e)
×
1918
            }
1919
        }
1920
    }
159✔
1921

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

NEW
1927
        let mut path_components = Vec::new();
×
1928
        // The stack of enum/struct/sequence names currently in context.
1929
        // Start from root and build upwards.
NEW
1930
        for (i, frame) in self.frames.iter().enumerate() {
×
NEW
1931
            match frame.shape.ty {
×
NEW
1932
                Type::User(user_type) => match user_type {
×
NEW
1933
                    UserType::Struct(struct_type) => {
×
1934
                        // Try to get currently active field index
NEW
1935
                        let mut field_str = None;
×
1936
                        if let Tracker::Struct {
NEW
1937
                            current_child: Some(idx),
×
1938
                            ..
NEW
1939
                        } = &frame.tracker
×
1940
                        {
NEW
1941
                            if let Some(field) = struct_type.fields.get(*idx) {
×
NEW
1942
                                field_str = Some(field.name);
×
NEW
1943
                            }
×
NEW
1944
                        }
×
NEW
1945
                        if i == 0 {
×
NEW
1946
                            // Use Display for the root struct shape
×
NEW
1947
                            path_components.push(format!("{}", frame.shape));
×
NEW
1948
                        }
×
NEW
1949
                        if let Some(field_name) = field_str {
×
NEW
1950
                            path_components.push(format!(".{field_name}"));
×
NEW
1951
                        }
×
1952
                    }
NEW
1953
                    UserType::Enum(_enum_type) => {
×
1954
                        // Try to get currently active variant and field
1955
                        if let Tracker::Enum {
NEW
1956
                            variant,
×
NEW
1957
                            current_child,
×
1958
                            ..
NEW
1959
                        } = &frame.tracker
×
1960
                        {
NEW
1961
                            if i == 0 {
×
NEW
1962
                                // Use Display for the root enum shape
×
NEW
1963
                                path_components.push(format!("{}", frame.shape));
×
NEW
1964
                            }
×
NEW
1965
                            path_components.push(format!("::{}", variant.name));
×
NEW
1966
                            if let Some(idx) = *current_child {
×
NEW
1967
                                if let Some(field) = variant.data.fields.get(idx) {
×
NEW
1968
                                    path_components.push(format!(".{}", field.name));
×
NEW
1969
                                }
×
NEW
1970
                            }
×
NEW
1971
                        } else if i == 0 {
×
NEW
1972
                            // just the enum display
×
NEW
1973
                            path_components.push(format!("{}", frame.shape));
×
NEW
1974
                        }
×
1975
                    }
NEW
1976
                    UserType::Union(_union_type) => {
×
NEW
1977
                        path_components.push(format!("{}", frame.shape));
×
NEW
1978
                    }
×
NEW
1979
                    UserType::Opaque => {
×
NEW
1980
                        path_components.push("<opaque>".to_string());
×
NEW
1981
                    }
×
1982
                },
NEW
1983
                Type::Sequence(seq_type) => match seq_type {
×
NEW
1984
                    facet_core::SequenceType::Array(_array_def) => {
×
1985
                        // Try to show current element index
1986
                        if let Tracker::Array {
NEW
1987
                            current_child: Some(idx),
×
1988
                            ..
NEW
1989
                        } = &frame.tracker
×
NEW
1990
                        {
×
NEW
1991
                            path_components.push(format!("[{idx}]"));
×
NEW
1992
                        }
×
1993
                    }
1994
                    // You can add more for Slice, Vec, etc., if applicable
NEW
1995
                    _ => {
×
NEW
1996
                        // just indicate "[]" for sequence
×
NEW
1997
                        path_components.push("[]".to_string());
×
NEW
1998
                    }
×
1999
                },
NEW
2000
                Type::Pointer(_) => {
×
NEW
2001
                    // Indicate deref
×
NEW
2002
                    path_components.push("*".to_string());
×
NEW
2003
                }
×
NEW
2004
                _ => {
×
NEW
2005
                    // No structural path
×
NEW
2006
                }
×
2007
            }
2008
        }
2009
        // Merge the path_components into a single string
NEW
2010
        for component in path_components {
×
NEW
2011
            out.push_str(&component);
×
NEW
2012
        }
×
NEW
2013
        out
×
NEW
2014
    }
×
2015

2016
    /// Returns the shape of the current frame.
2017
    #[inline]
2018
    pub fn shape(&self) -> &'static Shape {
7✔
2019
        self.frames
7✔
2020
            .last()
7✔
2021
            .expect("Partial always has at least one frame")
7✔
2022
            .shape
7✔
2023
    }
7✔
2024

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

2029
        match &frame.tracker {
12✔
2030
            Tracker::Uninit => Ok(false),
12✔
NEW
2031
            Tracker::Init => Ok(true),
×
NEW
2032
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
×
NEW
2033
            Tracker::Enum { data, .. } => {
×
2034
                // Check if the field is already marked as set
NEW
2035
                if data.get(index) {
×
NEW
2036
                    return Ok(true);
×
NEW
2037
                }
×
2038

2039
                // For enum variant fields that are empty structs, they are always initialized
NEW
2040
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
NEW
2041
                    if let Some(field) = variant.data.fields.get(index) {
×
NEW
2042
                        if let Type::User(UserType::Struct(field_struct)) = field.shape.ty {
×
NEW
2043
                            if field_struct.fields.is_empty() {
×
NEW
2044
                                return Ok(true);
×
NEW
2045
                            }
×
NEW
2046
                        }
×
NEW
2047
                    }
×
NEW
2048
                }
×
2049

NEW
2050
                Ok(false)
×
2051
            }
NEW
2052
            Tracker::Option { building_inner } => {
×
2053
                // For Options, index 0 represents the inner value
NEW
2054
                if index == 0 {
×
NEW
2055
                    Ok(!building_inner)
×
2056
                } else {
NEW
2057
                    Err(ReflectError::InvalidOperation {
×
NEW
2058
                        operation: "is_field_set",
×
NEW
2059
                        reason: "Option only has one field (index 0)",
×
NEW
2060
                    })
×
2061
                }
2062
            }
NEW
2063
            _ => Err(ReflectError::InvalidOperation {
×
NEW
2064
                operation: "is_field_set",
×
NEW
2065
                reason: "Current frame is not a struct, enum variant, or option",
×
NEW
2066
            }),
×
2067
        }
2068
    }
12✔
2069

2070
    /// Find the index of a field by name in the current struct
NEW
2071
    pub fn field_index(&self, field_name: &str) -> Option<usize> {
×
NEW
2072
        let frame = self.frames.last()?;
×
2073

NEW
2074
        match frame.shape.ty {
×
NEW
2075
            Type::User(UserType::Struct(struct_def)) => {
×
NEW
2076
                struct_def.fields.iter().position(|f| f.name == field_name)
×
2077
            }
2078
            Type::User(UserType::Enum(_)) => {
2079
                // If we're in an enum variant, check its fields
NEW
2080
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
NEW
2081
                    variant
×
NEW
2082
                        .data
×
NEW
2083
                        .fields
×
NEW
2084
                        .iter()
×
NEW
2085
                        .position(|f| f.name == field_name)
×
2086
                } else {
NEW
2087
                    None
×
2088
                }
2089
            }
NEW
2090
            _ => None,
×
2091
        }
NEW
2092
    }
×
2093

2094
    /// Get the currently selected variant for an enum
NEW
2095
    pub fn selected_variant(&self) -> Option<Variant> {
×
NEW
2096
        let frame = self.frames.last()?;
×
2097

NEW
2098
        match &frame.tracker {
×
NEW
2099
            Tracker::Enum { variant, .. } => Some(**variant),
×
NEW
2100
            _ => None,
×
2101
        }
NEW
2102
    }
×
2103

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

NEW
2108
        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
×
NEW
2109
            enum_def
×
NEW
2110
                .variants
×
NEW
2111
                .iter()
×
NEW
2112
                .enumerate()
×
NEW
2113
                .find(|(_, v)| v.name == variant_name)
×
2114
        } else {
NEW
2115
            None
×
2116
        }
NEW
2117
    }
×
2118

2119
    /// Begin building the Some variant of an Option
2120
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1✔
2121
        self.require_active()?;
1✔
2122
        let frame = self.frames.last_mut().unwrap();
1✔
2123

2124
        // Verify we're working with an Option
2125
        let option_def = match frame.shape.def {
1✔
2126
            Def::Option(def) => def,
1✔
2127
            _ => {
NEW
2128
                return Err(ReflectError::WasNotA {
×
NEW
2129
                    expected: "Option",
×
NEW
2130
                    actual: frame.shape,
×
NEW
2131
                });
×
2132
            }
2133
        };
2134

2135
        // Initialize the tracker for Option building
2136
        if matches!(frame.tracker, Tracker::Uninit) {
1✔
2137
            frame.tracker = Tracker::Option {
1✔
2138
                building_inner: true,
1✔
2139
            };
1✔
2140
        }
1✔
2141

2142
        // Get the inner type shape
2143
        let inner_shape = option_def.t;
1✔
2144

2145
        // Allocate memory for the inner value
2146
        let inner_layout =
1✔
2147
            inner_shape
1✔
2148
                .layout
1✔
2149
                .sized_layout()
1✔
2150
                .map_err(|_| ReflectError::Unsized {
1✔
NEW
2151
                    shape: inner_shape,
×
2152
                    operation: "begin_some, allocating Option inner value",
NEW
2153
                })?;
×
2154

2155
        let inner_data = if inner_layout.size() == 0 {
1✔
2156
            // For ZST, use a non-null but unallocated pointer
NEW
2157
            PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
2158
        } else {
2159
            // Allocate memory for the inner value
2160
            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1✔
2161
            if ptr.is_null() {
1✔
NEW
2162
                alloc::alloc::handle_alloc_error(inner_layout);
×
2163
            }
1✔
2164
            PtrUninit::new(ptr)
1✔
2165
        };
2166

2167
        // Create a new frame for the inner value
2168
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1✔
2169
        self.frames.push(inner_frame);
1✔
2170

2171
        Ok(self)
1✔
2172
    }
1✔
2173

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

2178
        // Get the inner shape and check for try_from
NEW
2179
        let (inner_shape, has_try_from, parent_shape) = {
×
NEW
2180
            let frame = self.frames.last().unwrap();
×
NEW
2181
            if let Some(inner_fn) = frame.shape.inner {
×
NEW
2182
                let inner_shape = inner_fn();
×
NEW
2183
                let has_try_from = frame
×
NEW
2184
                    .shape
×
NEW
2185
                    .vtable
×
NEW
2186
                    .sized()
×
NEW
2187
                    .and_then(|v| (v.try_from)())
×
NEW
2188
                    .is_some();
×
NEW
2189
                (Some(inner_shape), has_try_from, frame.shape)
×
2190
            } else {
NEW
2191
                (None, false, frame.shape)
×
2192
            }
2193
        };
2194

NEW
2195
        if let Some(inner_shape) = inner_shape {
×
NEW
2196
            if has_try_from {
×
2197
                // Create a conversion frame with the inner shape
2198

2199
                // For conversion frames, we leave the parent tracker unchanged
2200
                // This allows automatic conversion detection to work properly
2201

2202
                // Allocate memory for the inner value (conversion source)
NEW
2203
                let inner_layout =
×
NEW
2204
                    inner_shape
×
NEW
2205
                        .layout
×
NEW
2206
                        .sized_layout()
×
NEW
2207
                        .map_err(|_| ReflectError::Unsized {
×
NEW
2208
                            shape: inner_shape,
×
2209
                            operation: "begin_inner, getting inner layout",
NEW
2210
                        })?;
×
2211

NEW
2212
                let inner_data = if inner_layout.size() == 0 {
×
2213
                    // For ZST, use a non-null but unallocated pointer
NEW
2214
                    PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
2215
                } else {
2216
                    // Allocate memory for the inner value
NEW
2217
                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
×
NEW
2218
                    if ptr.is_null() {
×
NEW
2219
                        alloc::alloc::handle_alloc_error(inner_layout);
×
NEW
2220
                    }
×
NEW
2221
                    PtrUninit::new(ptr)
×
2222
                };
2223

2224
                // For conversion frames, we create a frame directly with the inner shape
2225
                // This allows setting values of the inner type which will be converted
2226
                // The automatic conversion detection in end() will handle the conversion
2227
                trace!(
2228
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
2229
                );
NEW
2230
                self.frames
×
NEW
2231
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
×
2232

NEW
2233
                Ok(self)
×
2234
            } else {
2235
                // For wrapper types without try_from, navigate to the first field
2236
                // This is a common pattern for newtype wrappers
2237
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
NEW
2238
                self.begin_nth_field(0)
×
2239
            }
2240
        } else {
NEW
2241
            Err(ReflectError::OperationFailed {
×
NEW
2242
                shape: parent_shape,
×
NEW
2243
                operation: "type does not have an inner value",
×
NEW
2244
            })
×
2245
        }
NEW
2246
    }
×
2247

2248
    /// Copy a value from a Peek into the current position (safe alternative to set_shape)
2249
    ///
2250
    /// # Invariants
2251
    ///
2252
    /// `peek` must be a thin pointer, otherwise this panics.
NEW
2253
    pub fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
NEW
2254
        self.require_active()?;
×
2255

2256
        // Get the source value's pointer and shape
NEW
2257
        let src_ptr = peek
×
NEW
2258
            .data()
×
NEW
2259
            .thin()
×
NEW
2260
            .expect("set_from_peek requires thin pointers");
×
NEW
2261
        let src_shape = peek.shape();
×
2262

2263
        // Safety: This is a safe wrapper around set_shape
2264
        // The peek guarantees the source data is valid for its shape
NEW
2265
        unsafe { self.set_shape(src_ptr, src_shape) }
×
NEW
2266
    }
×
2267

2268
    /// Convenience shortcut: sets the nth element of an array directly to value, popping after.
2269
    pub fn set_nth_element<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
34✔
2270
    where
34✔
2271
        U: Facet<'facet>,
34✔
2272
    {
2273
        self.begin_nth_element(idx)?.set(value)?.end()
34✔
2274
    }
34✔
2275

2276
    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
2277
    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
9✔
2278
    where
9✔
2279
        U: Facet<'facet>,
9✔
2280
    {
2281
        self.begin_nth_field(idx)?.set(value)?.end()
9✔
2282
    }
9✔
2283

2284
    /// Convenience shortcut: sets the named field to value, popping after.
2285
    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
70✔
2286
    where
70✔
2287
        U: Facet<'facet>,
70✔
2288
    {
2289
        self.begin_field(field_name)?.set(value)?.end()
70✔
2290
    }
70✔
2291

2292
    /// Convenience shortcut: sets the nth field of an enum variant directly to value, popping after.
2293
    pub fn set_nth_enum_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
2✔
2294
    where
2✔
2295
        U: Facet<'facet>,
2✔
2296
    {
2297
        self.begin_nth_enum_field(idx)?.set(value)?.end()
2✔
2298
    }
2✔
2299

2300
    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
2301
    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2✔
2302
    where
2✔
2303
        U: Facet<'facet>,
2✔
2304
    {
2305
        self.begin_key()?.set(value)?.end()
2✔
2306
    }
2✔
2307

2308
    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
NEW
2309
    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
×
NEW
2310
    where
×
NEW
2311
        U: Facet<'facet>,
×
2312
    {
NEW
2313
        self.begin_value()?.set(value)?.end()
×
NEW
2314
    }
×
2315

2316
    /// Shorthand for: begin_list_item(), set, end
2317
    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
27✔
2318
    where
27✔
2319
        U: Facet<'facet>,
27✔
2320
    {
2321
        self.begin_list_item()?.set(value)?.end()
27✔
2322
    }
27✔
2323
}
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