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

facet-rs / facet / 17649684574

11 Sep 2025 03:36PM UTC coverage: 54.755% (+0.4%) from 54.357%
17649684574

Pull #882

github

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

1072 of 1711 new or added lines in 3 files covered. (62.65%)

2 existing lines in 1 file now uncovered.

4796 of 8759 relevant lines covered (54.76%)

35.92 hits per line

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

60.01
/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> {
225✔
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 {
225✔
25
            shape,
1✔
26
            operation: "alloc_shape",
27
        })?;
1✔
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);
224✔
33
        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
224✔
34

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

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

53
    /// Require that the partial is active
54
    #[inline]
55
    fn require_active(&self) -> Result<(), ReflectError> {
1,784✔
56
        if self.state == PartialState::Active {
1,784✔
57
            Ok(())
1,783✔
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,784✔
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
    ///
83
    /// If the current frame was already initialized, the previous value is
84
    /// dropped. If it was partially initialized, the fields that were initialized
85
    /// are dropped, etc.
86
    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
313✔
87
    where
313✔
88
        U: Facet<'facet>,
313✔
89
    {
90
        self.require_active()?;
313✔
91

92
        let ptr_const = PtrConst::new(&raw const value);
313✔
93
        unsafe {
94
            // Safety: We are calling set_shape with a valid shape and a valid pointer
95
            self.set_shape(ptr_const, U::SHAPE)?
313✔
96
        };
97

98
        // Prevent the value from being dropped since we've copied it
99
        core::mem::forget(value);
312✔
100

101
        Ok(self)
312✔
102
    }
313✔
103

104
    /// Sets a value into the current frame by [PtrConst] / [Shape].
105
    ///
106
    /// # Safety
107
    ///
108
    /// The caller must ensure that `src_value` points to a valid instance of a value
109
    /// whose memory layout and type matches `src_shape`, and that this value can be
110
    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
111
    ///
112
    /// After a successful call, the ownership of the value at `src_value` is effectively moved
113
    /// into the Partial (i.e., the destination), and the original value should not be used
114
    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
115
    ///
116
    /// If an error is returned, the destination remains unmodified and safe for future operations.
117
    #[inline]
118
    pub unsafe fn set_shape(
313✔
119
        &mut self,
313✔
120
        src_value: PtrConst<'_>,
313✔
121
        src_shape: &'static Shape,
313✔
122
    ) -> Result<&mut Self, ReflectError> {
313✔
123
        self.require_active()?;
313✔
124

125
        let fr = self.frames.last_mut().unwrap();
313✔
126
        crate::trace!("set_shape({src_shape:?})");
127

128
        if !fr.shape.is_shape(src_shape) {
313✔
129
            return Err(ReflectError::WrongShape {
1✔
130
                expected: fr.shape,
1✔
131
                actual: src_shape,
1✔
132
            });
1✔
133
        }
312✔
134

135
        fr.deinit();
312✔
136

137
        // SAFETY: `fr.shape` and `src_shape` are the same, so they have the same size,
138
        // and the preconditions for this function are that `src_value` is fully intialized.
139
        unsafe {
312✔
140
            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
312✔
141
            // which is not possible for `Partial`
312✔
142
            fr.data.copy_from(src_value, fr.shape).unwrap();
312✔
143
        }
312✔
144

145
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
146
        unsafe {
312✔
147
            fr.mark_as_init();
312✔
148
        }
312✔
149

150
        Ok(self)
312✔
151
    }
313✔
152

153
    /// Sets the current frame to its default value using `default_in_place` from the
154
    /// vtable.
155
    ///
156
    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
157
    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
158
    /// for `field`.
159
    #[inline]
160
    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
5✔
161
        let frame = self.frames.last().unwrap();
5✔
162

163
        let Some(default_fn) = (frame.shape.vtable.sized().unwrap().default_in_place)() else {
5✔
164
            return Err(ReflectError::OperationFailed {
1✔
165
                shape: frame.shape,
1✔
166
                operation: "type does not implement Default",
1✔
167
            });
1✔
168
        };
169

170
        // Initialize with default value using set_from_function
171
        //
172
        // # Safety
173
        //
174
        // `default_fn` must fully initialize the passed pointer. we took it
175
        // from the vtable of `frame.shape`.
176
        unsafe {
177
            self.set_from_function(move |ptr| {
4✔
178
                default_fn(ptr);
4✔
179
                Ok(())
4✔
180
            })
4✔
181
        }
182
    }
5✔
183

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

195
        let frame = self.frames.last_mut().unwrap();
4✔
196

197
        // First deinit anything previously initialized
198
        frame.deinit();
4✔
199

200
        // Call the function to initialize the value
201
        match f(frame.data) {
4✔
202
            Ok(()) => {
203
                // FIXME: what about finding out the discriminant of enums?
204
                frame.tracker = Tracker::Init;
4✔
205
                Ok(self)
4✔
206
            }
NEW
207
            Err(e) => Err(e),
×
208
        }
209
    }
4✔
210

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

217
        let frame = self.frames.last_mut().unwrap();
2✔
218

219
        // Check if the type has a parse function
220
        let Some(parse_fn) = (frame.shape.vtable.sized().unwrap().parse)() else {
2✔
NEW
221
            return Err(ReflectError::OperationFailed {
×
NEW
222
                shape: frame.shape,
×
NEW
223
                operation: "Type does not support parsing from string",
×
NEW
224
            });
×
225
        };
226

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

230
        // Parse the string value using the type's parse function
231
        let result = unsafe { parse_fn(s, frame.data) };
2✔
232
        if let Err(_pe) = result {
2✔
233
            return Err(ReflectError::OperationFailed {
1✔
234
                shape: frame.shape,
1✔
235
                operation: "Failed to parse string value",
1✔
236
            });
1✔
237
        }
1✔
238

239
        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
240
        unsafe {
1✔
241
            frame.mark_as_init();
1✔
242
        }
1✔
243
        Ok(self)
1✔
244
    }
2✔
245

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

250
        let fr = self.frames.last_mut().unwrap();
30✔
251

252
        // Check that we're dealing with an enum
253
        let enum_type = match fr.shape.ty {
30✔
254
            Type::User(UserType::Enum(e)) => e,
30✔
255
            _ => {
NEW
256
                return Err(ReflectError::OperationFailed {
×
NEW
257
                    shape: fr.shape,
×
NEW
258
                    operation: "push_variant_named requires an enum type",
×
NEW
259
                });
×
260
            }
261
        };
262

263
        // Find the variant with the matching name
264
        let variant = match enum_type.variants.iter().find(|v| v.name == variant_name) {
69✔
265
            Some(v) => v,
28✔
266
            None => {
267
                return Err(ReflectError::OperationFailed {
2✔
268
                    shape: fr.shape,
2✔
269
                    operation: "No variant found with the given name",
2✔
270
                });
2✔
271
            }
272
        };
273

274
        // Get the discriminant value
275
        let discriminant = match variant.discriminant {
28✔
276
            Some(d) => d,
28✔
277
            None => {
NEW
278
                return Err(ReflectError::OperationFailed {
×
NEW
279
                    shape: fr.shape,
×
NEW
280
                    operation: "Variant has no discriminant value",
×
NEW
281
                });
×
282
            }
283
        };
284

285
        // Delegate to push_variant
286
        self.select_variant(discriminant)
28✔
287
    }
30✔
288

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

293
        // Check all invariants early before making any changes
294
        let fr = self.frames.last().unwrap();
38✔
295

296
        // Check that we're dealing with an enum
297
        let enum_type = match fr.shape.ty {
38✔
298
            Type::User(UserType::Enum(e)) => e,
38✔
299
            _ => {
NEW
300
                return Err(ReflectError::WasNotA {
×
NEW
301
                    expected: "enum",
×
NEW
302
                    actual: fr.shape,
×
NEW
303
                });
×
304
            }
305
        };
306

307
        // Find the variant with the matching discriminant
308
        let variant = match enum_type
38✔
309
            .variants
38✔
310
            .iter()
38✔
311
            .find(|v| v.discriminant == Some(discriminant))
79✔
312
        {
313
            Some(v) => v,
38✔
314
            None => {
NEW
315
                return Err(ReflectError::OperationFailed {
×
NEW
316
                    shape: fr.shape,
×
NEW
317
                    operation: "No variant found with the given discriminant",
×
NEW
318
                });
×
319
            }
320
        };
321

322
        // Check enum representation early
323
        match enum_type.enum_repr {
38✔
324
            EnumRepr::RustNPO => {
NEW
325
                return Err(ReflectError::OperationFailed {
×
NEW
326
                    shape: fr.shape,
×
NEW
327
                    operation: "RustNPO enums are not supported for incremental building",
×
NEW
328
                });
×
329
            }
330
            EnumRepr::U8
331
            | EnumRepr::U16
332
            | EnumRepr::U32
333
            | EnumRepr::U64
334
            | EnumRepr::I8
335
            | EnumRepr::I16
336
            | EnumRepr::I32
337
            | EnumRepr::I64
338
            | EnumRepr::USize
339
            | EnumRepr::ISize => {
38✔
340
                // These are supported, continue
38✔
341
            }
38✔
342
        }
343

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

347
        // Write the discriminant to memory
348
        unsafe {
349
            match enum_type.enum_repr {
38✔
350
                EnumRepr::U8 => {
24✔
351
                    let ptr = fr.data.as_mut_byte_ptr();
24✔
352
                    *ptr = discriminant as u8;
24✔
353
                }
24✔
354
                EnumRepr::U16 => {
1✔
355
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
1✔
356
                    *ptr = discriminant as u16;
1✔
357
                }
1✔
358
                EnumRepr::U32 => {
8✔
359
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
8✔
360
                    *ptr = discriminant as u32;
8✔
361
                }
8✔
NEW
362
                EnumRepr::U64 => {
×
NEW
363
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
NEW
364
                    *ptr = discriminant as u64;
×
NEW
365
                }
×
NEW
366
                EnumRepr::I8 => {
×
NEW
367
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
NEW
368
                    *ptr = discriminant as i8;
×
NEW
369
                }
×
370
                EnumRepr::I16 => {
4✔
371
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
372
                    *ptr = discriminant as i16;
4✔
373
                }
4✔
374
                EnumRepr::I32 => {
1✔
375
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
376
                    *ptr = discriminant as i32;
1✔
377
                }
1✔
NEW
378
                EnumRepr::I64 => {
×
NEW
379
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
NEW
380
                    *ptr = discriminant;
×
NEW
381
                }
×
NEW
382
                EnumRepr::USize => {
×
NEW
383
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
NEW
384
                    *ptr = discriminant as usize;
×
NEW
385
                }
×
NEW
386
                EnumRepr::ISize => {
×
NEW
387
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
NEW
388
                    *ptr = discriminant as isize;
×
NEW
389
                }
×
NEW
390
                _ => unreachable!("Already checked enum representation above"),
×
391
            }
392
        }
393

394
        // Update tracker to track the variant
395
        fr.tracker = Tracker::Enum {
38✔
396
            variant,
38✔
397
            data: ISet::new(variant.data.fields.len()),
38✔
398
            current_child: None,
38✔
399
        };
38✔
400

401
        Ok(self)
38✔
402
    }
38✔
403

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

408
        let fr = self.frames.last().unwrap();
2✔
409

410
        // Check that we're dealing with an enum
411
        let enum_type = match fr.shape.ty {
2✔
412
            Type::User(UserType::Enum(e)) => e,
2✔
413
            _ => {
NEW
414
                return Err(ReflectError::OperationFailed {
×
NEW
415
                    shape: fr.shape,
×
NEW
416
                    operation: "select_nth_variant requires an enum type",
×
NEW
417
                });
×
418
            }
419
        };
420

421
        if index >= enum_type.variants.len() {
2✔
NEW
422
            return Err(ReflectError::OperationFailed {
×
NEW
423
                shape: fr.shape,
×
NEW
424
                operation: "variant index out of bounds",
×
NEW
425
            });
×
426
        }
2✔
427
        let variant = &enum_type.variants[index];
2✔
428

429
        // Get the discriminant value
430
        let discriminant = match variant.discriminant {
2✔
431
            Some(d) => d,
2✔
432
            None => {
NEW
433
                return Err(ReflectError::OperationFailed {
×
NEW
434
                    shape: fr.shape,
×
NEW
435
                    operation: "Variant has no discriminant value",
×
NEW
436
                });
×
437
            }
438
        };
439

440
        // Delegate to select_variant
441
        self.select_variant(discriminant)
2✔
442
    }
2✔
443

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

448
        let frame = self.frames.last_mut().unwrap();
162✔
449
        match frame.shape.ty {
162✔
NEW
450
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
×
NEW
451
                shape: frame.shape,
×
NEW
452
                operation: "cannot select a field from a primitive type",
×
NEW
453
            }),
×
NEW
454
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
NEW
455
                shape: frame.shape,
×
NEW
456
                operation: "cannot select a field from a sequence type",
×
NEW
457
            }),
×
458
            Type::User(user_type) => match user_type {
162✔
459
                UserType::Struct(struct_type) => {
138✔
460
                    let idx = struct_type.fields.iter().position(|f| f.name == field_name);
206✔
461
                    let idx = match idx {
138✔
462
                        Some(idx) => idx,
137✔
463
                        None => {
464
                            return Err(ReflectError::OperationFailed {
1✔
465
                                shape: frame.shape,
1✔
466
                                operation: "field not found",
1✔
467
                            });
1✔
468
                        }
469
                    };
470
                    self.begin_nth_field(idx)
137✔
471
                }
472
                UserType::Enum(_) => {
473
                    // Check if we have a variant selected
474
                    match &frame.tracker {
23✔
475
                        Tracker::Enum { variant, .. } => {
22✔
476
                            let idx = variant
22✔
477
                                .data
22✔
478
                                .fields
22✔
479
                                .iter()
22✔
480
                                .position(|f| f.name == field_name);
33✔
481
                            let idx = match idx {
22✔
482
                                Some(idx) => idx,
20✔
483
                                None => {
484
                                    return Err(ReflectError::OperationFailed {
2✔
485
                                        shape: frame.shape,
2✔
486
                                        operation: "field not found in current enum variant",
2✔
487
                                    });
2✔
488
                                }
489
                            };
490
                            self.begin_nth_enum_field(idx)
20✔
491
                        }
492
                        _ => Err(ReflectError::OperationFailed {
1✔
493
                            shape: frame.shape,
1✔
494
                            operation: "must call push_variant before selecting enum fields",
1✔
495
                        }),
1✔
496
                    }
497
                }
NEW
498
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
499
                    shape: frame.shape,
×
NEW
500
                    operation: "unions are not supported",
×
NEW
501
                }),
×
502
                UserType::Opaque => Err(ReflectError::OperationFailed {
1✔
503
                    shape: frame.shape,
1✔
504
                    operation: "opaque types cannot be reflected upon",
1✔
505
                }),
1✔
506
            },
NEW
507
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
NEW
508
                shape: frame.shape,
×
NEW
509
                operation: "cannot select a field from a pointer type",
×
NEW
510
            }),
×
511
        }
512
    }
162✔
513

514
    /// Selects the nth field of a struct by index
515
    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
174✔
516
        self.require_active()?;
174✔
517
        let frame = self.frames.last_mut().unwrap();
174✔
518
        match frame.shape.ty {
174✔
519
            Type::User(user_type) => match user_type {
174✔
520
                UserType::Struct(struct_type) => {
174✔
521
                    if idx >= struct_type.fields.len() {
174✔
NEW
522
                        return Err(ReflectError::OperationFailed {
×
NEW
523
                            shape: frame.shape,
×
NEW
524
                            operation: "field index out of bounds",
×
NEW
525
                        });
×
526
                    }
174✔
527
                    let field = &struct_type.fields[idx];
174✔
528
                    let mut is_field_init = false;
174✔
529

530
                    match &mut frame.tracker {
174✔
531
                        Tracker::Uninit => {
532
                            frame.tracker = Tracker::Struct {
102✔
533
                                iset: ISet::new(struct_type.fields.len()),
102✔
534
                                current_child: Some(idx),
102✔
535
                            }
102✔
536
                        }
537
                        Tracker::Struct {
538
                            iset,
72✔
539
                            current_child,
72✔
540
                        } => {
541
                            // Check if this field was already initialized
542
                            if iset.get(idx) {
72✔
543
                                is_field_init = true;
3✔
544
                            }
69✔
545
                            *current_child = Some(idx);
72✔
546
                        }
NEW
547
                        _ => unreachable!(),
×
548
                    }
549

550
                    // Push a new frame for this field onto the frames stack.
551
                    let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
174✔
552
                    let field_shape = field.shape;
174✔
553
                    let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
174✔
554
                    if is_field_init {
174✔
555
                        next_frame.tracker = Tracker::Init;
3✔
556
                    }
171✔
557
                    self.frames.push(next_frame);
174✔
558

559
                    Ok(self)
174✔
560
                }
561
                UserType::Enum(_) => {
562
                    // Check if we have a variant selected
NEW
563
                    match &frame.tracker {
×
NEW
564
                        Tracker::Enum { variant, .. } => {
×
NEW
565
                            if idx >= variant.data.fields.len() {
×
NEW
566
                                return Err(ReflectError::OperationFailed {
×
NEW
567
                                    shape: frame.shape,
×
NEW
568
                                    operation: "enum field index out of bounds",
×
NEW
569
                                });
×
NEW
570
                            }
×
NEW
571
                            self.begin_nth_enum_field(idx)
×
572
                        }
NEW
573
                        _ => Err(ReflectError::OperationFailed {
×
NEW
574
                            shape: frame.shape,
×
NEW
575
                            operation: "must call select_variant before selecting enum fields",
×
NEW
576
                        }),
×
577
                    }
578
                }
NEW
579
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
NEW
580
                    shape: frame.shape,
×
NEW
581
                    operation: "unions are not supported",
×
NEW
582
                }),
×
NEW
583
                UserType::Opaque => Err(ReflectError::OperationFailed {
×
NEW
584
                    shape: frame.shape,
×
NEW
585
                    operation: "opaque types cannot be reflected upon",
×
NEW
586
                }),
×
587
            },
NEW
588
            _ => Err(ReflectError::OperationFailed {
×
NEW
589
                shape: frame.shape,
×
NEW
590
                operation: "cannot select a field from this type",
×
NEW
591
            }),
×
592
        }
593
    }
174✔
594

595
    /// Selects the nth element of an array by index
596
    pub fn begin_nth_element(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
38✔
597
        self.require_active()?;
38✔
598
        let frame = self.frames.last_mut().unwrap();
38✔
599
        match frame.shape.ty {
38✔
600
            Type::Sequence(seq_type) => match seq_type {
38✔
601
                facet_core::SequenceType::Array(array_def) => {
38✔
602
                    if idx >= array_def.n {
38✔
603
                        return Err(ReflectError::OperationFailed {
1✔
604
                            shape: frame.shape,
1✔
605
                            operation: "array index out of bounds",
1✔
606
                        });
1✔
607
                    }
37✔
608

609
                    if array_def.n > 63 {
37✔
NEW
610
                        return Err(ReflectError::OperationFailed {
×
NEW
611
                            shape: frame.shape,
×
NEW
612
                            operation: "arrays larger than 63 elements are not yet supported",
×
NEW
613
                        });
×
614
                    }
37✔
615

616
                    // Ensure frame is in Array state
617
                    if matches!(frame.tracker, Tracker::Uninit) {
37✔
618
                        frame.tracker = Tracker::Array {
14✔
619
                            iset: ISet::default(),
14✔
620
                            current_child: None,
14✔
621
                        };
14✔
622
                    }
23✔
623

624
                    match &mut frame.tracker {
37✔
625
                        Tracker::Array {
626
                            iset,
37✔
627
                            current_child,
37✔
628
                        } => {
629
                            // Calculate the offset for this array element
630
                            let element_layout = match array_def.t.layout.sized_layout() {
37✔
631
                                Ok(layout) => layout,
37✔
632
                                Err(_) => {
NEW
633
                                    return Err(ReflectError::Unsized {
×
NEW
634
                                        shape: array_def.t,
×
NEW
635
                                        operation: "begin_nth_element, calculating array element offset",
×
NEW
636
                                    });
×
637
                                }
638
                            };
639
                            let offset = element_layout.size() * idx;
37✔
640

641
                            // Check if this element was already initialized
642
                            if iset.get(idx) {
37✔
643
                                // Drop the existing value before re-initializing
644
                                let element_ptr = unsafe { frame.data.field_init_at(offset) };
1✔
645
                                if let Some(drop_fn) =
1✔
646
                                    array_def.t.vtable.sized().and_then(|v| (v.drop_in_place)())
1✔
647
                                {
1✔
648
                                    unsafe { drop_fn(element_ptr) };
1✔
649
                                }
1✔
650
                                // Unset the bit so we can re-initialize
651
                                iset.unset(idx);
1✔
652
                            }
36✔
653

654
                            *current_child = Some(idx);
37✔
655

656
                            // Create a new frame for the array element
657
                            let element_data = unsafe { frame.data.field_uninit_at(offset) };
37✔
658
                            self.frames.push(Frame::new(
37✔
659
                                element_data,
37✔
660
                                array_def.t,
37✔
661
                                FrameOwnership::Field,
37✔
662
                            ));
663

664
                            Ok(self)
37✔
665
                        }
NEW
666
                        _ => Err(ReflectError::OperationFailed {
×
NEW
667
                            shape: frame.shape,
×
NEW
668
                            operation: "expected array tracker state",
×
NEW
669
                        }),
×
670
                    }
671
                }
NEW
672
                _ => Err(ReflectError::OperationFailed {
×
NEW
673
                    shape: frame.shape,
×
NEW
674
                    operation: "can only select elements from arrays",
×
NEW
675
                }),
×
676
            },
NEW
677
            _ => Err(ReflectError::OperationFailed {
×
NEW
678
                shape: frame.shape,
×
NEW
679
                operation: "cannot select an element from this type",
×
NEW
680
            }),
×
681
        }
682
    }
38✔
683

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

689
        // Ensure we're in an enum with a variant selected
690
        let (variant, enum_type) = match (&frame.tracker, &frame.shape.ty) {
42✔
691
            (Tracker::Enum { variant, .. }, Type::User(UserType::Enum(e))) => (variant, e),
42✔
692
            _ => {
NEW
693
                return Err(ReflectError::OperationFailed {
×
NEW
694
                    shape: frame.shape,
×
NEW
695
                    operation: "push_nth_enum_field requires an enum with a variant selected",
×
NEW
696
                });
×
697
            }
698
        };
699

700
        // Check bounds
701
        if idx >= variant.data.fields.len() {
42✔
NEW
702
            return Err(ReflectError::OperationFailed {
×
NEW
703
                shape: frame.shape,
×
NEW
704
                operation: "enum field index out of bounds",
×
NEW
705
            });
×
706
        }
42✔
707

708
        let field = &variant.data.fields[idx];
42✔
709

710
        // Update tracker
711
        match &mut frame.tracker {
42✔
712
            Tracker::Enum {
713
                data,
42✔
714
                current_child,
42✔
715
                ..
716
            } => {
717
                // Check if field was already initialized and drop if needed
718
                if data.get(idx) {
42✔
719
                    // Calculate the field offset, taking into account the discriminant
720
                    let _discriminant_size = match enum_type.enum_repr {
1✔
NEW
721
                        EnumRepr::U8 | EnumRepr::I8 => 1,
×
722
                        EnumRepr::U16 | EnumRepr::I16 => 2,
1✔
NEW
723
                        EnumRepr::U32 | EnumRepr::I32 => 4,
×
NEW
724
                        EnumRepr::U64 | EnumRepr::I64 => 8,
×
NEW
725
                        EnumRepr::USize | EnumRepr::ISize => core::mem::size_of::<usize>(),
×
726
                        EnumRepr::RustNPO => {
NEW
727
                            return Err(ReflectError::OperationFailed {
×
NEW
728
                                shape: frame.shape,
×
NEW
729
                                operation: "RustNPO enums are not supported",
×
NEW
730
                            });
×
731
                        }
732
                    };
733

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

NEW
737
                    if let Some(drop_fn) =
×
738
                        field.shape.vtable.sized().and_then(|v| (v.drop_in_place)())
1✔
NEW
739
                    {
×
NEW
740
                        unsafe { drop_fn(PtrMut::new(field_ptr)) };
×
741
                    }
1✔
742

743
                    // Unset the bit so we can re-initialize
744
                    data.unset(idx);
1✔
745
                }
41✔
746

747
                // Set current_child to track which field we're initializing
748
                *current_child = Some(idx);
42✔
749
            }
NEW
750
            _ => unreachable!("Already checked that we have Enum tracker"),
×
751
        }
752

753
        // Extract data we need before pushing frame
754
        let field_ptr = unsafe { frame.data.as_mut_byte_ptr().add(field.offset) };
42✔
755
        let field_shape = field.shape;
42✔
756

757
        // Push new frame for the field
758
        self.frames.push(Frame::new(
42✔
759
            PtrUninit::new(field_ptr),
42✔
760
            field_shape,
42✔
761
            FrameOwnership::Field,
42✔
762
        ));
763

764
        Ok(self)
42✔
765
    }
42✔
766

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

773
        // Check that we have a SmartPointer
774
        match &frame.shape.def {
21✔
775
            Def::Pointer(smart_ptr_def) => {
21✔
776
                // Check for supported smart pointer types
777
                match smart_ptr_def.known {
21✔
778
                    Some(KnownPointer::Box)
779
                    | Some(KnownPointer::Rc)
780
                    | Some(KnownPointer::Arc)
781
                    | Some(KnownPointer::SharedReference) => {
21✔
782
                        // Supported types, continue
21✔
783
                    }
21✔
784
                    _ => {
NEW
785
                        return Err(ReflectError::OperationFailed {
×
NEW
786
                            shape: frame.shape,
×
NEW
787
                            operation: "only the following pointers are currently supported: Box<T>, Rc<T>, Arc<T>, and &T",
×
NEW
788
                        });
×
789
                    }
790
                }
791

792
                // Get the pointee shape
793
                let pointee_shape = match smart_ptr_def.pointee() {
21✔
794
                    Some(shape) => shape,
21✔
795
                    None => {
NEW
796
                        return Err(ReflectError::OperationFailed {
×
NEW
797
                            shape: frame.shape,
×
NEW
798
                            operation: "Box must have a pointee shape",
×
NEW
799
                        });
×
800
                    }
801
                };
802

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

807
                    if matches!(frame.tracker, Tracker::Uninit) {
7✔
808
                        frame.tracker = Tracker::SmartPointer {
7✔
809
                            is_initialized: false,
7✔
810
                        };
7✔
811
                    }
7✔
812

813
                    let inner_layout = match pointee_shape.layout.sized_layout() {
7✔
814
                        Ok(layout) => layout,
7✔
815
                        Err(_) => {
NEW
816
                            return Err(ReflectError::Unsized {
×
NEW
817
                                shape: pointee_shape,
×
NEW
818
                                operation: "begin_smart_ptr, calculating inner value layout",
×
NEW
819
                            });
×
820
                        }
821
                    };
822
                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
7✔
823
                    if inner_ptr.is_null() {
7✔
NEW
824
                        return Err(ReflectError::OperationFailed {
×
NEW
825
                            shape: frame.shape,
×
NEW
826
                            operation: "failed to allocate memory for smart pointer inner value",
×
NEW
827
                        });
×
828
                    }
7✔
829

830
                    // Push a new frame for the inner value
831
                    self.frames.push(Frame::new(
7✔
832
                        PtrUninit::new(inner_ptr),
7✔
833
                        pointee_shape,
7✔
834
                        FrameOwnership::Owned,
7✔
835
                    ));
836
                } else {
837
                    // pointee is unsized, we only support a handful of cases there
838
                    if pointee_shape == str::SHAPE {
14✔
839
                        crate::trace!("Pointee is str");
840

841
                        // Allocate space for a String
842
                        let string_layout = String::SHAPE
8✔
843
                            .layout
8✔
844
                            .sized_layout()
8✔
845
                            .expect("String must have a sized layout");
8✔
846
                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
8✔
847
                        if string_ptr.is_null() {
8✔
NEW
848
                            alloc::alloc::handle_alloc_error(string_layout);
×
849
                        }
8✔
850
                        let mut frame = Frame::new(
8✔
851
                            PtrUninit::new(string_ptr),
8✔
852
                            String::SHAPE,
853
                            FrameOwnership::Owned,
8✔
854
                        );
855
                        frame.tracker = Tracker::Uninit;
8✔
856
                        self.frames.push(frame);
8✔
857
                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
6✔
858
                        crate::trace!("Pointee is [{}]", _st.t);
859

860
                        // Get the slice builder vtable
861
                        let slice_builder_vtable = smart_ptr_def
6✔
862
                            .vtable
6✔
863
                            .slice_builder_vtable
6✔
864
                            .ok_or(ReflectError::OperationFailed {
6✔
865
                                shape: frame.shape,
6✔
866
                                operation: "smart pointer does not support slice building",
6✔
867
                            })?;
6✔
868

869
                        // Create a new builder
870
                        let builder_ptr = (slice_builder_vtable.new_fn)();
6✔
871

872
                        // Deallocate the original Arc allocation before replacing with slice builder
873
                        if let FrameOwnership::Owned = frame.ownership {
6✔
874
                            if let Ok(layout) = frame.shape.layout.sized_layout() {
6✔
875
                                if layout.size() > 0 {
6✔
876
                                    unsafe {
6✔
877
                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
6✔
878
                                    };
6✔
879
                                }
6✔
NEW
880
                            }
×
NEW
881
                        }
×
882

883
                        // Update the current frame to use the slice builder
884
                        frame.data = PtrUninit::new(builder_ptr.as_mut_byte_ptr());
6✔
885
                        frame.tracker = Tracker::SmartPointerSlice {
6✔
886
                            vtable: slice_builder_vtable,
6✔
887
                            building_item: false,
6✔
888
                        };
6✔
889
                        // The slice builder memory is managed by the vtable, not by us
890
                        frame.ownership = FrameOwnership::ManagedElsewhere;
6✔
891
                    } else {
NEW
892
                        todo!("unsupported unsize pointee shape: {}", pointee_shape)
×
893
                    }
894
                }
895

896
                Ok(self)
21✔
897
            }
NEW
898
            _ => Err(ReflectError::OperationFailed {
×
NEW
899
                shape: frame.shape,
×
NEW
900
                operation: "push_smart_ptr can only be called on compatible types",
×
NEW
901
            }),
×
902
        }
903
    }
21✔
904

905
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
906
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
907
    /// `push`.
908
    ///
909
    /// `begin_list` does not clear the list if it was previously initialized.
910
    /// `begin_list` does not push a new frame to the stack, and thus does not
911
    /// require `end` to be called afterwards.
912
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
36✔
913
        crate::trace!("begin_list()");
914
        self.require_active()?;
36✔
915
        let frame = self.frames.last_mut().unwrap();
36✔
916

917
        match &frame.tracker {
36✔
918
            Tracker::Uninit => {
28✔
919
                // that's good, let's initialize it
28✔
920
            }
28✔
921
            Tracker::Init => {
922
                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
923
                frame.tracker = Tracker::List {
1✔
924
                    is_initialized: true,
1✔
925
                    current_child: false,
1✔
926
                };
1✔
927
                return Ok(self);
1✔
928
            }
929
            Tracker::List { is_initialized, .. } => {
1✔
930
                if *is_initialized {
1✔
931
                    // already initialized, nothing to do
932
                    return Ok(self);
1✔
NEW
933
                }
×
934
            }
935
            Tracker::SmartPointerSlice { .. } => {
936
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
937
                return Ok(self);
6✔
938
            }
939
            _ => {
NEW
940
                return Err(ReflectError::UnexpectedTracker {
×
NEW
941
                    message: "begin_list called but tracker isn't something list-like",
×
NEW
942
                    current_tracker: frame.tracker.kind(),
×
NEW
943
                });
×
944
            }
945
        };
946

947
        // Check that we have a List
948
        let list_def = match &frame.shape.def {
28✔
949
            Def::List(list_def) => list_def,
25✔
950
            _ => {
951
                return Err(ReflectError::OperationFailed {
3✔
952
                    shape: frame.shape,
3✔
953
                    operation: "begin_list can only be called on List types",
3✔
954
                });
3✔
955
            }
956
        };
957

958
        // Check that we have init_in_place_with_capacity function
959
        let init_fn = match list_def.vtable.init_in_place_with_capacity {
25✔
960
            Some(f) => f,
25✔
961
            None => {
NEW
962
                return Err(ReflectError::OperationFailed {
×
NEW
963
                    shape: frame.shape,
×
NEW
964
                    operation: "list type does not support initialization with capacity",
×
NEW
965
                });
×
966
            }
967
        };
968

969
        // Initialize the list with default capacity (0)
970
        unsafe {
25✔
971
            init_fn(frame.data, 0);
25✔
972
        }
25✔
973

974
        // Update tracker to List state
975
        frame.tracker = Tracker::List {
25✔
976
            is_initialized: true,
25✔
977
            current_child: false,
25✔
978
        };
25✔
979

980
        Ok(self)
25✔
981
    }
36✔
982

983
    /// Pushes an element to the list
984
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
985
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
72✔
986
        crate::trace!("begin_list_item()");
987
        self.require_active()?;
72✔
988
        let frame = self.frames.last_mut().unwrap();
72✔
989

990
        // Check if we're building a smart pointer slice
991
        if let Tracker::SmartPointerSlice {
992
            building_item,
14✔
993
            vtable: _,
994
        } = &frame.tracker
72✔
995
        {
996
            if *building_item {
14✔
NEW
997
                return Err(ReflectError::OperationFailed {
×
NEW
998
                    shape: frame.shape,
×
NEW
999
                    operation: "already building an item, call end() first",
×
NEW
1000
                });
×
1001
            }
14✔
1002

1003
            // Get the element type from the smart pointer's pointee
1004
            let element_shape = match &frame.shape.def {
14✔
1005
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
14✔
1006
                    Some(pointee_shape) => match &pointee_shape.ty {
14✔
1007
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
14✔
1008
                        _ => {
NEW
1009
                            return Err(ReflectError::OperationFailed {
×
NEW
1010
                                shape: frame.shape,
×
NEW
1011
                                operation: "smart pointer pointee is not a slice",
×
NEW
1012
                            });
×
1013
                        }
1014
                    },
1015
                    None => {
NEW
1016
                        return Err(ReflectError::OperationFailed {
×
NEW
1017
                            shape: frame.shape,
×
NEW
1018
                            operation: "smart pointer has no pointee",
×
NEW
1019
                        });
×
1020
                    }
1021
                },
1022
                _ => {
NEW
1023
                    return Err(ReflectError::OperationFailed {
×
NEW
1024
                        shape: frame.shape,
×
NEW
1025
                        operation: "expected smart pointer definition",
×
NEW
1026
                    });
×
1027
                }
1028
            };
1029

1030
            // Allocate space for the element
1031
            crate::trace!("Pointee is a slice of {element_shape}");
1032
            let element_layout = match element_shape.layout.sized_layout() {
14✔
1033
                Ok(layout) => layout,
14✔
1034
                Err(_) => {
NEW
1035
                    return Err(ReflectError::OperationFailed {
×
NEW
1036
                        shape: element_shape,
×
NEW
1037
                        operation: "cannot allocate unsized element",
×
NEW
1038
                    });
×
1039
                }
1040
            };
1041

1042
            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
14✔
1043
            if element_ptr.is_null() {
14✔
NEW
1044
                alloc::alloc::handle_alloc_error(element_layout);
×
1045
            }
14✔
1046

1047
            // Create and push the element frame
1048
            crate::trace!("Pushing element frame, which we just allocated");
1049
            let element_frame = Frame::new(
14✔
1050
                PtrUninit::new(element_ptr),
14✔
1051
                element_shape,
14✔
1052
                FrameOwnership::Owned,
14✔
1053
            );
1054
            self.frames.push(element_frame);
14✔
1055

1056
            // Mark that we're building an item
1057
            // We need to update the tracker after pushing the frame
1058
            let parent_idx = self.frames.len() - 2;
14✔
1059
            if let Tracker::SmartPointerSlice { building_item, .. } =
14✔
1060
                &mut self.frames[parent_idx].tracker
14✔
1061
            {
14✔
1062
                crate::trace!("Marking element frame as building item");
14✔
1063
                *building_item = true;
14✔
1064
            }
14✔
1065

1066
            return Ok(self);
14✔
1067
        }
58✔
1068

1069
        // Check that we have a List that's been initialized
1070
        let list_def = match &frame.shape.def {
58✔
1071
            Def::List(list_def) => list_def,
57✔
1072
            _ => {
1073
                return Err(ReflectError::OperationFailed {
1✔
1074
                    shape: frame.shape,
1✔
1075
                    operation: "push can only be called on List types",
1✔
1076
                });
1✔
1077
            }
1078
        };
1079

1080
        // Verify the tracker is in List state and initialized
1081
        match &mut frame.tracker {
57✔
1082
            Tracker::List {
1083
                is_initialized: true,
1084
                current_child,
57✔
1085
            } => {
1086
                if *current_child {
57✔
NEW
1087
                    return Err(ReflectError::OperationFailed {
×
NEW
1088
                        shape: frame.shape,
×
NEW
1089
                        operation: "already pushing an element, call pop() first",
×
NEW
1090
                    });
×
1091
                }
57✔
1092
                *current_child = true;
57✔
1093
            }
1094
            _ => {
NEW
1095
                return Err(ReflectError::OperationFailed {
×
NEW
1096
                    shape: frame.shape,
×
NEW
1097
                    operation: "must call begin_list() before push()",
×
NEW
1098
                });
×
1099
            }
1100
        }
1101

1102
        // Get the element shape
1103
        let element_shape = list_def.t();
57✔
1104

1105
        // Allocate space for the new element
1106
        let element_layout = match element_shape.layout.sized_layout() {
57✔
1107
            Ok(layout) => layout,
57✔
1108
            Err(_) => {
NEW
1109
                return Err(ReflectError::Unsized {
×
NEW
1110
                    shape: element_shape,
×
NEW
1111
                    operation: "begin_list_item: calculating element layout",
×
NEW
1112
                });
×
1113
            }
1114
        };
1115
        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
57✔
1116

1117
        if element_ptr.is_null() {
57✔
NEW
1118
            return Err(ReflectError::OperationFailed {
×
NEW
1119
                shape: frame.shape,
×
NEW
1120
                operation: "failed to allocate memory for list element",
×
NEW
1121
            });
×
1122
        }
57✔
1123

1124
        // Push a new frame for the element
1125
        self.frames.push(Frame::new(
57✔
1126
            PtrUninit::new(element_ptr),
57✔
1127
            element_shape,
57✔
1128
            FrameOwnership::Owned,
57✔
1129
        ));
1130

1131
        Ok(self)
57✔
1132
    }
72✔
1133

1134
    /// Begins a map initialization operation
1135
    /// This initializes the map with default capacity and allows inserting key-value pairs
1136
    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
12✔
1137
        self.require_active()?;
12✔
1138
        let frame = self.frames.last_mut().unwrap();
12✔
1139

1140
        // Check that we have a Map
1141
        let map_def = match &frame.shape.def {
12✔
1142
            Def::Map(map_def) => map_def,
12✔
1143
            _ => {
NEW
1144
                return Err(ReflectError::OperationFailed {
×
NEW
1145
                    shape: frame.shape,
×
NEW
1146
                    operation: "begin_map can only be called on Map types",
×
NEW
1147
                });
×
1148
            }
1149
        };
1150

1151
        // Check that we have init_in_place_with_capacity function
1152
        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
12✔
1153

1154
        // Initialize the map with default capacity (0)
1155
        unsafe {
12✔
1156
            init_fn(frame.data, 0);
12✔
1157
        }
12✔
1158

1159
        // Update tracker to Map state
1160
        frame.tracker = Tracker::Map {
12✔
1161
            is_initialized: true,
12✔
1162
            insert_state: MapInsertState::Idle,
12✔
1163
        };
12✔
1164

1165
        Ok(self)
12✔
1166
    }
12✔
1167

1168
    /// Pushes a frame for the map key
1169
    /// Automatically starts a new insert if we're idle
1170
    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
13✔
1171
        self.require_active()?;
13✔
1172
        let frame = self.frames.last_mut().unwrap();
13✔
1173

1174
        // Check that we have a Map and set up for key insertion
1175
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
13✔
1176
            (
1177
                Def::Map(map_def),
13✔
1178
                Tracker::Map {
1179
                    is_initialized: true,
1180
                    insert_state,
13✔
1181
                },
1182
            ) => {
1183
                match insert_state {
13✔
1184
                    MapInsertState::Idle => {
13✔
1185
                        // Start a new insert automatically
13✔
1186
                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
13✔
1187
                    }
13✔
NEW
1188
                    MapInsertState::PushingKey { key_ptr } => {
×
NEW
1189
                        if key_ptr.is_some() {
×
NEW
1190
                            return Err(ReflectError::OperationFailed {
×
NEW
1191
                                shape: frame.shape,
×
NEW
1192
                                operation: "already pushing a key, call end() first",
×
NEW
1193
                            });
×
NEW
1194
                        }
×
1195
                    }
1196
                    _ => {
NEW
1197
                        return Err(ReflectError::OperationFailed {
×
NEW
1198
                            shape: frame.shape,
×
NEW
1199
                            operation: "must complete current operation before begin_key()",
×
NEW
1200
                        });
×
1201
                    }
1202
                }
1203
                map_def
13✔
1204
            }
1205
            _ => {
NEW
1206
                return Err(ReflectError::OperationFailed {
×
NEW
1207
                    shape: frame.shape,
×
NEW
1208
                    operation: "must call begin_map() before begin_key()",
×
NEW
1209
                });
×
1210
            }
1211
        };
1212

1213
        // Get the key shape
1214
        let key_shape = map_def.k();
13✔
1215

1216
        // Allocate space for the key
1217
        let key_layout = match key_shape.layout.sized_layout() {
13✔
1218
            Ok(layout) => layout,
13✔
1219
            Err(_) => {
NEW
1220
                return Err(ReflectError::Unsized {
×
NEW
1221
                    shape: key_shape,
×
NEW
1222
                    operation: "begin_key allocating key",
×
NEW
1223
                });
×
1224
            }
1225
        };
1226
        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
13✔
1227

1228
        if key_ptr_raw.is_null() {
13✔
NEW
1229
            return Err(ReflectError::OperationFailed {
×
NEW
1230
                shape: frame.shape,
×
NEW
1231
                operation: "failed to allocate memory for map key",
×
NEW
1232
            });
×
1233
        }
13✔
1234

1235
        // Store the key pointer in the insert state
1236
        match &mut frame.tracker {
13✔
1237
            Tracker::Map {
1238
                insert_state: MapInsertState::PushingKey { key_ptr: kp },
13✔
1239
                ..
1240
            } => {
13✔
1241
                *kp = Some(PtrUninit::new(key_ptr_raw));
13✔
1242
            }
13✔
NEW
1243
            _ => unreachable!(),
×
1244
        }
1245

1246
        // Push a new frame for the key
1247
        self.frames.push(Frame::new(
13✔
1248
            PtrUninit::new(key_ptr_raw),
13✔
1249
            key_shape,
13✔
1250
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
13✔
1251
        ));
1252

1253
        Ok(self)
13✔
1254
    }
13✔
1255

1256
    /// Pushes a frame for the map value
1257
    /// Must be called after the key has been set and popped
1258
    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
10✔
1259
        self.require_active()?;
10✔
1260
        let frame = self.frames.last_mut().unwrap();
10✔
1261

1262
        // Check that we have a Map in PushingValue state
1263
        let map_def = match (&frame.shape.def, &mut frame.tracker) {
10✔
1264
            (
1265
                Def::Map(map_def),
10✔
1266
                Tracker::Map {
1267
                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
10✔
1268
                    ..
1269
                },
1270
            ) => {
1271
                if value_ptr.is_some() {
10✔
NEW
1272
                    return Err(ReflectError::OperationFailed {
×
NEW
1273
                        shape: frame.shape,
×
NEW
1274
                        operation: "already pushing a value, call pop() first",
×
NEW
1275
                    });
×
1276
                }
10✔
1277
                map_def
10✔
1278
            }
1279
            _ => {
NEW
1280
                return Err(ReflectError::OperationFailed {
×
NEW
1281
                    shape: frame.shape,
×
NEW
1282
                    operation: "must complete key before push_value()",
×
NEW
1283
                });
×
1284
            }
1285
        };
1286

1287
        // Get the value shape
1288
        let value_shape = map_def.v();
10✔
1289

1290
        // Allocate space for the value
1291
        let value_layout = match value_shape.layout.sized_layout() {
10✔
1292
            Ok(layout) => layout,
10✔
1293
            Err(_) => {
NEW
1294
                return Err(ReflectError::Unsized {
×
NEW
1295
                    shape: value_shape,
×
NEW
1296
                    operation: "begin_value allocating value",
×
NEW
1297
                });
×
1298
            }
1299
        };
1300
        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
10✔
1301

1302
        if value_ptr_raw.is_null() {
10✔
NEW
1303
            return Err(ReflectError::OperationFailed {
×
NEW
1304
                shape: frame.shape,
×
NEW
1305
                operation: "failed to allocate memory for map value",
×
NEW
1306
            });
×
1307
        }
10✔
1308

1309
        // Store the value pointer in the insert state
1310
        match &mut frame.tracker {
10✔
1311
            Tracker::Map {
1312
                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
10✔
1313
                ..
1314
            } => {
10✔
1315
                *vp = Some(PtrUninit::new(value_ptr_raw));
10✔
1316
            }
10✔
NEW
1317
            _ => unreachable!(),
×
1318
        }
1319

1320
        // Push a new frame for the value
1321
        self.frames.push(Frame::new(
10✔
1322
            PtrUninit::new(value_ptr_raw),
10✔
1323
            value_shape,
10✔
1324
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
10✔
1325
        ));
1326

1327
        Ok(self)
10✔
1328
    }
10✔
1329

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

1335
        // Special handling for SmartPointerSlice - convert builder to Arc
1336
        if self.frames.len() == 1 {
342✔
1337
            if let Tracker::SmartPointerSlice {
1338
                vtable,
6✔
1339
                building_item,
6✔
1340
            } = &self.frames[0].tracker
6✔
1341
            {
1342
                if *building_item {
6✔
NEW
1343
                    return Err(ReflectError::OperationFailed {
×
NEW
1344
                        shape: self.frames[0].shape,
×
NEW
1345
                        operation: "still building an item, finish it first",
×
NEW
1346
                    });
×
1347
                }
6✔
1348

1349
                // Convert the builder to Arc<[T]>
1350
                let builder_ptr = unsafe { self.frames[0].data.assume_init() };
6✔
1351
                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
6✔
1352

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

1359
                return Ok(self);
6✔
NEW
1360
            }
×
1361
        }
336✔
1362

1363
        if self.frames.len() <= 1 {
336✔
1364
            // Never pop the last/root frame.
NEW
1365
            return Err(ReflectError::InvariantViolation {
×
NEW
1366
                invariant: "Partial::end() called with only one frame on the stack",
×
NEW
1367
            });
×
1368
        }
336✔
1369

1370
        // Require that the top frame is fully initialized before popping.
1371
        {
1372
            let frame = self.frames.last().unwrap();
336✔
1373
            trace!(
1374
                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
1375
                frame.shape,
1376
                frame.tracker.kind()
1377
            );
1378
            frame.require_full_initialization()?
336✔
1379
        }
1380

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

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

1387
        trace!(
1388
            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
1389
            popped_frame.shape,
1390
            popped_frame.tracker.kind(),
1391
            parent_frame.shape,
1392
            parent_frame.tracker.kind()
1393
        );
1394

1395
        // Check if we need to do a conversion - this happens when:
1396
        // 1. The parent frame has an inner type that matches the popped frame's shape
1397
        // 2. The parent frame has try_from
1398
        // 3. The parent frame is not yet initialized
1399
        let needs_conversion = matches!(parent_frame.tracker, Tracker::Uninit)
334✔
1400
            && parent_frame.shape.inner.is_some()
4✔
1401
            && parent_frame.shape.inner.unwrap()() == popped_frame.shape
4✔
NEW
1402
            && parent_frame
×
NEW
1403
                .shape
×
NEW
1404
                .vtable
×
NEW
1405
                .sized()
×
NEW
1406
                .and_then(|v| (v.try_from)())
×
NEW
1407
                .is_some();
×
1408

1409
        if needs_conversion {
334✔
1410
            trace!(
1411
                "Detected implicit conversion needed from {} to {}",
1412
                popped_frame.shape, parent_frame.shape
1413
            );
1414
            // Perform the conversion
NEW
1415
            if let Some(try_from_fn) = parent_frame
×
NEW
1416
                .shape
×
NEW
1417
                .vtable
×
NEW
1418
                .sized()
×
NEW
1419
                .and_then(|v| (v.try_from)())
×
1420
            {
NEW
1421
                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
×
NEW
1422
                let inner_shape = popped_frame.shape;
×
1423

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

NEW
1427
                if let Err(e) = result {
×
1428
                    trace!("Conversion failed: {e:?}");
1429

1430
                    // Deallocate the inner value's memory since conversion failed
NEW
1431
                    if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
1432
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
1433
                            if layout.size() > 0 {
×
1434
                                trace!(
1435
                                    "Deallocating conversion frame memory after failure: size={}, align={}",
1436
                                    layout.size(),
1437
                                    layout.align()
1438
                                );
NEW
1439
                                unsafe {
×
NEW
1440
                                    alloc::alloc::dealloc(
×
NEW
1441
                                        popped_frame.data.as_mut_byte_ptr(),
×
NEW
1442
                                        layout,
×
NEW
1443
                                    );
×
NEW
1444
                                }
×
NEW
1445
                            }
×
NEW
1446
                        }
×
NEW
1447
                    }
×
1448

NEW
1449
                    return Err(ReflectError::TryFromError {
×
NEW
1450
                        src_shape: inner_shape,
×
NEW
1451
                        dst_shape: parent_frame.shape,
×
NEW
1452
                        inner: e,
×
NEW
1453
                    });
×
NEW
1454
                }
×
1455

1456
                trace!("Conversion succeeded, marking parent as initialized");
NEW
1457
                parent_frame.tracker = Tracker::Init;
×
1458

1459
                // Deallocate the inner value's memory since try_from consumed it
NEW
1460
                if let FrameOwnership::Owned = popped_frame.ownership {
×
NEW
1461
                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
×
NEW
1462
                        if layout.size() > 0 {
×
1463
                            trace!(
1464
                                "Deallocating conversion frame memory: size={}, align={}",
1465
                                layout.size(),
1466
                                layout.align()
1467
                            );
NEW
1468
                            unsafe {
×
NEW
1469
                                alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
×
NEW
1470
                            }
×
NEW
1471
                        }
×
NEW
1472
                    }
×
NEW
1473
                }
×
1474

NEW
1475
                return Ok(self);
×
NEW
1476
            }
×
1477
        }
334✔
1478

1479
        match &mut parent_frame.tracker {
334✔
1480
            Tracker::Struct {
1481
                iset,
158✔
1482
                current_child,
158✔
1483
            } => {
1484
                if let Some(idx) = *current_child {
158✔
1485
                    iset.set(idx);
158✔
1486
                    *current_child = None;
158✔
1487
                }
158✔
1488
            }
1489
            Tracker::Array {
1490
                iset,
37✔
1491
                current_child,
37✔
1492
            } => {
1493
                if let Some(idx) = *current_child {
37✔
1494
                    iset.set(idx);
37✔
1495
                    *current_child = None;
37✔
1496
                }
37✔
1497
            }
1498
            Tracker::SmartPointer { is_initialized } => {
7✔
1499
                // We just popped the inner value frame, so now we need to create the smart pointer
1500
                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
7✔
1501
                    if let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn {
7✔
1502
                        // The child frame contained the inner value
1503
                        let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
7✔
1504

1505
                        // Use new_into_fn to create the Box
1506
                        unsafe {
7✔
1507
                            new_into_fn(parent_frame.data, inner_ptr);
7✔
1508
                        }
7✔
1509

1510
                        // Deallocate the inner value's memory since new_into_fn moved it
1511
                        if let FrameOwnership::Owned = popped_frame.ownership {
7✔
1512
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
7✔
1513
                                if layout.size() > 0 {
7✔
1514
                                    unsafe {
7✔
1515
                                        alloc::alloc::dealloc(
7✔
1516
                                            popped_frame.data.as_mut_byte_ptr(),
7✔
1517
                                            layout,
7✔
1518
                                        );
7✔
1519
                                    }
7✔
NEW
1520
                                }
×
NEW
1521
                            }
×
NEW
1522
                        }
×
1523

1524
                        *is_initialized = true;
7✔
1525
                    } else {
NEW
1526
                        return Err(ReflectError::OperationFailed {
×
NEW
1527
                            shape: parent_frame.shape,
×
NEW
1528
                            operation: "SmartPointer missing new_into_fn",
×
NEW
1529
                        });
×
1530
                    }
NEW
1531
                }
×
1532
            }
1533
            Tracker::Enum {
1534
                data,
42✔
1535
                current_child,
42✔
1536
                ..
1537
            } => {
1538
                if let Some(idx) = *current_child {
42✔
1539
                    data.set(idx);
42✔
1540
                    *current_child = None;
42✔
1541
                }
42✔
1542
            }
1543
            Tracker::List {
1544
                is_initialized: true,
1545
                current_child,
51✔
1546
            } => {
1547
                if *current_child {
51✔
1548
                    // We just popped an element frame, now push it to the list
1549
                    if let Def::List(list_def) = parent_frame.shape.def {
51✔
1550
                        if let Some(push_fn) = list_def.vtable.push {
51✔
1551
                            // The child frame contained the element value
1552
                            let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
51✔
1553

1554
                            // Use push to add element to the list
1555
                            unsafe {
51✔
1556
                                push_fn(
51✔
1557
                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
51✔
1558
                                    element_ptr,
51✔
1559
                                );
51✔
1560
                            }
51✔
1561

1562
                            // Deallocate the element's memory since push moved it
1563
                            if let FrameOwnership::Owned = popped_frame.ownership {
51✔
1564
                                if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
51✔
1565
                                    if layout.size() > 0 {
51✔
1566
                                        unsafe {
51✔
1567
                                            alloc::alloc::dealloc(
51✔
1568
                                                popped_frame.data.as_mut_byte_ptr(),
51✔
1569
                                                layout,
51✔
1570
                                            );
51✔
1571
                                        }
51✔
NEW
1572
                                    }
×
NEW
1573
                                }
×
NEW
1574
                            }
×
1575

1576
                            *current_child = false;
51✔
1577
                        } else {
NEW
1578
                            return Err(ReflectError::OperationFailed {
×
NEW
1579
                                shape: parent_frame.shape,
×
NEW
1580
                                operation: "List missing push function",
×
NEW
1581
                            });
×
1582
                        }
NEW
1583
                    }
×
NEW
1584
                }
×
1585
            }
1586
            Tracker::Map {
1587
                is_initialized: true,
1588
                insert_state,
19✔
1589
            } => {
1590
                match insert_state {
19✔
1591
                    MapInsertState::PushingKey { key_ptr } => {
11✔
1592
                        // We just popped the key frame
1593
                        if let Some(key_ptr) = key_ptr {
11✔
1594
                            // Transition to PushingValue state
11✔
1595
                            *insert_state = MapInsertState::PushingValue {
11✔
1596
                                key_ptr: *key_ptr,
11✔
1597
                                value_ptr: None,
11✔
1598
                            };
11✔
1599
                        }
11✔
1600
                    }
1601
                    MapInsertState::PushingValue { key_ptr, value_ptr } => {
8✔
1602
                        // We just popped the value frame, now insert the pair
1603
                        if let (Some(value_ptr), Def::Map(map_def)) =
8✔
1604
                            (value_ptr, parent_frame.shape.def)
8✔
1605
                        {
1606
                            let insert_fn = map_def.vtable.insert_fn;
8✔
1607

1608
                            // Use insert to add key-value pair to the map
1609
                            unsafe {
8✔
1610
                                insert_fn(
8✔
1611
                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
8✔
1612
                                    PtrMut::new(key_ptr.as_mut_byte_ptr()),
8✔
1613
                                    PtrMut::new(value_ptr.as_mut_byte_ptr()),
8✔
1614
                                );
8✔
1615
                            }
8✔
1616

1617
                            // Note: We don't deallocate the key and value memory here.
1618
                            // The insert function has semantically moved the values into the map,
1619
                            // but we still need to deallocate the temporary buffers.
1620
                            // However, since we don't have frames for them anymore (they were popped),
1621
                            // we need to handle deallocation here.
1622
                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
8✔
1623
                                if key_shape.size() > 0 {
8✔
1624
                                    unsafe {
8✔
1625
                                        alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
8✔
1626
                                    }
8✔
NEW
1627
                                }
×
NEW
1628
                            }
×
1629
                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
8✔
1630
                                if value_shape.size() > 0 {
8✔
1631
                                    unsafe {
8✔
1632
                                        alloc::alloc::dealloc(
8✔
1633
                                            value_ptr.as_mut_byte_ptr(),
8✔
1634
                                            value_shape,
8✔
1635
                                        );
8✔
1636
                                    }
8✔
NEW
1637
                                }
×
NEW
1638
                            }
×
1639

1640
                            // Reset to idle state
1641
                            *insert_state = MapInsertState::Idle;
8✔
NEW
1642
                        }
×
1643
                    }
NEW
1644
                    MapInsertState::Idle => {
×
NEW
1645
                        // Nothing to do
×
NEW
1646
                    }
×
1647
                }
1648
            }
1649
            Tracker::Option { building_inner } => {
1✔
1650
                // We just popped the inner value frame for an Option's Some variant
1651
                if *building_inner {
1✔
1652
                    if let Def::Option(option_def) = parent_frame.shape.def {
1✔
1653
                        // Use the Option vtable to initialize Some(inner_value)
1654
                        let init_some_fn = option_def.vtable.init_some_fn;
1✔
1655

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

1659
                        // Initialize the Option as Some(inner_value)
1660
                        unsafe {
1✔
1661
                            init_some_fn(parent_frame.data, inner_value_ptr);
1✔
1662
                        }
1✔
1663

1664
                        // Deallocate the inner value's memory since init_some_fn moved it
1665
                        if let FrameOwnership::Owned = popped_frame.ownership {
1✔
1666
                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
1✔
1667
                                if layout.size() > 0 {
1✔
1668
                                    unsafe {
1✔
1669
                                        alloc::alloc::dealloc(
1✔
1670
                                            popped_frame.data.as_mut_byte_ptr(),
1✔
1671
                                            layout,
1✔
1672
                                        );
1✔
1673
                                    }
1✔
NEW
1674
                                }
×
NEW
1675
                            }
×
NEW
1676
                        }
×
1677

1678
                        // Mark that we're no longer building the inner value
1679
                        *building_inner = false;
1✔
1680
                    } else {
NEW
1681
                        return Err(ReflectError::OperationFailed {
×
NEW
1682
                            shape: parent_frame.shape,
×
NEW
1683
                            operation: "Option frame without Option definition",
×
NEW
1684
                        });
×
1685
                    }
NEW
1686
                }
×
1687
            }
1688
            Tracker::Uninit | Tracker::Init => {
1689
                // the main case here is: the popped frame was a `String` and the
1690
                // parent frame is an `Arc<str>`, `Box<str>` etc.
1691
                match &parent_frame.shape.def {
5✔
1692
                    Def::Pointer(smart_ptr_def) => {
5✔
1693
                        let pointee =
5✔
1694
                            smart_ptr_def
5✔
1695
                                .pointee()
5✔
1696
                                .ok_or(ReflectError::InvariantViolation {
5✔
1697
                                    invariant: "pointer type doesn't have a pointee",
5✔
1698
                                })?;
5✔
1699

1700
                        if !pointee.is_shape(str::SHAPE) {
5✔
NEW
1701
                            return Err(ReflectError::InvariantViolation {
×
NEW
1702
                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
×
NEW
1703
                            });
×
1704
                        }
5✔
1705

1706
                        if !popped_frame.shape.is_shape(String::SHAPE) {
5✔
NEW
1707
                            return Err(ReflectError::InvariantViolation {
×
NEW
1708
                                invariant: "the popped frame should be String when building a SmartPointer<T>",
×
NEW
1709
                            });
×
1710
                        }
5✔
1711

1712
                        popped_frame.require_full_initialization()?;
5✔
1713

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

1721
                        let Some(known) = smart_ptr_def.known else {
5✔
NEW
1722
                            return Err(ReflectError::OperationFailed {
×
NEW
1723
                                shape: parent_shape,
×
NEW
1724
                                operation: "SmartPointerStr for unknown smart pointer kind",
×
NEW
1725
                            });
×
1726
                        };
1727

1728
                        parent_frame.deinit();
5✔
1729

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

1734
                        match known {
5✔
1735
                            KnownPointer::Box => {
1736
                                let boxed: Box<str> = string_value.into_boxed_str();
1✔
1737
                                unsafe {
1✔
1738
                                    core::ptr::write(
1✔
1739
                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1✔
1740
                                        boxed,
1✔
1741
                                    );
1✔
1742
                                }
1✔
1743
                            }
1744
                            KnownPointer::Arc => {
1745
                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1✔
1746
                                unsafe {
1✔
1747
                                    core::ptr::write(
1✔
1748
                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1✔
1749
                                        arc,
1✔
1750
                                    );
1✔
1751
                                }
1✔
1752
                            }
1753
                            KnownPointer::Rc => {
1754
                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
3✔
1755
                                unsafe {
3✔
1756
                                    core::ptr::write(
3✔
1757
                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
3✔
1758
                                        rc,
3✔
1759
                                    );
3✔
1760
                                }
3✔
1761
                            }
1762
                            _ => {
NEW
1763
                                return Err(ReflectError::OperationFailed {
×
NEW
1764
                                    shape: parent_shape,
×
NEW
1765
                                    operation: "Don't know how to build this pointer type",
×
NEW
1766
                                });
×
1767
                            }
1768
                        }
1769

1770
                        parent_frame.tracker = Tracker::Init;
5✔
1771

1772
                        popped_frame.tracker = Tracker::Uninit;
5✔
1773
                        popped_frame.dealloc();
5✔
1774
                    }
1775
                    _ => {
NEW
1776
                        unreachable!(
×
1777
                            "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"
1778
                        )
1779
                    }
1780
                }
1781
            }
1782
            Tracker::SmartPointerSlice {
1783
                vtable,
14✔
1784
                building_item,
14✔
1785
            } => {
1786
                if *building_item {
14✔
1787
                    // We just popped an element frame, now push it to the slice builder
1788
                    let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
14✔
1789

1790
                    // Use the slice builder's push_fn to add the element
1791
                    crate::trace!("Pushing element to slice builder");
1792
                    unsafe {
14✔
1793
                        let parent_ptr = parent_frame.data.assume_init();
14✔
1794
                        (vtable.push_fn)(parent_ptr, element_ptr);
14✔
1795
                    }
14✔
1796

1797
                    // Deallocate the element's memory since push_fn moved it
1798
                    if let FrameOwnership::Owned = popped_frame.ownership {
14✔
1799
                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
14✔
1800
                            if layout.size() > 0 {
14✔
1801
                                unsafe {
14✔
1802
                                    alloc::alloc::dealloc(
14✔
1803
                                        popped_frame.data.as_mut_byte_ptr(),
14✔
1804
                                        layout,
14✔
1805
                                    );
14✔
1806
                                }
14✔
NEW
1807
                            }
×
NEW
1808
                        }
×
NEW
1809
                    }
×
1810

1811
                    if let Tracker::SmartPointerSlice {
1812
                        building_item: bi, ..
14✔
1813
                    } = &mut parent_frame.tracker
14✔
1814
                    {
14✔
1815
                        *bi = false;
14✔
1816
                    }
14✔
NEW
1817
                }
×
1818
            }
NEW
1819
            _ => {}
×
1820
        }
1821

1822
        Ok(self)
334✔
1823
    }
342✔
1824

1825
    /// Builds the value
1826
    pub fn build(&mut self) -> Result<HeapValue<'facet>, ReflectError> {
159✔
1827
        self.require_active()?;
159✔
1828
        if self.frames.len() != 1 {
158✔
1829
            self.state = PartialState::BuildFailed;
2✔
1830
            return Err(ReflectError::InvariantViolation {
2✔
1831
                invariant: "Partial::build() expects a single frame — call end() until that's the case",
2✔
1832
            });
2✔
1833
        }
156✔
1834

1835
        let frame = self.frames.pop().unwrap();
156✔
1836

1837
        // Check initialization before proceeding
1838
        if let Err(e) = frame.require_full_initialization() {
156✔
1839
            // Put the frame back so Drop can handle cleanup properly
1840
            self.frames.push(frame);
26✔
1841
            self.state = PartialState::BuildFailed;
26✔
1842
            return Err(e);
26✔
1843
        }
130✔
1844

1845
        // Check invariants if present
1846
        if let Some(invariants_fn) = frame.shape.vtable.sized().and_then(|v| (v.invariants)()) {
130✔
1847
            // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
1848
            let value_ptr = unsafe { frame.data.assume_init().as_const() };
6✔
1849
            let invariants_ok = unsafe { invariants_fn(value_ptr) };
6✔
1850

1851
            if !invariants_ok {
6✔
1852
                // Put the frame back so Drop can handle cleanup properly
1853
                self.frames.push(frame);
3✔
1854
                self.state = PartialState::BuildFailed;
3✔
1855
                return Err(ReflectError::InvariantViolation {
3✔
1856
                    invariant: "Type invariants check failed",
3✔
1857
                });
3✔
1858
            }
3✔
1859
        }
124✔
1860

1861
        // Mark as built to prevent reuse
1862
        self.state = PartialState::Built;
127✔
1863

1864
        match frame
127✔
1865
            .shape
127✔
1866
            .layout
127✔
1867
            .sized_layout()
127✔
1868
            .map_err(|_layout_err| ReflectError::Unsized {
127✔
NEW
1869
                shape: frame.shape,
×
1870
                operation: "build (final check for sized layout)",
NEW
1871
            }) {
×
1872
            Ok(layout) => Ok(HeapValue {
127✔
1873
                guard: Some(Guard {
127✔
1874
                    ptr: frame.data.as_mut_byte_ptr(),
127✔
1875
                    layout,
127✔
1876
                }),
127✔
1877
                shape: frame.shape,
127✔
1878
                phantom: PhantomData,
127✔
1879
            }),
127✔
NEW
1880
            Err(e) => {
×
1881
                // Put the frame back for proper cleanup
NEW
1882
                self.frames.push(frame);
×
NEW
1883
                self.state = PartialState::BuildFailed;
×
NEW
1884
                Err(e)
×
1885
            }
1886
        }
1887
    }
159✔
1888

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

NEW
1894
        let mut path_components = Vec::new();
×
1895
        // The stack of enum/struct/sequence names currently in context.
1896
        // Start from root and build upwards.
NEW
1897
        for (i, frame) in self.frames.iter().enumerate() {
×
NEW
1898
            match frame.shape.ty {
×
NEW
1899
                Type::User(user_type) => match user_type {
×
NEW
1900
                    UserType::Struct(struct_type) => {
×
1901
                        // Try to get currently active field index
NEW
1902
                        let mut field_str = None;
×
1903
                        if let Tracker::Struct {
NEW
1904
                            current_child: Some(idx),
×
1905
                            ..
NEW
1906
                        } = &frame.tracker
×
1907
                        {
NEW
1908
                            if let Some(field) = struct_type.fields.get(*idx) {
×
NEW
1909
                                field_str = Some(field.name);
×
NEW
1910
                            }
×
NEW
1911
                        }
×
NEW
1912
                        if i == 0 {
×
NEW
1913
                            // Use Display for the root struct shape
×
NEW
1914
                            path_components.push(format!("{}", frame.shape));
×
NEW
1915
                        }
×
NEW
1916
                        if let Some(field_name) = field_str {
×
NEW
1917
                            path_components.push(format!(".{field_name}"));
×
NEW
1918
                        }
×
1919
                    }
NEW
1920
                    UserType::Enum(_enum_type) => {
×
1921
                        // Try to get currently active variant and field
1922
                        if let Tracker::Enum {
NEW
1923
                            variant,
×
NEW
1924
                            current_child,
×
1925
                            ..
NEW
1926
                        } = &frame.tracker
×
1927
                        {
NEW
1928
                            if i == 0 {
×
NEW
1929
                                // Use Display for the root enum shape
×
NEW
1930
                                path_components.push(format!("{}", frame.shape));
×
NEW
1931
                            }
×
NEW
1932
                            path_components.push(format!("::{}", variant.name));
×
NEW
1933
                            if let Some(idx) = *current_child {
×
NEW
1934
                                if let Some(field) = variant.data.fields.get(idx) {
×
NEW
1935
                                    path_components.push(format!(".{}", field.name));
×
NEW
1936
                                }
×
NEW
1937
                            }
×
NEW
1938
                        } else if i == 0 {
×
NEW
1939
                            // just the enum display
×
NEW
1940
                            path_components.push(format!("{}", frame.shape));
×
NEW
1941
                        }
×
1942
                    }
NEW
1943
                    UserType::Union(_union_type) => {
×
NEW
1944
                        path_components.push(format!("{}", frame.shape));
×
NEW
1945
                    }
×
NEW
1946
                    UserType::Opaque => {
×
NEW
1947
                        path_components.push("<opaque>".to_string());
×
NEW
1948
                    }
×
1949
                },
NEW
1950
                Type::Sequence(seq_type) => match seq_type {
×
NEW
1951
                    facet_core::SequenceType::Array(_array_def) => {
×
1952
                        // Try to show current element index
1953
                        if let Tracker::Array {
NEW
1954
                            current_child: Some(idx),
×
1955
                            ..
NEW
1956
                        } = &frame.tracker
×
NEW
1957
                        {
×
NEW
1958
                            path_components.push(format!("[{idx}]"));
×
NEW
1959
                        }
×
1960
                    }
1961
                    // You can add more for Slice, Vec, etc., if applicable
NEW
1962
                    _ => {
×
NEW
1963
                        // just indicate "[]" for sequence
×
NEW
1964
                        path_components.push("[]".to_string());
×
NEW
1965
                    }
×
1966
                },
NEW
1967
                Type::Pointer(_) => {
×
NEW
1968
                    // Indicate deref
×
NEW
1969
                    path_components.push("*".to_string());
×
NEW
1970
                }
×
NEW
1971
                _ => {
×
NEW
1972
                    // No structural path
×
NEW
1973
                }
×
1974
            }
1975
        }
1976
        // Merge the path_components into a single string
NEW
1977
        for component in path_components {
×
NEW
1978
            out.push_str(&component);
×
NEW
1979
        }
×
NEW
1980
        out
×
NEW
1981
    }
×
1982

1983
    /// Returns the shape of the current frame.
1984
    #[inline]
1985
    pub fn shape(&self) -> &'static Shape {
7✔
1986
        self.frames
7✔
1987
            .last()
7✔
1988
            .expect("Partial always has at least one frame")
7✔
1989
            .shape
7✔
1990
    }
7✔
1991

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

1996
        match &frame.tracker {
12✔
1997
            Tracker::Uninit => Ok(false),
12✔
NEW
1998
            Tracker::Init => Ok(true),
×
NEW
1999
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
×
NEW
2000
            Tracker::Enum { data, .. } => {
×
2001
                // Check if the field is already marked as set
NEW
2002
                if data.get(index) {
×
NEW
2003
                    return Ok(true);
×
NEW
2004
                }
×
2005

2006
                // For enum variant fields that are empty structs, they are always initialized
NEW
2007
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
NEW
2008
                    if let Some(field) = variant.data.fields.get(index) {
×
NEW
2009
                        if let Type::User(UserType::Struct(field_struct)) = field.shape.ty {
×
NEW
2010
                            if field_struct.fields.is_empty() {
×
NEW
2011
                                return Ok(true);
×
NEW
2012
                            }
×
NEW
2013
                        }
×
NEW
2014
                    }
×
NEW
2015
                }
×
2016

NEW
2017
                Ok(false)
×
2018
            }
NEW
2019
            Tracker::Option { building_inner } => {
×
2020
                // For Options, index 0 represents the inner value
NEW
2021
                if index == 0 {
×
NEW
2022
                    Ok(!building_inner)
×
2023
                } else {
NEW
2024
                    Err(ReflectError::InvalidOperation {
×
NEW
2025
                        operation: "is_field_set",
×
NEW
2026
                        reason: "Option only has one field (index 0)",
×
NEW
2027
                    })
×
2028
                }
2029
            }
NEW
2030
            _ => Err(ReflectError::InvalidOperation {
×
NEW
2031
                operation: "is_field_set",
×
NEW
2032
                reason: "Current frame is not a struct, enum variant, or option",
×
NEW
2033
            }),
×
2034
        }
2035
    }
12✔
2036

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

NEW
2041
        match frame.shape.ty {
×
NEW
2042
            Type::User(UserType::Struct(struct_def)) => {
×
NEW
2043
                struct_def.fields.iter().position(|f| f.name == field_name)
×
2044
            }
2045
            Type::User(UserType::Enum(_)) => {
2046
                // If we're in an enum variant, check its fields
NEW
2047
                if let Tracker::Enum { variant, .. } = &frame.tracker {
×
NEW
2048
                    variant
×
NEW
2049
                        .data
×
NEW
2050
                        .fields
×
NEW
2051
                        .iter()
×
NEW
2052
                        .position(|f| f.name == field_name)
×
2053
                } else {
NEW
2054
                    None
×
2055
                }
2056
            }
NEW
2057
            _ => None,
×
2058
        }
NEW
2059
    }
×
2060

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

NEW
2065
        match &frame.tracker {
×
NEW
2066
            Tracker::Enum { variant, .. } => Some(**variant),
×
NEW
2067
            _ => None,
×
2068
        }
NEW
2069
    }
×
2070

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

NEW
2075
        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
×
NEW
2076
            enum_def
×
NEW
2077
                .variants
×
NEW
2078
                .iter()
×
NEW
2079
                .enumerate()
×
NEW
2080
                .find(|(_, v)| v.name == variant_name)
×
2081
        } else {
NEW
2082
            None
×
2083
        }
NEW
2084
    }
×
2085

2086
    /// Begin building the Some variant of an Option
2087
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1✔
2088
        self.require_active()?;
1✔
2089
        let frame = self.frames.last_mut().unwrap();
1✔
2090

2091
        // Verify we're working with an Option
2092
        let option_def = match frame.shape.def {
1✔
2093
            Def::Option(def) => def,
1✔
2094
            _ => {
NEW
2095
                return Err(ReflectError::WasNotA {
×
NEW
2096
                    expected: "Option",
×
NEW
2097
                    actual: frame.shape,
×
NEW
2098
                });
×
2099
            }
2100
        };
2101

2102
        // Initialize the tracker for Option building
2103
        if matches!(frame.tracker, Tracker::Uninit) {
1✔
2104
            frame.tracker = Tracker::Option {
1✔
2105
                building_inner: true,
1✔
2106
            };
1✔
2107
        }
1✔
2108

2109
        // Get the inner type shape
2110
        let inner_shape = option_def.t;
1✔
2111

2112
        // Allocate memory for the inner value
2113
        let inner_layout =
1✔
2114
            inner_shape
1✔
2115
                .layout
1✔
2116
                .sized_layout()
1✔
2117
                .map_err(|_| ReflectError::Unsized {
1✔
NEW
2118
                    shape: inner_shape,
×
2119
                    operation: "begin_some, allocating Option inner value",
NEW
2120
                })?;
×
2121

2122
        let inner_data = if inner_layout.size() == 0 {
1✔
2123
            // For ZST, use a non-null but unallocated pointer
NEW
2124
            PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
2125
        } else {
2126
            // Allocate memory for the inner value
2127
            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1✔
2128
            if ptr.is_null() {
1✔
NEW
2129
                alloc::alloc::handle_alloc_error(inner_layout);
×
2130
            }
1✔
2131
            PtrUninit::new(ptr)
1✔
2132
        };
2133

2134
        // Create a new frame for the inner value
2135
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1✔
2136
        self.frames.push(inner_frame);
1✔
2137

2138
        Ok(self)
1✔
2139
    }
1✔
2140

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

2145
        // Get the inner shape and check for try_from
NEW
2146
        let (inner_shape, has_try_from, parent_shape) = {
×
NEW
2147
            let frame = self.frames.last().unwrap();
×
NEW
2148
            if let Some(inner_fn) = frame.shape.inner {
×
NEW
2149
                let inner_shape = inner_fn();
×
NEW
2150
                let has_try_from = frame
×
NEW
2151
                    .shape
×
NEW
2152
                    .vtable
×
NEW
2153
                    .sized()
×
NEW
2154
                    .and_then(|v| (v.try_from)())
×
NEW
2155
                    .is_some();
×
NEW
2156
                (Some(inner_shape), has_try_from, frame.shape)
×
2157
            } else {
NEW
2158
                (None, false, frame.shape)
×
2159
            }
2160
        };
2161

NEW
2162
        if let Some(inner_shape) = inner_shape {
×
NEW
2163
            if has_try_from {
×
2164
                // Create a conversion frame with the inner shape
2165

2166
                // For conversion frames, we leave the parent tracker unchanged
2167
                // This allows automatic conversion detection to work properly
2168

2169
                // Allocate memory for the inner value (conversion source)
NEW
2170
                let inner_layout =
×
NEW
2171
                    inner_shape
×
NEW
2172
                        .layout
×
NEW
2173
                        .sized_layout()
×
NEW
2174
                        .map_err(|_| ReflectError::Unsized {
×
NEW
2175
                            shape: inner_shape,
×
2176
                            operation: "begin_inner, getting inner layout",
NEW
2177
                        })?;
×
2178

NEW
2179
                let inner_data = if inner_layout.size() == 0 {
×
2180
                    // For ZST, use a non-null but unallocated pointer
NEW
2181
                    PtrUninit::new(core::ptr::NonNull::<u8>::dangling().as_ptr())
×
2182
                } else {
2183
                    // Allocate memory for the inner value
NEW
2184
                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
×
NEW
2185
                    if ptr.is_null() {
×
NEW
2186
                        alloc::alloc::handle_alloc_error(inner_layout);
×
NEW
2187
                    }
×
NEW
2188
                    PtrUninit::new(ptr)
×
2189
                };
2190

2191
                // For conversion frames, we create a frame directly with the inner shape
2192
                // This allows setting values of the inner type which will be converted
2193
                // The automatic conversion detection in end() will handle the conversion
2194
                trace!(
2195
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
2196
                );
NEW
2197
                self.frames
×
NEW
2198
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
×
2199

NEW
2200
                Ok(self)
×
2201
            } else {
2202
                // For wrapper types without try_from, navigate to the first field
2203
                // This is a common pattern for newtype wrappers
2204
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
NEW
2205
                self.begin_nth_field(0)
×
2206
            }
2207
        } else {
NEW
2208
            Err(ReflectError::OperationFailed {
×
NEW
2209
                shape: parent_shape,
×
NEW
2210
                operation: "type does not have an inner value",
×
NEW
2211
            })
×
2212
        }
NEW
2213
    }
×
2214

2215
    /// Copy a value from a Peek into the current position (safe alternative to set_shape)
2216
    ///
2217
    /// # Invariants
2218
    ///
2219
    /// `peek` must be a thin pointer, otherwise this panics.
NEW
2220
    pub fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
NEW
2221
        self.require_active()?;
×
2222

2223
        // Get the source value's pointer and shape
NEW
2224
        let src_ptr = peek
×
NEW
2225
            .data()
×
NEW
2226
            .thin()
×
NEW
2227
            .expect("set_from_peek requires thin pointers");
×
NEW
2228
        let src_shape = peek.shape();
×
2229

2230
        // Safety: This is a safe wrapper around set_shape
2231
        // The peek guarantees the source data is valid for its shape
NEW
2232
        unsafe { self.set_shape(src_ptr, src_shape) }
×
NEW
2233
    }
×
2234

2235
    /// Convenience shortcut: sets the nth element of an array directly to value, popping after.
2236
    pub fn set_nth_element<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
34✔
2237
    where
34✔
2238
        U: Facet<'facet>,
34✔
2239
    {
2240
        self.begin_nth_element(idx)?.set(value)?.end()
34✔
2241
    }
34✔
2242

2243
    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
2244
    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
9✔
2245
    where
9✔
2246
        U: Facet<'facet>,
9✔
2247
    {
2248
        self.begin_nth_field(idx)?.set(value)?.end()
9✔
2249
    }
9✔
2250

2251
    /// Convenience shortcut: sets the named field to value, popping after.
2252
    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
70✔
2253
    where
70✔
2254
        U: Facet<'facet>,
70✔
2255
    {
2256
        self.begin_field(field_name)?.set(value)?.end()
70✔
2257
    }
70✔
2258

2259
    /// Convenience shortcut: sets the nth field of an enum variant directly to value, popping after.
2260
    pub fn set_nth_enum_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
2✔
2261
    where
2✔
2262
        U: Facet<'facet>,
2✔
2263
    {
2264
        self.begin_nth_enum_field(idx)?.set(value)?.end()
2✔
2265
    }
2✔
2266

2267
    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
2268
    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2✔
2269
    where
2✔
2270
        U: Facet<'facet>,
2✔
2271
    {
2272
        self.begin_key()?.set(value)?.end()
2✔
2273
    }
2✔
2274

2275
    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
NEW
2276
    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
×
NEW
2277
    where
×
NEW
2278
        U: Facet<'facet>,
×
2279
    {
NEW
2280
        self.begin_value()?.set(value)?.end()
×
NEW
2281
    }
×
2282

2283
    /// Shorthand for: begin_list_item(), set, end
2284
    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
27✔
2285
    where
27✔
2286
        U: Facet<'facet>,
27✔
2287
    {
2288
        self.begin_list_item()?.set(value)?.end()
27✔
2289
    }
27✔
2290
}
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