facet_reflect/partial/
partial_api.rs

1// This module contains the public-facing API for `Partial`
2
3use alloc::{
4    boxed::Box,
5    format,
6    string::{String, ToString},
7    vec::Vec,
8};
9
10use core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
11
12use crate::{
13    Guard, HeapValue, Partial, Peek, ReflectError, TypedPartial,
14    partial::{Frame, FrameOwnership, MapInsertState, PartialState, Tracker, iset::ISet},
15    trace,
16};
17use facet_core::{
18    ArrayType, Characteristic, Def, EnumRepr, EnumType, Facet, Field, KnownPointer, PtrConst,
19    PtrMut, PtrUninit, SequenceType, Shape, StructType, Type, UserType, Variant,
20};
21
22////////////////////////////////////////////////////////////////////////////////////////////////////
23// Allocation, constructors etc.
24////////////////////////////////////////////////////////////////////////////////////////////////////
25impl<'facet> Partial<'facet> {
26    /// Allocates a new [TypedPartial] instance on the heap, with the given shape and type
27    pub fn alloc<T>() -> Result<TypedPartial<'facet, T>, ReflectError>
28    where
29        T: Facet<'facet> + ?Sized,
30    {
31        Ok(TypedPartial {
32            inner: Self::alloc_shape(T::SHAPE)?,
33            phantom: PhantomData,
34        })
35    }
36
37    /// Allocates a new [Partial] instance on the heap, with the given shape.
38    pub fn alloc_shape(shape: &'static Shape) -> Result<Self, ReflectError> {
39        crate::trace!(
40            "alloc_shape({:?}), with layout {:?}",
41            shape,
42            shape.layout.sized_layout()
43        );
44
45        let data = shape.allocate().map_err(|_| ReflectError::Unsized {
46            shape,
47            operation: "alloc_shape",
48        })?;
49
50        // Preallocate a couple of frames. The cost of allocating 4 frames is
51        // basically identical to allocating 1 frame, so for every type that
52        // has at least 1 level of nesting, this saves at least one guaranteed reallocation.
53        let mut frames = Vec::with_capacity(4);
54        frames.push(Frame::new(data, shape, FrameOwnership::Owned));
55
56        Ok(Self {
57            frames,
58            state: PartialState::Active,
59            invariant: PhantomData,
60        })
61    }
62}
63
64////////////////////////////////////////////////////////////////////////////////////////////////////
65// Misc.
66////////////////////////////////////////////////////////////////////////////////////////////////////
67impl<'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 {
78        self.frames.len()
79    }
80
81    /// Returns the shape of the current frame.
82    #[inline]
83    pub fn shape(&self) -> &'static Shape {
84        self.frames
85            .last()
86            .expect("Partial always has at least one frame")
87            .shape
88    }
89
90    /// Pops the current frame off the stack, indicating we're done initializing the current field
91    pub fn end(&mut self) -> Result<&mut Self, ReflectError> {
92        crate::trace!("end() called");
93        self.require_active()?;
94
95        // Special handling for SmartPointerSlice - convert builder to Arc
96        if self.frames.len() == 1 {
97            if let Tracker::SmartPointerSlice {
98                vtable,
99                building_item,
100            } = &self.frames[0].tracker
101            {
102                if *building_item {
103                    return Err(ReflectError::OperationFailed {
104                        shape: self.frames[0].shape,
105                        operation: "still building an item, finish it first",
106                    });
107                }
108
109                // Convert the builder to Arc<[T]>
110                let builder_ptr = unsafe { self.frames[0].data.assume_init() };
111                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
112
113                // Update the frame to store the Arc
114                self.frames[0].data = PtrUninit::new(unsafe {
115                    NonNull::new_unchecked(arc_ptr.as_byte_ptr() as *mut u8)
116                });
117                self.frames[0].tracker = Tracker::Init;
118                // The builder memory has been consumed by convert_fn, so we no longer own it
119                self.frames[0].ownership = FrameOwnership::ManagedElsewhere;
120
121                return Ok(self);
122            }
123        }
124
125        if self.frames.len() <= 1 {
126            // Never pop the last/root frame.
127            return Err(ReflectError::InvariantViolation {
128                invariant: "Partial::end() called with only one frame on the stack",
129            });
130        }
131
132        // Require that the top frame is fully initialized before popping.
133        {
134            let frame = self.frames.last().unwrap();
135            trace!(
136                "end(): Checking full initialization for frame with shape {} and tracker {:?}",
137                frame.shape,
138                frame.tracker.kind()
139            );
140            frame.require_full_initialization()?
141        }
142
143        // Pop the frame and save its data pointer for SmartPointer handling
144        let mut popped_frame = self.frames.pop().unwrap();
145
146        // Update parent frame's tracking when popping from a child
147        let parent_frame = self.frames.last_mut().unwrap();
148
149        trace!(
150            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
151            popped_frame.shape,
152            popped_frame.tracker.kind(),
153            parent_frame.shape,
154            parent_frame.tracker.kind()
155        );
156
157        // Check if we need to do a conversion - this happens when:
158        // 1. The parent frame has an inner type that matches the popped frame's shape
159        // 2. The parent frame has try_from
160        // 3. The parent frame is not yet initialized
161        let needs_conversion = matches!(parent_frame.tracker, Tracker::Uninit)
162            && parent_frame.shape.inner.is_some()
163            && parent_frame.shape.inner.unwrap() == popped_frame.shape
164            && parent_frame.shape.vtable.try_from.is_some();
165
166        if needs_conversion {
167            trace!(
168                "Detected implicit conversion needed from {} to {}",
169                popped_frame.shape, parent_frame.shape
170            );
171            // Perform the conversion
172            if let Some(try_from_fn) = parent_frame.shape.vtable.try_from {
173                let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
174                let inner_shape = popped_frame.shape;
175
176                trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
177                let result = unsafe { try_from_fn(inner_ptr, inner_shape, parent_frame.data) };
178
179                if let Err(e) = result {
180                    trace!("Conversion failed: {e:?}");
181
182                    // Deallocate the inner value's memory since conversion failed
183                    if let FrameOwnership::Owned = popped_frame.ownership {
184                        if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
185                            if layout.size() > 0 {
186                                trace!(
187                                    "Deallocating conversion frame memory after failure: size={}, align={}",
188                                    layout.size(),
189                                    layout.align()
190                                );
191                                unsafe {
192                                    alloc::alloc::dealloc(
193                                        popped_frame.data.as_mut_byte_ptr(),
194                                        layout,
195                                    );
196                                }
197                            }
198                        }
199                    }
200
201                    return Err(ReflectError::TryFromError {
202                        src_shape: inner_shape,
203                        dst_shape: parent_frame.shape,
204                        inner: e,
205                    });
206                }
207
208                trace!("Conversion succeeded, marking parent as initialized");
209                parent_frame.tracker = Tracker::Init;
210
211                // Deallocate the inner value's memory since try_from consumed it
212                if let FrameOwnership::Owned = popped_frame.ownership {
213                    if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
214                        if layout.size() > 0 {
215                            trace!(
216                                "Deallocating conversion frame memory: size={}, align={}",
217                                layout.size(),
218                                layout.align()
219                            );
220                            unsafe {
221                                alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
222                            }
223                        }
224                    }
225                }
226
227                return Ok(self);
228            }
229        }
230
231        match &mut parent_frame.tracker {
232            Tracker::Struct {
233                iset,
234                current_child,
235            } => {
236                if let Some(idx) = *current_child {
237                    iset.set(idx);
238                    *current_child = None;
239                }
240            }
241            Tracker::Array {
242                iset,
243                current_child,
244            } => {
245                if let Some(idx) = *current_child {
246                    iset.set(idx);
247                    *current_child = None;
248                }
249            }
250            Tracker::SmartPointer { is_initialized } => {
251                // We just popped the inner value frame, so now we need to create the smart pointer
252                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
253                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
254                        return Err(ReflectError::OperationFailed {
255                            shape: parent_frame.shape,
256                            operation: "SmartPointer missing new_into_fn",
257                        });
258                    };
259
260                    // The child frame contained the inner value
261                    let inner_ptr = PtrMut::new(unsafe {
262                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
263                    });
264
265                    // Use new_into_fn to create the Box
266                    unsafe {
267                        new_into_fn(parent_frame.data, inner_ptr);
268                    }
269
270                    // We just moved out of it
271                    popped_frame.tracker = Tracker::Uninit;
272
273                    // Deallocate the inner value's memory since new_into_fn moved it
274                    popped_frame.dealloc();
275
276                    *is_initialized = true;
277                }
278            }
279            Tracker::Enum {
280                data,
281                current_child,
282                ..
283            } => {
284                if let Some(idx) = *current_child {
285                    data.set(idx);
286                    *current_child = None;
287                }
288            }
289            Tracker::List {
290                is_initialized: true,
291                current_child,
292            } => {
293                if *current_child {
294                    // We just popped an element frame, now push it to the list
295                    if let Def::List(list_def) = parent_frame.shape.def {
296                        let Some(push_fn) = list_def.vtable.push else {
297                            return Err(ReflectError::OperationFailed {
298                                shape: parent_frame.shape,
299                                operation: "List missing push function",
300                            });
301                        };
302
303                        // The child frame contained the element value
304                        let element_ptr = PtrMut::new(unsafe {
305                            NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
306                        });
307
308                        // Use push to add element to the list
309                        unsafe {
310                            push_fn(
311                                PtrMut::new(NonNull::new_unchecked(
312                                    parent_frame.data.as_mut_byte_ptr(),
313                                )),
314                                element_ptr,
315                            );
316                        }
317
318                        // Push moved out of popped_frame
319                        popped_frame.tracker = Tracker::Uninit;
320                        popped_frame.dealloc();
321
322                        *current_child = false;
323                    }
324                }
325            }
326            Tracker::Map {
327                is_initialized: true,
328                insert_state,
329            } => {
330                match insert_state {
331                    MapInsertState::PushingKey { key_ptr } => {
332                        // We just popped the key frame
333                        if let Some(key_ptr) = key_ptr {
334                            // Transition to PushingValue state
335                            *insert_state = MapInsertState::PushingValue {
336                                key_ptr: *key_ptr,
337                                value_ptr: None,
338                            };
339                        }
340                    }
341                    MapInsertState::PushingValue { key_ptr, value_ptr } => {
342                        // We just popped the value frame, now insert the pair
343                        if let (Some(value_ptr), Def::Map(map_def)) =
344                            (value_ptr, parent_frame.shape.def)
345                        {
346                            let insert_fn = map_def.vtable.insert_fn;
347
348                            // Use insert to add key-value pair to the map
349                            unsafe {
350                                insert_fn(
351                                    PtrMut::new(NonNull::new_unchecked(
352                                        parent_frame.data.as_mut_byte_ptr(),
353                                    )),
354                                    PtrMut::new(NonNull::new_unchecked(key_ptr.as_mut_byte_ptr())),
355                                    PtrMut::new(NonNull::new_unchecked(
356                                        value_ptr.as_mut_byte_ptr(),
357                                    )),
358                                );
359                            }
360
361                            // Note: We don't deallocate the key and value memory here.
362                            // The insert function has semantically moved the values into the map,
363                            // but we still need to deallocate the temporary buffers.
364                            // However, since we don't have frames for them anymore (they were popped),
365                            // we need to handle deallocation here.
366                            if let Ok(key_shape) = map_def.k().layout.sized_layout() {
367                                if key_shape.size() > 0 {
368                                    unsafe {
369                                        alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
370                                    }
371                                }
372                            }
373                            if let Ok(value_shape) = map_def.v().layout.sized_layout() {
374                                if value_shape.size() > 0 {
375                                    unsafe {
376                                        alloc::alloc::dealloc(
377                                            value_ptr.as_mut_byte_ptr(),
378                                            value_shape,
379                                        );
380                                    }
381                                }
382                            }
383
384                            // Reset to idle state
385                            *insert_state = MapInsertState::Idle;
386                        }
387                    }
388                    MapInsertState::Idle => {
389                        // Nothing to do
390                    }
391                }
392            }
393            Tracker::Option { building_inner } => {
394                // We just popped the inner value frame for an Option's Some variant
395                if *building_inner {
396                    if let Def::Option(option_def) = parent_frame.shape.def {
397                        // Use the Option vtable to initialize Some(inner_value)
398                        let init_some_fn = option_def.vtable.init_some_fn;
399
400                        // The popped frame contains the inner value
401                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
402
403                        // Initialize the Option as Some(inner_value)
404                        unsafe {
405                            init_some_fn(parent_frame.data, inner_value_ptr);
406                        }
407
408                        // Deallocate the inner value's memory since init_some_fn moved it
409                        if let FrameOwnership::Owned = popped_frame.ownership {
410                            if let Ok(layout) = popped_frame.shape.layout.sized_layout() {
411                                if layout.size() > 0 {
412                                    unsafe {
413                                        alloc::alloc::dealloc(
414                                            popped_frame.data.as_mut_byte_ptr(),
415                                            layout,
416                                        );
417                                    }
418                                }
419                            }
420                        }
421
422                        // Mark that we're no longer building the inner value
423                        *building_inner = false;
424                    } else {
425                        return Err(ReflectError::OperationFailed {
426                            shape: parent_frame.shape,
427                            operation: "Option frame without Option definition",
428                        });
429                    }
430                }
431            }
432            Tracker::Uninit | Tracker::Init => {
433                // the main case here is: the popped frame was a `String` and the
434                // parent frame is an `Arc<str>`, `Box<str>` etc.
435                match &parent_frame.shape.def {
436                    Def::Pointer(smart_ptr_def) => {
437                        let pointee =
438                            smart_ptr_def
439                                .pointee()
440                                .ok_or(ReflectError::InvariantViolation {
441                                    invariant: "pointer type doesn't have a pointee",
442                                })?;
443
444                        if !pointee.is_shape(str::SHAPE) {
445                            return Err(ReflectError::InvariantViolation {
446                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
447                            });
448                        }
449
450                        if !popped_frame.shape.is_shape(String::SHAPE) {
451                            return Err(ReflectError::InvariantViolation {
452                                invariant: "the popped frame should be String when building a SmartPointer<T>",
453                            });
454                        }
455
456                        popped_frame.require_full_initialization()?;
457
458                        // if the just-popped frame was a SmartPointerStr, we have some conversion to do:
459                        // Special-case: SmartPointer<str> (Box<str>, Arc<str>, Rc<str>) via SmartPointerStr tracker
460                        // Here, popped_frame actually contains a value for String that should be moved into the smart pointer.
461                        // We convert the String into Box<str>, Arc<str>, or Rc<str> as appropriate and write it to the parent frame.
462                        use alloc::{rc::Rc, string::String, sync::Arc};
463                        let parent_shape = parent_frame.shape;
464
465                        let Some(known) = smart_ptr_def.known else {
466                            return Err(ReflectError::OperationFailed {
467                                shape: parent_shape,
468                                operation: "SmartPointerStr for unknown smart pointer kind",
469                            });
470                        };
471
472                        parent_frame.deinit();
473
474                        // Interpret the memory as a String, then convert and write.
475                        let string_ptr = popped_frame.data.as_mut_byte_ptr() as *mut String;
476                        let string_value = unsafe { core::ptr::read(string_ptr) };
477
478                        match known {
479                            KnownPointer::Box => {
480                                let boxed: Box<str> = string_value.into_boxed_str();
481                                unsafe {
482                                    core::ptr::write(
483                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
484                                        boxed,
485                                    );
486                                }
487                            }
488                            KnownPointer::Arc => {
489                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
490                                unsafe {
491                                    core::ptr::write(
492                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
493                                        arc,
494                                    );
495                                }
496                            }
497                            KnownPointer::Rc => {
498                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
499                                unsafe {
500                                    core::ptr::write(
501                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
502                                        rc,
503                                    );
504                                }
505                            }
506                            _ => {
507                                return Err(ReflectError::OperationFailed {
508                                    shape: parent_shape,
509                                    operation: "Don't know how to build this pointer type",
510                                });
511                            }
512                        }
513
514                        parent_frame.tracker = Tracker::Init;
515
516                        popped_frame.tracker = Tracker::Uninit;
517                        popped_frame.dealloc();
518                    }
519                    _ => {
520                        unreachable!(
521                            "we popped a frame and parent was Init or Uninit, but it wasn't a smart pointer and... there's no way this should happen normally"
522                        )
523                    }
524                }
525            }
526            Tracker::SmartPointerSlice {
527                vtable,
528                building_item,
529            } => {
530                if *building_item {
531                    // We just popped an element frame, now push it to the slice builder
532                    let element_ptr = PtrMut::new(unsafe {
533                        NonNull::new_unchecked(popped_frame.data.as_mut_byte_ptr())
534                    });
535
536                    // Use the slice builder's push_fn to add the element
537                    crate::trace!("Pushing element to slice builder");
538                    unsafe {
539                        let parent_ptr = parent_frame.data.assume_init();
540                        (vtable.push_fn)(parent_ptr, element_ptr);
541                    }
542
543                    popped_frame.tracker = Tracker::Uninit;
544                    popped_frame.dealloc();
545
546                    if let Tracker::SmartPointerSlice {
547                        building_item: bi, ..
548                    } = &mut parent_frame.tracker
549                    {
550                        *bi = false;
551                    }
552                }
553            }
554            _ => {}
555        }
556
557        Ok(self)
558    }
559
560    /// Returns a human-readable path representing the current traversal in the builder,
561    /// e.g., `RootStruct.fieldName[index].subfield`.
562    pub fn path(&self) -> String {
563        let mut out = String::new();
564
565        let mut path_components = Vec::new();
566        // The stack of enum/struct/sequence names currently in context.
567        // Start from root and build upwards.
568        for (i, frame) in self.frames.iter().enumerate() {
569            match frame.shape.ty {
570                Type::User(user_type) => match user_type {
571                    UserType::Struct(struct_type) => {
572                        // Try to get currently active field index
573                        let mut field_str = None;
574                        if let Tracker::Struct {
575                            current_child: Some(idx),
576                            ..
577                        } = &frame.tracker
578                        {
579                            if let Some(field) = struct_type.fields.get(*idx) {
580                                field_str = Some(field.name);
581                            }
582                        }
583                        if i == 0 {
584                            // Use Display for the root struct shape
585                            path_components.push(format!("{}", frame.shape));
586                        }
587                        if let Some(field_name) = field_str {
588                            path_components.push(format!(".{field_name}"));
589                        }
590                    }
591                    UserType::Enum(_enum_type) => {
592                        // Try to get currently active variant and field
593                        if let Tracker::Enum {
594                            variant,
595                            current_child,
596                            ..
597                        } = &frame.tracker
598                        {
599                            if i == 0 {
600                                // Use Display for the root enum shape
601                                path_components.push(format!("{}", frame.shape));
602                            }
603                            path_components.push(format!("::{}", variant.name));
604                            if let Some(idx) = *current_child {
605                                if let Some(field) = variant.data.fields.get(idx) {
606                                    path_components.push(format!(".{}", field.name));
607                                }
608                            }
609                        } else if i == 0 {
610                            // just the enum display
611                            path_components.push(format!("{}", frame.shape));
612                        }
613                    }
614                    UserType::Union(_union_type) => {
615                        path_components.push(format!("{}", frame.shape));
616                    }
617                    UserType::Opaque => {
618                        path_components.push("<opaque>".to_string());
619                    }
620                },
621                Type::Sequence(seq_type) => match seq_type {
622                    facet_core::SequenceType::Array(_array_def) => {
623                        // Try to show current element index
624                        if let Tracker::Array {
625                            current_child: Some(idx),
626                            ..
627                        } = &frame.tracker
628                        {
629                            path_components.push(format!("[{idx}]"));
630                        }
631                    }
632                    // You can add more for Slice, Vec, etc., if applicable
633                    _ => {
634                        // just indicate "[]" for sequence
635                        path_components.push("[]".to_string());
636                    }
637                },
638                Type::Pointer(_) => {
639                    // Indicate deref
640                    path_components.push("*".to_string());
641                }
642                _ => {
643                    // No structural path
644                }
645            }
646        }
647        // Merge the path_components into a single string
648        for component in path_components {
649            out.push_str(&component);
650        }
651        out
652    }
653}
654
655////////////////////////////////////////////////////////////////////////////////////////////////////
656// Build
657////////////////////////////////////////////////////////////////////////////////////////////////////
658impl<'facet> Partial<'facet> {
659    /// Builds the value
660    pub fn build(&mut self) -> Result<HeapValue<'facet>, ReflectError> {
661        self.require_active()?;
662        if self.frames.len() != 1 {
663            self.state = PartialState::BuildFailed;
664            return Err(ReflectError::InvariantViolation {
665                invariant: "Partial::build() expects a single frame — call end() until that's the case",
666            });
667        }
668
669        let frame = self.frames.pop().unwrap();
670
671        // Check initialization before proceeding
672        if let Err(e) = frame.require_full_initialization() {
673            // Put the frame back so Drop can handle cleanup properly
674            self.frames.push(frame);
675            self.state = PartialState::BuildFailed;
676            return Err(e);
677        }
678
679        // Check invariants if present
680        if let Some(invariants_fn) = frame.shape.vtable.invariants {
681            // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
682            let value_ptr = unsafe { frame.data.assume_init().as_const() };
683            let invariants_ok = unsafe { invariants_fn(value_ptr) };
684
685            if !invariants_ok {
686                // Put the frame back so Drop can handle cleanup properly
687                self.frames.push(frame);
688                self.state = PartialState::BuildFailed;
689                return Err(ReflectError::InvariantViolation {
690                    invariant: "Type invariants check failed",
691                });
692            }
693        }
694
695        // Mark as built to prevent reuse
696        self.state = PartialState::Built;
697
698        match frame
699            .shape
700            .layout
701            .sized_layout()
702            .map_err(|_layout_err| ReflectError::Unsized {
703                shape: frame.shape,
704                operation: "build (final check for sized layout)",
705            }) {
706            Ok(layout) => Ok(HeapValue {
707                guard: Some(Guard {
708                    ptr: unsafe { NonNull::new_unchecked(frame.data.as_mut_byte_ptr()) },
709                    layout,
710                }),
711                shape: frame.shape,
712                phantom: PhantomData,
713            }),
714            Err(e) => {
715                // Put the frame back for proper cleanup
716                self.frames.push(frame);
717                self.state = PartialState::BuildFailed;
718                Err(e)
719            }
720        }
721    }
722}
723
724////////////////////////////////////////////////////////////////////////////////////////////////////
725// `Set` and set helpers
726////////////////////////////////////////////////////////////////////////////////////////////////////
727impl<'facet> Partial<'facet> {
728    /// Sets a value wholesale into the current frame.
729    ///
730    /// If the current frame was already initialized, the previous value is
731    /// dropped. If it was partially initialized, the fields that were initialized
732    /// are dropped, etc.
733    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
734    where
735        U: Facet<'facet>,
736    {
737        self.require_active()?;
738        struct DropVal<U> {
739            ptr: *mut U,
740        }
741        impl<U> Drop for DropVal<U> {
742            #[inline]
743            fn drop(&mut self) {
744                unsafe { core::ptr::drop_in_place(self.ptr) };
745            }
746        }
747
748        let mut value = ManuallyDrop::new(value);
749        let drop = DropVal {
750            ptr: (&mut value) as *mut ManuallyDrop<U> as *mut U,
751        };
752
753        let ptr_const = PtrConst::new(unsafe { NonNull::new_unchecked(drop.ptr) });
754        unsafe {
755            // Safety: We are calling set_shape with a valid shape and a valid pointer
756            self.set_shape(ptr_const, U::SHAPE)?
757        };
758        core::mem::forget(drop);
759
760        Ok(self)
761    }
762
763    /// Sets a value into the current frame by [PtrConst] / [Shape].
764    ///
765    /// # Safety
766    ///
767    /// The caller must ensure that `src_value` points to a valid instance of a value
768    /// whose memory layout and type matches `src_shape`, and that this value can be
769    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
770    ///
771    /// After a successful call, the ownership of the value at `src_value` is effectively moved
772    /// into the Partial (i.e., the destination), and the original value should not be used
773    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
774    ///
775    /// If an error is returned, the destination remains unmodified and safe for future operations.
776    #[inline]
777    pub unsafe fn set_shape(
778        &mut self,
779        src_value: PtrConst<'_>,
780        src_shape: &'static Shape,
781    ) -> Result<&mut Self, ReflectError> {
782        self.require_active()?;
783
784        let fr = self.frames.last_mut().unwrap();
785        crate::trace!("set_shape({src_shape:?})");
786
787        if !fr.shape.is_shape(src_shape) {
788            return Err(ReflectError::WrongShape {
789                expected: fr.shape,
790                actual: src_shape,
791            });
792        }
793
794        fr.deinit();
795
796        // SAFETY: `fr.shape` and `src_shape` are the same, so they have the same size,
797        // and the preconditions for this function are that `src_value` is fully intialized.
798        unsafe {
799            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
800            // which is not possible for `Partial`
801            fr.data.copy_from(src_value, fr.shape).unwrap();
802        }
803
804        // SAFETY: if we reached this point, `fr.data` is correctly initialized
805        unsafe {
806            fr.mark_as_init();
807        }
808
809        Ok(self)
810    }
811
812    /// Sets the current frame using a function that initializes the value
813    ///
814    /// # Safety
815    ///
816    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
817    /// value of the right type.
818    ///
819    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
820    /// there is no need to drop it in place.
821    pub unsafe fn set_from_function<F>(&mut self, f: F) -> Result<&mut Self, ReflectError>
822    where
823        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
824    {
825        self.require_active()?;
826        let frame = self.frames.last_mut().unwrap();
827
828        frame.deinit();
829        f(frame.data)?;
830
831        // safety: `f()` returned Ok, so `frame.data` must be initialized
832        unsafe {
833            frame.mark_as_init();
834        }
835
836        Ok(self)
837    }
838
839    /// Sets the current frame to its default value using `default_in_place` from the
840    /// vtable.
841    ///
842    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
843    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
844    /// for `field`.
845    ///
846    /// If the current frame's shape does not implement `Default`, then this returns an error.
847    #[inline]
848    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
849        let frame = self.frames.last().unwrap();
850
851        let Some(default_fn) = frame.shape.vtable.default_in_place else {
852            return Err(ReflectError::OperationFailed {
853                shape: frame.shape,
854                operation: "type does not implement Default",
855            });
856        };
857
858        // SAFETY: `default_fn` fully initializes the passed pointer. we took it
859        // from the vtable of `frame.shape`.
860        unsafe {
861            self.set_from_function(move |ptr| {
862                default_fn(ptr);
863                Ok(())
864            })
865        }
866    }
867
868    /// Copy a value from a Peek into the current frame.
869    ///
870    /// # Invariants
871    ///
872    /// `peek` must be a thin pointer, otherwise this panics.
873    ///
874    /// # Safety
875    ///
876    /// If this succeeds, the value `Peek` points to has been moved out of, and
877    /// as such, should not be dropped (but should be deallocated).
878    pub unsafe fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
879        self.require_active()?;
880
881        // Get the source value's pointer and shape
882        let src_ptr = peek.data();
883        let src_shape = peek.shape();
884
885        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
886        unsafe { self.set_shape(src_ptr, src_shape) }
887    }
888
889    /// Parses a string value into the current frame using the type's ParseFn from the vtable.
890    ///
891    /// If the current frame was previously initialized, its contents are dropped in place.
892    pub fn parse_from_str(&mut self, s: &str) -> Result<&mut Self, ReflectError> {
893        self.require_active()?;
894
895        let frame = self.frames.last_mut().unwrap();
896
897        // Check if the type has a parse function
898        let Some(parse_fn) = frame.shape.vtable.parse else {
899            return Err(ReflectError::OperationFailed {
900                shape: frame.shape,
901                operation: "Type does not support parsing from string",
902            });
903        };
904
905        // Note: deinit leaves us in `Tracker::Uninit` state which is valid even if we error out.
906        frame.deinit();
907
908        // Parse the string value using the type's parse function
909        let result = unsafe { parse_fn(s, frame.data) };
910        if let Err(_pe) = result {
911            // TODO: can we propagate the ParseError somehow?
912            return Err(ReflectError::OperationFailed {
913                shape: frame.shape,
914                operation: "Failed to parse string value",
915            });
916        }
917
918        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
919        unsafe {
920            frame.mark_as_init();
921        }
922        Ok(self)
923    }
924}
925
926////////////////////////////////////////////////////////////////////////////////////////////////////
927// Enum variant selection
928////////////////////////////////////////////////////////////////////////////////////////////////////
929impl<'facet> Partial<'facet> {
930    /// Get the currently selected variant for an enum
931    pub fn selected_variant(&self) -> Option<Variant> {
932        let frame = self.frames.last()?;
933
934        match &frame.tracker {
935            Tracker::Enum { variant, .. } => Some(**variant),
936            _ => None,
937        }
938    }
939
940    /// Find a variant by name in the current enum
941    pub fn find_variant(&self, variant_name: &str) -> Option<(usize, &'static Variant)> {
942        let frame = self.frames.last()?;
943
944        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
945            enum_def
946                .variants
947                .iter()
948                .enumerate()
949                .find(|(_, v)| v.name == variant_name)
950        } else {
951            None
952        }
953    }
954
955    /// Assuming the current frame is an enum, this selects a variant by index
956    /// (0-based, in declaration order).
957    ///
958    /// For example:
959    ///
960    /// ```rust,no_run
961    /// enum E { A, B, C }
962    /// ```
963    ///
964    /// Calling `select_nth_variant(2)` would select variant `C`.
965    ///
966    /// This will return an error if the current frame is anything other than fully-uninitialized.
967    /// In other words, it's not possible to "switch to a different variant" once you've selected one.
968    ///
969    /// This does _not_ push a frame on the stack.
970    pub fn select_nth_variant(&mut self, index: usize) -> Result<&mut Self, ReflectError> {
971        self.require_active()?;
972
973        let frame = self.frames.last().unwrap();
974        let enum_type = frame.get_enum_type()?;
975
976        if index >= enum_type.variants.len() {
977            return Err(ReflectError::OperationFailed {
978                shape: frame.shape,
979                operation: "variant index out of bounds",
980            });
981        }
982        let variant = &enum_type.variants[index];
983
984        self.select_variant_internal(&enum_type, variant)?;
985        Ok(self)
986    }
987
988    /// Pushes a variant for enum initialization by name
989    ///
990    /// See [Self::select_nth_variant] for more notes.
991    pub fn select_variant_named(&mut self, variant_name: &str) -> Result<&mut Self, ReflectError> {
992        self.require_active()?;
993
994        let frame = self.frames.last_mut().unwrap();
995        let enum_type = frame.get_enum_type()?;
996
997        let Some(variant) = enum_type.variants.iter().find(|v| v.name == variant_name) else {
998            return Err(ReflectError::OperationFailed {
999                shape: frame.shape,
1000                operation: "No variant found with the given name",
1001            });
1002        };
1003
1004        self.select_variant_internal(&enum_type, variant)?;
1005        Ok(self)
1006    }
1007
1008    /// Selects a given enum variant by discriminant. If none of the variants
1009    /// of the frame's enum have that discriminant, this returns an error.
1010    ///
1011    /// See [Self::select_nth_variant] for more notes.
1012    pub fn select_variant(&mut self, discriminant: i64) -> Result<&mut Self, ReflectError> {
1013        self.require_active()?;
1014
1015        // Check all invariants early before making any changes
1016        let frame = self.frames.last().unwrap();
1017
1018        // Check that we're dealing with an enum
1019        let enum_type = match frame.shape.ty {
1020            Type::User(UserType::Enum(e)) => e,
1021            _ => {
1022                return Err(ReflectError::WasNotA {
1023                    expected: "enum",
1024                    actual: frame.shape,
1025                });
1026            }
1027        };
1028
1029        // Find the variant with the matching discriminant
1030        let Some(variant) = enum_type
1031            .variants
1032            .iter()
1033            .find(|v| v.discriminant == Some(discriminant))
1034        else {
1035            return Err(ReflectError::OperationFailed {
1036                shape: frame.shape,
1037                operation: "No variant found with the given discriminant",
1038            });
1039        };
1040
1041        // Update the frame tracker to select the variant
1042        self.select_variant_internal(&enum_type, variant)?;
1043
1044        Ok(self)
1045    }
1046}
1047
1048////////////////////////////////////////////////////////////////////////////////////////////////////
1049// Field selection
1050////////////////////////////////////////////////////////////////////////////////////////////////////
1051impl Partial<'_> {
1052    /// Find the index of a field by name in the current struct
1053    ///
1054    /// If the current frame isn't a struct or an enum (with a selected variant)
1055    /// then this returns `None` for sure.
1056    pub fn field_index(&self, field_name: &str) -> Option<usize> {
1057        let frame = self.frames.last()?;
1058
1059        match frame.shape.ty {
1060            Type::User(UserType::Struct(struct_def)) => {
1061                struct_def.fields.iter().position(|f| f.name == field_name)
1062            }
1063            Type::User(UserType::Enum(_)) => {
1064                // If we're in an enum variant, check its fields
1065                if let Tracker::Enum { variant, .. } = &frame.tracker {
1066                    variant
1067                        .data
1068                        .fields
1069                        .iter()
1070                        .position(|f| f.name == field_name)
1071                } else {
1072                    None
1073                }
1074            }
1075            _ => None,
1076        }
1077    }
1078
1079    /// Check if a struct field at the given index has been set
1080    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
1081        let frame = self.frames.last().ok_or(ReflectError::NoActiveFrame)?;
1082
1083        match &frame.tracker {
1084            Tracker::Uninit => Ok(false),
1085            Tracker::Init => Ok(true),
1086            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
1087            Tracker::Enum { data, variant, .. } => {
1088                // Check if the field is already marked as set
1089                if data.get(index) {
1090                    return Ok(true);
1091                }
1092
1093                // For enum variant fields that are empty structs, they are always initialized
1094                if let Some(field) = variant.data.fields.get(index) {
1095                    if let Type::User(UserType::Struct(field_struct)) = field.shape().ty {
1096                        if field_struct.fields.is_empty() {
1097                            return Ok(true);
1098                        }
1099                    }
1100                }
1101
1102                Ok(false)
1103            }
1104            Tracker::Option { building_inner } => {
1105                // For Options, index 0 represents the inner value
1106                if index == 0 {
1107                    Ok(!building_inner)
1108                } else {
1109                    Err(ReflectError::InvalidOperation {
1110                        operation: "is_field_set",
1111                        reason: "Option only has one field (index 0)",
1112                    })
1113                }
1114            }
1115            _ => Err(ReflectError::InvalidOperation {
1116                operation: "is_field_set",
1117                reason: "Current frame is not a struct, enum variant, or option",
1118            }),
1119        }
1120    }
1121
1122    /// Selects a field (by name) of a struct or enum data.
1123    ///
1124    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
1125    /// and friends.
1126    pub fn begin_field(&mut self, field_name: &str) -> Result<&mut Self, ReflectError> {
1127        self.require_active()?;
1128
1129        let frame = self.frames.last().unwrap();
1130        let fields = self.get_fields()?;
1131        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
1132            return Err(ReflectError::FieldError {
1133                shape: frame.shape,
1134                field_error: facet_core::FieldError::NoSuchField,
1135            });
1136        };
1137        self.begin_nth_field(idx)
1138    }
1139
1140    /// Begins the nth field of a struct, enum variant, or array, by index.
1141    ///
1142    /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
1143    pub fn begin_nth_field(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
1144        self.require_active()?;
1145        let frame = self.frames.last_mut().unwrap();
1146
1147        let next_frame = match frame.shape.ty {
1148            Type::User(user_type) => match user_type {
1149                UserType::Struct(struct_type) => {
1150                    Self::begin_nth_struct_field(frame, struct_type, idx)?
1151                }
1152                UserType::Enum(_) => {
1153                    // Check if we have a variant selected
1154                    match &frame.tracker {
1155                        Tracker::Enum { variant, .. } => {
1156                            Self::begin_nth_enum_field(frame, variant, idx)?
1157                        }
1158                        _ => {
1159                            return Err(ReflectError::OperationFailed {
1160                                shape: frame.shape,
1161                                operation: "must call select_variant before selecting enum fields",
1162                            });
1163                        }
1164                    }
1165                }
1166                UserType::Union(_) => {
1167                    return Err(ReflectError::OperationFailed {
1168                        shape: frame.shape,
1169                        operation: "cannot select a field from a union",
1170                    });
1171                }
1172                UserType::Opaque => {
1173                    return Err(ReflectError::OperationFailed {
1174                        shape: frame.shape,
1175                        operation: "cannot select a field from an opaque type",
1176                    });
1177                }
1178            },
1179            Type::Sequence(sequence_type) => match sequence_type {
1180                SequenceType::Array(array_type) => {
1181                    Self::begin_nth_array_element(frame, array_type, idx)?
1182                }
1183                SequenceType::Slice(_) => {
1184                    return Err(ReflectError::OperationFailed {
1185                        shape: frame.shape,
1186                        operation: "cannot select a field from slices yet",
1187                    });
1188                }
1189            },
1190            _ => {
1191                return Err(ReflectError::OperationFailed {
1192                    shape: frame.shape,
1193                    operation: "cannot select a field from this type",
1194                });
1195            }
1196        };
1197
1198        self.frames.push(next_frame);
1199        Ok(self)
1200    }
1201
1202    /// Sets the given field to its default value, preferring:
1203    ///
1204    ///   * A `default = some_fn()` function
1205    ///   * The field's `Default` implementation if any
1206    ///
1207    /// But without going all the way up to the parent struct's `Default` impl.
1208    ///
1209    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
1210    pub fn set_nth_field_to_default(&mut self, idx: usize) -> Result<&mut Self, ReflectError> {
1211        self.require_active()?;
1212
1213        let frame = self.frames.last().unwrap();
1214        let fields = self.get_fields()?;
1215
1216        if idx >= fields.len() {
1217            return Err(ReflectError::OperationFailed {
1218                shape: frame.shape,
1219                operation: "field index out of bounds",
1220            });
1221        }
1222
1223        let field = fields[idx];
1224
1225        // Check for field-level default function first, then type-level default
1226        if let Some(field_default_fn) = field.vtable.default_fn {
1227            self.begin_nth_field(idx)?;
1228            // the field default fn should be well-behaved
1229            unsafe {
1230                self.set_from_function(|ptr| {
1231                    field_default_fn(ptr);
1232                    Ok(())
1233                })?;
1234            }
1235            self.end()
1236        } else if field.shape().is(Characteristic::Default) {
1237            self.begin_nth_field(idx)?;
1238            self.set_default()?;
1239            self.end()
1240        } else {
1241            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
1242                shape: field.shape(),
1243            });
1244        }
1245    }
1246
1247    /// Given a `Partial` for the same shape, and assuming that partial has the nth
1248    /// field initialized, move the value from `src` to `self`, marking it as deinitialized
1249    /// in `src`.
1250    pub fn steal_nth_field(
1251        &mut self,
1252        src: &mut Partial,
1253        field_index: usize,
1254    ) -> Result<&mut Self, ReflectError> {
1255        let dst_shape = self.shape();
1256        let src_shape = src.shape();
1257        if dst_shape != src_shape {
1258            return Err(ReflectError::HeistCancelledDifferentShapes {
1259                src_shape,
1260                dst_shape,
1261            });
1262        }
1263
1264        // FIXME: what about enums? we don't check that the right variant is
1265        // selected here.
1266        if !src.is_field_set(field_index)? {
1267            return Err(ReflectError::InvariantViolation {
1268                invariant: "stolen field must be initialized",
1269            });
1270        }
1271
1272        let maybe_fields = match src_shape.ty {
1273            Type::Primitive(_primitive_type) => None,
1274            Type::Sequence(_sequence_type) => None,
1275            Type::User(user_type) => match user_type {
1276                UserType::Struct(struct_type) => Some(struct_type.fields),
1277                UserType::Enum(_enum_type) => match self.selected_variant() {
1278                    Some(variant) => Some(variant.data.fields),
1279                    None => {
1280                        return Err(ReflectError::InvariantViolation {
1281                            invariant: "enum field thief must have variant selected",
1282                        });
1283                    }
1284                },
1285                UserType::Union(_union_type) => None,
1286                UserType::Opaque => None,
1287            },
1288            Type::Pointer(_pointer_type) => None,
1289        };
1290
1291        let Some(fields) = maybe_fields else {
1292            return Err(ReflectError::OperationFailed {
1293                shape: src_shape,
1294                operation: "fetching field list for steal_nth_field",
1295            });
1296        };
1297
1298        if field_index >= fields.len() {
1299            return Err(ReflectError::OperationFailed {
1300                shape: src_shape,
1301                operation: "field index out of bounds",
1302            });
1303        }
1304        let field = fields[field_index];
1305
1306        let src_frame = src.frames.last_mut().unwrap();
1307
1308        self.begin_nth_field(field_index)?;
1309        unsafe {
1310            self.set_from_function(|dst_field_ptr| {
1311                let src_field_ptr = src_frame.data.field_init_at(field.offset).as_const();
1312                dst_field_ptr
1313                    .copy_from(src_field_ptr, field.shape())
1314                    .unwrap();
1315                Ok(())
1316            })?;
1317        }
1318        self.end()?;
1319
1320        // now mark field as uninitialized in `src`
1321        match &mut src_frame.tracker {
1322            Tracker::Uninit => {
1323                unreachable!("we just stole a field from src, it couldn't have been fully uninit")
1324            }
1325            Tracker::Init => {
1326                // all struct fields were init so we don't even have a struct tracker,
1327                // let's make one!
1328                let mut iset = ISet::new(fields.len());
1329                iset.set_all();
1330                iset.unset(field_index);
1331                src_frame.tracker = Tracker::Struct {
1332                    iset,
1333                    current_child: None,
1334                }
1335            }
1336            Tracker::Array { .. } => unreachable!("can't steal fields from arrays"),
1337            Tracker::Struct { iset, .. } => {
1338                iset.unset(field_index);
1339            }
1340            Tracker::SmartPointer { .. } => {
1341                unreachable!("can't steal fields from smart pointers")
1342            }
1343            Tracker::SmartPointerSlice { .. } => {
1344                unreachable!("can't steal fields from smart pointer slices")
1345            }
1346            Tracker::Enum { data, .. } => {
1347                data.unset(field_index);
1348            }
1349            Tracker::List { .. } => {
1350                unreachable!("can't steal fields from lists")
1351            }
1352            Tracker::Map { .. } => {
1353                unreachable!("can't steal fields from maps")
1354            }
1355            Tracker::Option { .. } => {
1356                unreachable!("can't steal fields from options")
1357            }
1358        }
1359
1360        Ok(self)
1361    }
1362}
1363
1364////////////////////////////////////////////////////////////////////////////////////////////////////
1365// Smart pointers
1366////////////////////////////////////////////////////////////////////////////////////////////////////
1367impl Partial<'_> {
1368    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
1369    pub fn begin_smart_ptr(&mut self) -> Result<&mut Self, ReflectError> {
1370        crate::trace!("begin_smart_ptr()");
1371        self.require_active()?;
1372        let frame = self.frames.last_mut().unwrap();
1373
1374        // Check that we have a SmartPointer
1375        match &frame.shape.def {
1376            Def::Pointer(smart_ptr_def) if smart_ptr_def.constructible_from_pointee() => {
1377                // Get the pointee shape
1378                let pointee_shape = match smart_ptr_def.pointee() {
1379                    Some(shape) => shape,
1380                    None => {
1381                        return Err(ReflectError::OperationFailed {
1382                            shape: frame.shape,
1383                            operation: "Smart pointer must have a pointee shape",
1384                        });
1385                    }
1386                };
1387
1388                if pointee_shape.layout.sized_layout().is_ok() {
1389                    // pointee is sized, we can allocate it — for `Arc<T>` we'll be allocating a `T` and
1390                    // holding onto it. We'll build a new Arc with it when ending the smart pointer frame.
1391
1392                    if matches!(frame.tracker, Tracker::Uninit) {
1393                        frame.tracker = Tracker::SmartPointer {
1394                            is_initialized: false,
1395                        };
1396                    }
1397
1398                    let inner_layout = match pointee_shape.layout.sized_layout() {
1399                        Ok(layout) => layout,
1400                        Err(_) => {
1401                            return Err(ReflectError::Unsized {
1402                                shape: pointee_shape,
1403                                operation: "begin_smart_ptr, calculating inner value layout",
1404                            });
1405                        }
1406                    };
1407                    let inner_ptr: *mut u8 = unsafe { alloc::alloc::alloc(inner_layout) };
1408                    let Some(inner_ptr) = NonNull::new(inner_ptr) else {
1409                        return Err(ReflectError::OperationFailed {
1410                            shape: frame.shape,
1411                            operation: "failed to allocate memory for smart pointer inner value",
1412                        });
1413                    };
1414
1415                    // Push a new frame for the inner value
1416                    self.frames.push(Frame::new(
1417                        PtrUninit::new(inner_ptr),
1418                        pointee_shape,
1419                        FrameOwnership::Owned,
1420                    ));
1421                } else {
1422                    // pointee is unsized, we only support a handful of cases there
1423                    if pointee_shape == str::SHAPE {
1424                        crate::trace!("Pointee is str");
1425
1426                        // Allocate space for a String
1427                        let string_layout = String::SHAPE
1428                            .layout
1429                            .sized_layout()
1430                            .expect("String must have a sized layout");
1431                        let string_ptr: *mut u8 = unsafe { alloc::alloc::alloc(string_layout) };
1432                        let Some(string_ptr) = NonNull::new(string_ptr) else {
1433                            return Err(ReflectError::OperationFailed {
1434                                shape: frame.shape,
1435                                operation: "failed to allocate memory for string",
1436                            });
1437                        };
1438                        let mut frame = Frame::new(
1439                            PtrUninit::new(string_ptr),
1440                            String::SHAPE,
1441                            FrameOwnership::Owned,
1442                        );
1443                        frame.tracker = Tracker::Uninit;
1444                        self.frames.push(frame);
1445                    } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
1446                        crate::trace!("Pointee is [{}]", _st.t);
1447
1448                        // Get the slice builder vtable
1449                        let slice_builder_vtable = smart_ptr_def
1450                            .vtable
1451                            .slice_builder_vtable
1452                            .ok_or(ReflectError::OperationFailed {
1453                                shape: frame.shape,
1454                                operation: "smart pointer does not support slice building",
1455                            })?;
1456
1457                        // Create a new builder
1458                        let builder_ptr = (slice_builder_vtable.new_fn)();
1459
1460                        // Deallocate the original Arc allocation before replacing with slice builder
1461                        if let FrameOwnership::Owned = frame.ownership {
1462                            if let Ok(layout) = frame.shape.layout.sized_layout() {
1463                                if layout.size() > 0 {
1464                                    unsafe {
1465                                        alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout)
1466                                    };
1467                                }
1468                            }
1469                        }
1470
1471                        // Update the current frame to use the slice builder
1472                        frame.data = builder_ptr.as_uninit();
1473                        frame.tracker = Tracker::SmartPointerSlice {
1474                            vtable: slice_builder_vtable,
1475                            building_item: false,
1476                        };
1477                        // The slice builder memory is managed by the vtable, not by us
1478                        frame.ownership = FrameOwnership::ManagedElsewhere;
1479                    } else {
1480                        return Err(ReflectError::OperationFailed {
1481                            shape: frame.shape,
1482                            operation: "push_smart_ptr can only be called on pointers to supported pointee types",
1483                        });
1484                    }
1485                }
1486
1487                Ok(self)
1488            }
1489            _ => Err(ReflectError::OperationFailed {
1490                shape: frame.shape,
1491                operation: "push_smart_ptr can only be called on compatible types",
1492            }),
1493        }
1494    }
1495}
1496
1497////////////////////////////////////////////////////////////////////////////////////////////////////
1498// Lists
1499////////////////////////////////////////////////////////////////////////////////////////////////////
1500impl Partial<'_> {
1501    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
1502    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
1503    /// `push`.
1504    ///
1505    /// `begin_list` does not clear the list if it was previously initialized.
1506    /// `begin_list` does not push a new frame to the stack, and thus does not
1507    /// require `end` to be called afterwards.
1508    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
1509        crate::trace!("begin_list()");
1510        self.require_active()?;
1511        let frame = self.frames.last_mut().unwrap();
1512
1513        match &frame.tracker {
1514            Tracker::Uninit => {
1515                // that's good, let's initialize it
1516            }
1517            Tracker::Init => {
1518                // initialized (perhaps from a previous round?) but should be a list tracker, let's fix that:
1519                frame.tracker = Tracker::List {
1520                    is_initialized: true,
1521                    current_child: false,
1522                };
1523                return Ok(self);
1524            }
1525            Tracker::List { is_initialized, .. } => {
1526                if *is_initialized {
1527                    // already initialized, nothing to do
1528                    return Ok(self);
1529                }
1530            }
1531            Tracker::SmartPointerSlice { .. } => {
1532                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
1533                return Ok(self);
1534            }
1535            _ => {
1536                return Err(ReflectError::UnexpectedTracker {
1537                    message: "begin_list called but tracker isn't something list-like",
1538                    current_tracker: frame.tracker.kind(),
1539                });
1540            }
1541        };
1542
1543        // Check that we have a List
1544        let list_def = match &frame.shape.def {
1545            Def::List(list_def) => list_def,
1546            _ => {
1547                return Err(ReflectError::OperationFailed {
1548                    shape: frame.shape,
1549                    operation: "begin_list can only be called on List types",
1550                });
1551            }
1552        };
1553
1554        // Check that we have init_in_place_with_capacity function
1555        let init_fn = match list_def.vtable.init_in_place_with_capacity {
1556            Some(f) => f,
1557            None => {
1558                return Err(ReflectError::OperationFailed {
1559                    shape: frame.shape,
1560                    operation: "list type does not support initialization with capacity",
1561                });
1562            }
1563        };
1564
1565        // Initialize the list with default capacity (0)
1566        unsafe {
1567            init_fn(frame.data, 0);
1568        }
1569
1570        // Update tracker to List state
1571        frame.tracker = Tracker::List {
1572            is_initialized: true,
1573            current_child: false,
1574        };
1575
1576        Ok(self)
1577    }
1578
1579    /// Pushes an element to the list
1580    /// The element should be set using `set()` or similar methods, then `pop()` to complete
1581    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
1582        crate::trace!("begin_list_item()");
1583        self.require_active()?;
1584        let frame = self.frames.last_mut().unwrap();
1585
1586        // Check if we're building a smart pointer slice
1587        if let Tracker::SmartPointerSlice {
1588            building_item,
1589            vtable: _,
1590        } = &frame.tracker
1591        {
1592            if *building_item {
1593                return Err(ReflectError::OperationFailed {
1594                    shape: frame.shape,
1595                    operation: "already building an item, call end() first",
1596                });
1597            }
1598
1599            // Get the element type from the smart pointer's pointee
1600            let element_shape = match &frame.shape.def {
1601                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
1602                    Some(pointee_shape) => match &pointee_shape.ty {
1603                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
1604                        _ => {
1605                            return Err(ReflectError::OperationFailed {
1606                                shape: frame.shape,
1607                                operation: "smart pointer pointee is not a slice",
1608                            });
1609                        }
1610                    },
1611                    None => {
1612                        return Err(ReflectError::OperationFailed {
1613                            shape: frame.shape,
1614                            operation: "smart pointer has no pointee",
1615                        });
1616                    }
1617                },
1618                _ => {
1619                    return Err(ReflectError::OperationFailed {
1620                        shape: frame.shape,
1621                        operation: "expected smart pointer definition",
1622                    });
1623                }
1624            };
1625
1626            // Allocate space for the element
1627            crate::trace!("Pointee is a slice of {element_shape}");
1628            let element_layout = match element_shape.layout.sized_layout() {
1629                Ok(layout) => layout,
1630                Err(_) => {
1631                    return Err(ReflectError::OperationFailed {
1632                        shape: element_shape,
1633                        operation: "cannot allocate unsized element",
1634                    });
1635                }
1636            };
1637
1638            let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
1639            let Some(element_ptr) = NonNull::new(element_ptr) else {
1640                return Err(ReflectError::OperationFailed {
1641                    shape: frame.shape,
1642                    operation: "failed to allocate memory for list element",
1643                });
1644            };
1645
1646            // Create and push the element frame
1647            crate::trace!("Pushing element frame, which we just allocated");
1648            let element_frame = Frame::new(
1649                PtrUninit::new(element_ptr),
1650                element_shape,
1651                FrameOwnership::Owned,
1652            );
1653            self.frames.push(element_frame);
1654
1655            // Mark that we're building an item
1656            // We need to update the tracker after pushing the frame
1657            let parent_idx = self.frames.len() - 2;
1658            if let Tracker::SmartPointerSlice { building_item, .. } =
1659                &mut self.frames[parent_idx].tracker
1660            {
1661                crate::trace!("Marking element frame as building item");
1662                *building_item = true;
1663            }
1664
1665            return Ok(self);
1666        }
1667
1668        // Check that we have a List that's been initialized
1669        let list_def = match &frame.shape.def {
1670            Def::List(list_def) => list_def,
1671            _ => {
1672                return Err(ReflectError::OperationFailed {
1673                    shape: frame.shape,
1674                    operation: "push can only be called on List types",
1675                });
1676            }
1677        };
1678
1679        // Verify the tracker is in List state and initialized
1680        match &mut frame.tracker {
1681            Tracker::List {
1682                is_initialized: true,
1683                current_child,
1684            } => {
1685                if *current_child {
1686                    return Err(ReflectError::OperationFailed {
1687                        shape: frame.shape,
1688                        operation: "already pushing an element, call pop() first",
1689                    });
1690                }
1691                *current_child = true;
1692            }
1693            _ => {
1694                return Err(ReflectError::OperationFailed {
1695                    shape: frame.shape,
1696                    operation: "must call begin_list() before push()",
1697                });
1698            }
1699        }
1700
1701        // Get the element shape
1702        let element_shape = list_def.t();
1703
1704        // Allocate space for the new element
1705        let element_layout = match element_shape.layout.sized_layout() {
1706            Ok(layout) => layout,
1707            Err(_) => {
1708                return Err(ReflectError::Unsized {
1709                    shape: element_shape,
1710                    operation: "begin_list_item: calculating element layout",
1711                });
1712            }
1713        };
1714        let element_ptr: *mut u8 = unsafe { alloc::alloc::alloc(element_layout) };
1715
1716        let Some(element_ptr) = NonNull::new(element_ptr) else {
1717            return Err(ReflectError::OperationFailed {
1718                shape: frame.shape,
1719                operation: "failed to allocate memory for list element",
1720            });
1721        };
1722
1723        // Push a new frame for the element
1724        self.frames.push(Frame::new(
1725            PtrUninit::new(element_ptr),
1726            element_shape,
1727            FrameOwnership::Owned,
1728        ));
1729
1730        Ok(self)
1731    }
1732}
1733
1734////////////////////////////////////////////////////////////////////////////////////////////////////
1735// Maps
1736////////////////////////////////////////////////////////////////////////////////////////////////////
1737impl Partial<'_> {
1738    /// Begins a map initialization operation
1739    ///
1740    /// This initializes the map with default capacity and allows inserting key-value pairs
1741    /// It does _not_ push a new frame onto the stack.
1742    pub fn begin_map(&mut self) -> Result<&mut Self, ReflectError> {
1743        self.require_active()?;
1744        let frame = self.frames.last_mut().unwrap();
1745
1746        // Check that we have a Map
1747        let map_def = match &frame.shape.def {
1748            Def::Map(map_def) => map_def,
1749            _ => {
1750                return Err(ReflectError::OperationFailed {
1751                    shape: frame.shape,
1752                    operation: "begin_map can only be called on Map types",
1753                });
1754            }
1755        };
1756
1757        let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
1758
1759        // Initialize the map with default capacity (0)
1760        unsafe {
1761            init_fn(frame.data, 0);
1762        }
1763
1764        // Update tracker to Map state
1765        frame.tracker = Tracker::Map {
1766            is_initialized: true,
1767            insert_state: MapInsertState::Idle,
1768        };
1769
1770        Ok(self)
1771    }
1772
1773    /// Pushes a frame for the map key. After that, `set()` should be called
1774    /// (or the key should be initialized somehow) and `end()` should be called
1775    /// to pop the frame.
1776    pub fn begin_key(&mut self) -> Result<&mut Self, ReflectError> {
1777        self.require_active()?;
1778        let frame = self.frames.last_mut().unwrap();
1779
1780        // Check that we have a Map and set up for key insertion
1781        let map_def = match (&frame.shape.def, &mut frame.tracker) {
1782            (
1783                Def::Map(map_def),
1784                Tracker::Map {
1785                    is_initialized: true,
1786                    insert_state,
1787                },
1788            ) => {
1789                match insert_state {
1790                    MapInsertState::Idle => {
1791                        // Start a new insert automatically
1792                        *insert_state = MapInsertState::PushingKey { key_ptr: None };
1793                    }
1794                    MapInsertState::PushingKey { key_ptr } => {
1795                        if key_ptr.is_some() {
1796                            return Err(ReflectError::OperationFailed {
1797                                shape: frame.shape,
1798                                operation: "already pushing a key, call end() first",
1799                            });
1800                        }
1801                    }
1802                    _ => {
1803                        return Err(ReflectError::OperationFailed {
1804                            shape: frame.shape,
1805                            operation: "must complete current operation before begin_key()",
1806                        });
1807                    }
1808                }
1809                map_def
1810            }
1811            _ => {
1812                return Err(ReflectError::OperationFailed {
1813                    shape: frame.shape,
1814                    operation: "must call begin_map() before begin_key()",
1815                });
1816            }
1817        };
1818
1819        // Get the key shape
1820        let key_shape = map_def.k();
1821
1822        // Allocate space for the key
1823        let key_layout = match key_shape.layout.sized_layout() {
1824            Ok(layout) => layout,
1825            Err(_) => {
1826                return Err(ReflectError::Unsized {
1827                    shape: key_shape,
1828                    operation: "begin_key allocating key",
1829                });
1830            }
1831        };
1832        let key_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(key_layout) };
1833
1834        let Some(key_ptr_raw) = NonNull::new(key_ptr_raw) else {
1835            return Err(ReflectError::OperationFailed {
1836                shape: frame.shape,
1837                operation: "failed to allocate memory for map key",
1838            });
1839        };
1840
1841        // Store the key pointer in the insert state
1842        match &mut frame.tracker {
1843            Tracker::Map {
1844                insert_state: MapInsertState::PushingKey { key_ptr: kp },
1845                ..
1846            } => {
1847                *kp = Some(PtrUninit::new(key_ptr_raw));
1848            }
1849            _ => unreachable!(),
1850        }
1851
1852        // Push a new frame for the key
1853        self.frames.push(Frame::new(
1854            PtrUninit::new(key_ptr_raw),
1855            key_shape,
1856            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
1857        ));
1858
1859        Ok(self)
1860    }
1861
1862    /// Pushes a frame for the map value
1863    /// Must be called after the key has been set and popped
1864    pub fn begin_value(&mut self) -> Result<&mut Self, ReflectError> {
1865        self.require_active()?;
1866        let frame = self.frames.last_mut().unwrap();
1867
1868        // Check that we have a Map in PushingValue state
1869        let map_def = match (&frame.shape.def, &mut frame.tracker) {
1870            (
1871                Def::Map(map_def),
1872                Tracker::Map {
1873                    insert_state: MapInsertState::PushingValue { value_ptr, .. },
1874                    ..
1875                },
1876            ) => {
1877                if value_ptr.is_some() {
1878                    return Err(ReflectError::OperationFailed {
1879                        shape: frame.shape,
1880                        operation: "already pushing a value, call pop() first",
1881                    });
1882                }
1883                map_def
1884            }
1885            _ => {
1886                return Err(ReflectError::OperationFailed {
1887                    shape: frame.shape,
1888                    operation: "must complete key before push_value()",
1889                });
1890            }
1891        };
1892
1893        // Get the value shape
1894        let value_shape = map_def.v();
1895
1896        // Allocate space for the value
1897        let value_layout = match value_shape.layout.sized_layout() {
1898            Ok(layout) => layout,
1899            Err(_) => {
1900                return Err(ReflectError::Unsized {
1901                    shape: value_shape,
1902                    operation: "begin_value allocating value",
1903                });
1904            }
1905        };
1906        let value_ptr_raw: *mut u8 = unsafe { alloc::alloc::alloc(value_layout) };
1907
1908        let Some(value_ptr_raw) = NonNull::new(value_ptr_raw) else {
1909            return Err(ReflectError::OperationFailed {
1910                shape: frame.shape,
1911                operation: "failed to allocate memory for map value",
1912            });
1913        };
1914
1915        // Store the value pointer in the insert state
1916        match &mut frame.tracker {
1917            Tracker::Map {
1918                insert_state: MapInsertState::PushingValue { value_ptr: vp, .. },
1919                ..
1920            } => {
1921                *vp = Some(PtrUninit::new(value_ptr_raw));
1922            }
1923            _ => unreachable!(),
1924        }
1925
1926        // Push a new frame for the value
1927        self.frames.push(Frame::new(
1928            PtrUninit::new(value_ptr_raw),
1929            value_shape,
1930            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
1931        ));
1932
1933        Ok(self)
1934    }
1935}
1936
1937////////////////////////////////////////////////////////////////////////////////////////////////////
1938// Option / inner
1939////////////////////////////////////////////////////////////////////////////////////////////////////
1940impl Partial<'_> {
1941    /// Begin building the Some variant of an Option
1942    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
1943        self.require_active()?;
1944        let frame = self.frames.last_mut().unwrap();
1945
1946        // Verify we're working with an Option
1947        let option_def = match frame.shape.def {
1948            Def::Option(def) => def,
1949            _ => {
1950                return Err(ReflectError::WasNotA {
1951                    expected: "Option",
1952                    actual: frame.shape,
1953                });
1954            }
1955        };
1956
1957        // Initialize the tracker for Option building
1958        if matches!(frame.tracker, Tracker::Uninit) {
1959            frame.tracker = Tracker::Option {
1960                building_inner: true,
1961            };
1962        }
1963
1964        // Get the inner type shape
1965        let inner_shape = option_def.t;
1966
1967        // Allocate memory for the inner value
1968        let inner_layout =
1969            inner_shape
1970                .layout
1971                .sized_layout()
1972                .map_err(|_| ReflectError::Unsized {
1973                    shape: inner_shape,
1974                    operation: "begin_some, allocating Option inner value",
1975                })?;
1976
1977        let inner_data = if inner_layout.size() == 0 {
1978            // For ZST, use a non-null but unallocated pointer
1979            PtrUninit::new(NonNull::<u8>::dangling())
1980        } else {
1981            // Allocate memory for the inner value
1982            let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
1983            let Some(ptr) = NonNull::new(ptr) else {
1984                alloc::alloc::handle_alloc_error(inner_layout);
1985            };
1986            PtrUninit::new(ptr)
1987        };
1988
1989        // Create a new frame for the inner value
1990        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
1991        self.frames.push(inner_frame);
1992
1993        Ok(self)
1994    }
1995
1996    /// Begin building the inner value of a wrapper type
1997    pub fn begin_inner(&mut self) -> Result<&mut Self, ReflectError> {
1998        self.require_active()?;
1999
2000        // Get the inner shape and check for try_from
2001        let (inner_shape, has_try_from, parent_shape) = {
2002            let frame = self.frames.last().unwrap();
2003            if let Some(inner_shape) = frame.shape.inner {
2004                let has_try_from = frame.shape.vtable.try_from.is_some();
2005                (Some(inner_shape), has_try_from, frame.shape)
2006            } else {
2007                (None, false, frame.shape)
2008            }
2009        };
2010
2011        if let Some(inner_shape) = inner_shape {
2012            if has_try_from {
2013                // Create a conversion frame with the inner shape
2014
2015                // For conversion frames, we leave the parent tracker unchanged
2016                // This allows automatic conversion detection to work properly
2017
2018                // Allocate memory for the inner value (conversion source)
2019                let inner_layout =
2020                    inner_shape
2021                        .layout
2022                        .sized_layout()
2023                        .map_err(|_| ReflectError::Unsized {
2024                            shape: inner_shape,
2025                            operation: "begin_inner, getting inner layout",
2026                        })?;
2027
2028                let inner_data = if inner_layout.size() == 0 {
2029                    // For ZST, use a non-null but unallocated pointer
2030                    PtrUninit::new(NonNull::<u8>::dangling())
2031                } else {
2032                    // Allocate memory for the inner value
2033                    let ptr = unsafe { alloc::alloc::alloc(inner_layout) };
2034                    let Some(ptr) = NonNull::new(ptr) else {
2035                        alloc::alloc::handle_alloc_error(inner_layout);
2036                    };
2037                    PtrUninit::new(ptr)
2038                };
2039
2040                // For conversion frames, we create a frame directly with the inner shape
2041                // This allows setting values of the inner type which will be converted
2042                // The automatic conversion detection in end() will handle the conversion
2043                trace!(
2044                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
2045                );
2046                self.frames
2047                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
2048
2049                Ok(self)
2050            } else {
2051                // For wrapper types without try_from, navigate to the first field
2052                // This is a common pattern for newtype wrappers
2053                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
2054                self.begin_nth_field(0)
2055            }
2056        } else {
2057            Err(ReflectError::OperationFailed {
2058                shape: parent_shape,
2059                operation: "type does not have an inner value",
2060            })
2061        }
2062    }
2063}
2064
2065////////////////////////////////////////////////////////////////////////////////////////////////////
2066// Shorthands
2067////////////////////////////////////////////////////////////////////////////////////////////////////
2068impl<'facet> Partial<'facet> {
2069    /// Convenience shortcut: sets the field at index `idx` directly to value, popping after.
2070    ///
2071    /// Works on structs, enums (after selecting a variant) and arrays.
2072    pub fn set_nth_field<U>(&mut self, idx: usize, value: U) -> Result<&mut Self, ReflectError>
2073    where
2074        U: Facet<'facet>,
2075    {
2076        self.begin_nth_field(idx)?.set(value)?.end()
2077    }
2078
2079    /// Convenience shortcut: sets the named field to value, popping after.
2080    pub fn set_field<U>(&mut self, field_name: &str, value: U) -> Result<&mut Self, ReflectError>
2081    where
2082        U: Facet<'facet>,
2083    {
2084        self.begin_field(field_name)?.set(value)?.end()
2085    }
2086
2087    /// Convenience shortcut: sets the key for a map key-value insertion, then pops after.
2088    pub fn set_key<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2089    where
2090        U: Facet<'facet>,
2091    {
2092        self.begin_key()?.set(value)?.end()
2093    }
2094
2095    /// Convenience shortcut: sets the value for a map key-value insertion, then pops after.
2096    pub fn set_value<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2097    where
2098        U: Facet<'facet>,
2099    {
2100        self.begin_value()?.set(value)?.end()
2101    }
2102
2103    /// Shorthand for: begin_list_item(), set(), end()
2104    pub fn push<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2105    where
2106        U: Facet<'facet>,
2107    {
2108        self.begin_list_item()?.set(value)?.end()
2109    }
2110}
2111
2112////////////////////////////////////////////////////////////////////////////////////////////////////
2113// Internal methods
2114////////////////////////////////////////////////////////////////////////////////////////////////////
2115impl<'facet> Partial<'facet> {
2116    /// Preconditions:
2117    ///
2118    /// - `require_active()` check was made
2119    /// - frame.shape.ty is an Enum
2120    /// - `discriminant` is a valid discriminant
2121    ///
2122    /// Panics if current tracker is anything other than `Uninit`
2123    /// (switching variants is not supported for now).
2124    fn select_variant_internal(
2125        &mut self,
2126        enum_type: &EnumType,
2127        variant: &'static Variant,
2128    ) -> Result<(), ReflectError> {
2129        // Check all invariants early before making any changes
2130        let frame = self.frames.last().unwrap();
2131
2132        // Check enum representation early
2133        match enum_type.enum_repr {
2134            EnumRepr::RustNPO => {
2135                return Err(ReflectError::OperationFailed {
2136                    shape: frame.shape,
2137                    operation: "RustNPO enums are not supported for incremental building",
2138                });
2139            }
2140            EnumRepr::U8
2141            | EnumRepr::U16
2142            | EnumRepr::U32
2143            | EnumRepr::U64
2144            | EnumRepr::I8
2145            | EnumRepr::I16
2146            | EnumRepr::I32
2147            | EnumRepr::I64
2148            | EnumRepr::USize
2149            | EnumRepr::ISize => {
2150                // These are supported, continue
2151            }
2152        }
2153
2154        let Some(discriminant) = variant.discriminant else {
2155            return Err(ReflectError::OperationFailed {
2156                shape: frame.shape,
2157                operation: "trying to select an enum variant without a discriminant",
2158            });
2159        };
2160
2161        // All checks passed, now we can safely make changes
2162        let fr = self.frames.last_mut().unwrap();
2163
2164        // Write the discriminant to memory
2165        unsafe {
2166            match enum_type.enum_repr {
2167                EnumRepr::U8 => {
2168                    let ptr = fr.data.as_mut_byte_ptr();
2169                    *ptr = discriminant as u8;
2170                }
2171                EnumRepr::U16 => {
2172                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
2173                    *ptr = discriminant as u16;
2174                }
2175                EnumRepr::U32 => {
2176                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
2177                    *ptr = discriminant as u32;
2178                }
2179                EnumRepr::U64 => {
2180                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
2181                    *ptr = discriminant as u64;
2182                }
2183                EnumRepr::I8 => {
2184                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
2185                    *ptr = discriminant as i8;
2186                }
2187                EnumRepr::I16 => {
2188                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
2189                    *ptr = discriminant as i16;
2190                }
2191                EnumRepr::I32 => {
2192                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
2193                    *ptr = discriminant as i32;
2194                }
2195                EnumRepr::I64 => {
2196                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
2197                    *ptr = discriminant;
2198                }
2199                EnumRepr::USize => {
2200                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
2201                    *ptr = discriminant as usize;
2202                }
2203                EnumRepr::ISize => {
2204                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
2205                    *ptr = discriminant as isize;
2206                }
2207                _ => unreachable!("Already checked enum representation above"),
2208            }
2209        }
2210
2211        // Update tracker to track the variant
2212        fr.tracker = Tracker::Enum {
2213            variant,
2214            data: ISet::new(variant.data.fields.len()),
2215            current_child: None,
2216        };
2217
2218        Ok(())
2219    }
2220
2221    /// Used by `begin_field` etc. to get a list of fields to look through, errors out
2222    /// if we're not pointing to a struct or an enum with an already-selected variant
2223    fn get_fields(&self) -> Result<&'static [Field], ReflectError> {
2224        let frame = self.frames.last().unwrap();
2225        match frame.shape.ty {
2226            Type::Primitive(_) => Err(ReflectError::OperationFailed {
2227                shape: frame.shape,
2228                operation: "cannot select a field from a primitive type",
2229            }),
2230            Type::Sequence(_) => Err(ReflectError::OperationFailed {
2231                shape: frame.shape,
2232                operation: "cannot select a field from a sequence type",
2233            }),
2234            Type::User(user_type) => match user_type {
2235                UserType::Struct(struct_type) => Ok(struct_type.fields),
2236                UserType::Enum(_) => {
2237                    let Tracker::Enum { variant, .. } = &frame.tracker else {
2238                        return Err(ReflectError::OperationFailed {
2239                            shape: frame.shape,
2240                            operation: "must select variant before selecting enum fields",
2241                        });
2242                    };
2243                    Ok(variant.data.fields)
2244                }
2245                UserType::Union(_) => Err(ReflectError::OperationFailed {
2246                    shape: frame.shape,
2247                    operation: "cannot select a field from a union type",
2248                }),
2249                UserType::Opaque => Err(ReflectError::OperationFailed {
2250                    shape: frame.shape,
2251                    operation: "opaque types cannot be reflected upon",
2252                }),
2253            },
2254            Type::Pointer(_) => Err(ReflectError::OperationFailed {
2255                shape: frame.shape,
2256                operation: "cannot select a field from a pointer type",
2257            }),
2258        }
2259    }
2260
2261    /// Selects the nth field of a struct by index
2262    fn begin_nth_struct_field(
2263        frame: &mut Frame,
2264        struct_type: StructType,
2265        idx: usize,
2266    ) -> Result<Frame, ReflectError> {
2267        if idx >= struct_type.fields.len() {
2268            return Err(ReflectError::OperationFailed {
2269                shape: frame.shape,
2270                operation: "field index out of bounds",
2271            });
2272        }
2273        let field = &struct_type.fields[idx];
2274
2275        if !matches!(frame.tracker, Tracker::Struct { .. }) {
2276            frame.tracker = Tracker::Struct {
2277                iset: ISet::new(struct_type.fields.len()),
2278                current_child: None,
2279            }
2280        }
2281
2282        let was_field_init = match &mut frame.tracker {
2283            Tracker::Struct {
2284                iset,
2285                current_child,
2286            } => {
2287                *current_child = Some(idx);
2288                iset.get(idx)
2289            }
2290            _ => unreachable!(),
2291        };
2292
2293        // Push a new frame for this field onto the frames stack.
2294        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
2295        let field_shape = field.shape();
2296
2297        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
2298        if was_field_init {
2299            unsafe {
2300                // the struct field tracker said so!
2301                next_frame.mark_as_init();
2302            }
2303        }
2304
2305        Ok(next_frame)
2306    }
2307
2308    /// Selects the nth element of an array by index
2309    fn begin_nth_array_element(
2310        frame: &mut Frame,
2311        array_type: ArrayType,
2312        idx: usize,
2313    ) -> Result<Frame, ReflectError> {
2314        if idx >= array_type.n {
2315            return Err(ReflectError::OperationFailed {
2316                shape: frame.shape,
2317                operation: "array index out of bounds",
2318            });
2319        }
2320
2321        if array_type.n > 63 {
2322            return Err(ReflectError::OperationFailed {
2323                shape: frame.shape,
2324                operation: "arrays larger than 63 elements are not yet supported",
2325            });
2326        }
2327
2328        // Ensure frame is in Array state
2329        match &frame.tracker {
2330            Tracker::Uninit => {
2331                // this is fine
2332                frame.tracker = Tracker::Array {
2333                    iset: ISet::default(),
2334                    current_child: None,
2335                };
2336            }
2337            Tracker::Array { .. } => {
2338                // fine too
2339            }
2340            _other => {
2341                return Err(ReflectError::OperationFailed {
2342                    shape: frame.shape,
2343                    operation: "unexpected tracker state: expected Uninit or Array",
2344                });
2345            }
2346        }
2347
2348        match &mut frame.tracker {
2349            Tracker::Array {
2350                iset,
2351                current_child,
2352            } => {
2353                *current_child = Some(idx);
2354                let was_field_init = iset.get(idx);
2355
2356                // Calculate the offset for this array element
2357                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
2358                    return Err(ReflectError::Unsized {
2359                        shape: array_type.t,
2360                        operation: "begin_nth_element, calculating array element offset",
2361                    });
2362                };
2363                let offset = element_layout.size() * idx;
2364                let element_data = unsafe { frame.data.field_uninit_at(offset) };
2365
2366                let mut next_frame = Frame::new(element_data, array_type.t, FrameOwnership::Field);
2367                if was_field_init {
2368                    // safety: `iset` said it was initialized already
2369                    unsafe {
2370                        next_frame.mark_as_init();
2371                    }
2372                }
2373                Ok(next_frame)
2374            }
2375            _ => unreachable!(),
2376        }
2377    }
2378
2379    /// Selects the nth field of an enum variant by index
2380    fn begin_nth_enum_field(
2381        frame: &mut Frame,
2382        variant: &'static Variant,
2383        idx: usize,
2384    ) -> Result<Frame, ReflectError> {
2385        if idx >= variant.data.fields.len() {
2386            return Err(ReflectError::OperationFailed {
2387                shape: frame.shape,
2388                operation: "enum field index out of bounds",
2389            });
2390        }
2391
2392        let field = &variant.data.fields[idx];
2393
2394        // Update tracker
2395        let was_field_init = match &mut frame.tracker {
2396            Tracker::Enum {
2397                data,
2398                current_child,
2399                ..
2400            } => {
2401                *current_child = Some(idx);
2402                data.get(idx)
2403            }
2404            _ => {
2405                return Err(ReflectError::OperationFailed {
2406                    shape: frame.shape,
2407                    operation: "selecting a field on an enum requires selecting a variant first",
2408                });
2409            }
2410        };
2411
2412        // SAFETY: the field offset comes from an unsafe impl of the Facet trait, we trust it.
2413        // also, we checked that the variant was selected.
2414        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
2415        let field_shape = field.shape();
2416
2417        let mut next_frame = Frame::new(field_ptr, field_shape, FrameOwnership::Field);
2418        if was_field_init {
2419            // SAFETY: `ISet` told us the field was initialized
2420            unsafe {
2421                next_frame.mark_as_init();
2422            }
2423        }
2424
2425        Ok(next_frame)
2426    }
2427
2428    /// Require that the partial is active
2429    #[inline]
2430    pub(crate) fn require_active(&self) -> Result<(), ReflectError> {
2431        if self.state == PartialState::Active {
2432            Ok(())
2433        } else {
2434            Err(ReflectError::InvariantViolation {
2435                invariant: "Cannot use Partial after it has been built or poisoned",
2436            })
2437        }
2438    }
2439}