facet_reflect/wip/
mod.rs

1use crate::{ReflectError, ValueId};
2use crate::{debug, trace};
3#[cfg(feature = "log")]
4use alloc::string::ToString;
5#[cfg(feature = "log")]
6use owo_colors::OwoColorize;
7
8use alloc::format;
9use alloc::{vec, vec::Vec};
10use bitflags::bitflags;
11use core::{fmt, marker::PhantomData};
12use facet_core::{
13    Def, DefaultInPlaceFn, Facet, FieldError, PtrConst, PtrMut, PtrUninit, ScalarAffinity, Shape,
14    Variant,
15};
16use flat_map::FlatMap;
17
18use alloc::string::String;
19
20mod iset;
21pub use iset::*;
22
23mod put_f64;
24
25mod enum_;
26mod flat_map;
27
28mod heap_value;
29pub use heap_value::*;
30
31fn def_kind(def: &Def) -> &'static str {
32    match def {
33        Def::Scalar(_) => "scalar",
34        Def::Struct(_) => "struct",
35        Def::Map(_) => "map",
36        Def::List(_) => "list",
37        Def::Enum(_) => "enum",
38        Def::Option(_) => "option",
39        Def::SmartPointer(_) => "smart_ptr",
40        _ => "other",
41    }
42}
43
44/// Represents a frame in the initialization stack
45pub struct Frame {
46    /// The value we're initializing
47    data: PtrUninit<'static>,
48
49    /// The shape of the value
50    shape: &'static Shape,
51
52    /// If set, when we're initialized, we must mark the
53    /// parent's indexth field as initialized.
54    field_index_in_parent: Option<usize>,
55
56    /// Tracking which of our fields are initialized
57    /// TODO: I'm not sure we should track "ourselves" as initialized — we always have the
58    /// parent to look out for, right now we're tracking children in two states, which isn't ideal
59    istate: IState,
60}
61
62impl Frame {
63    /// Given a ValueId and an IState, recompose a Frame suitable for tracking
64    fn recompose(id: ValueId, istate: IState) -> Self {
65        Frame {
66            data: PtrUninit::new(id.ptr as *mut u8),
67            shape: id.shape,
68            field_index_in_parent: None,
69            istate,
70        }
71    }
72
73    /// Deallocates the memory used by this frame if it was heap-allocated.
74    fn dealloc_if_needed(&mut self) {
75        if self.istate.flags.contains(FrameFlags::ALLOCATED) {
76            trace!(
77                "[{}] {:p} => deallocating {}",
78                self.istate.depth,
79                self.data.as_mut_byte_ptr().magenta(),
80                self.shape.green(),
81            );
82            match self.shape.layout {
83                facet_core::ShapeLayout::Sized(layout) => {
84                    if layout.size() != 0 {
85                        unsafe {
86                            alloc::alloc::dealloc(self.data.as_mut_byte_ptr(), layout);
87                        }
88                    }
89                }
90                facet_core::ShapeLayout::Unsized => unimplemented!(),
91            }
92            self.istate.flags.remove(FrameFlags::ALLOCATED);
93        } else {
94            trace!(
95                "[{}] {:p} => NOT deallocating {} (not ALLOCATED)",
96                self.istate.depth,
97                self.data.as_mut_byte_ptr().magenta(),
98                self.shape.green(),
99            );
100        }
101    }
102}
103
104struct DisplayToDebug<T>(T);
105
106impl<T> fmt::Debug for DisplayToDebug<T>
107where
108    T: fmt::Display,
109{
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        fmt::Display::fmt(&self.0, f)
112    }
113}
114
115impl fmt::Debug for Frame {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("Frame")
118            .field("shape", &DisplayToDebug(&self.shape))
119            .field("kind", &def_kind(&self.shape.def))
120            .field("index", &self.field_index_in_parent)
121            .field("mode", &self.istate.mode)
122            .field("id", &self.id())
123            .finish()
124    }
125}
126
127impl Frame {
128    /// Returns the value ID for a frame
129    fn id(&self) -> ValueId {
130        ValueId::new(self.shape, self.data.as_byte_ptr())
131    }
132
133    /// Returns true if the frame is fully initialized
134    fn is_fully_initialized(&self) -> bool {
135        match self.shape.def {
136            Def::Struct(sd) => self.istate.fields.are_all_set(sd.fields.len()),
137            Def::Enum(_) => match self.istate.variant.as_ref() {
138                None => false,
139                Some(v) => self.istate.fields.are_all_set(v.data.fields.len()),
140            },
141            _ => self.istate.fields.are_all_set(1),
142        }
143    }
144
145    // Safety: only call if is fully initialized
146    unsafe fn drop_and_dealloc_if_needed(mut self) {
147        trace!(
148            "[Frame::drop] Dropping frame for shape {} at {:p}",
149            self.shape.blue(),
150            self.data.as_byte_ptr()
151        );
152        if let Some(drop_in_place) = self.shape.vtable.drop_in_place {
153            unsafe {
154                trace!(
155                    "[Frame::drop] Invoking drop_in_place for shape {} at {:p}",
156                    self.shape.green(),
157                    self.data.as_byte_ptr()
158                );
159                drop_in_place(self.data.assume_init());
160            }
161        } else {
162            trace!(
163                "[Frame::drop] No drop_in_place function for shape {}",
164                self.shape.blue(),
165            );
166        }
167        self.dealloc_if_needed();
168    }
169
170    /// Marks the frame as fully initialized
171    unsafe fn mark_fully_initialized(&mut self) {
172        match self.shape.def {
173            Def::Struct(sd) => {
174                self.istate.fields = ISet::all(sd.fields);
175            }
176            Def::Enum(_) => {
177                if let Some(variant) = &self.istate.variant {
178                    self.istate.fields = ISet::all(variant.data.fields);
179                }
180            }
181            _ => {
182                self.istate.fields.set(0);
183            }
184        }
185    }
186}
187
188/// Initialization state
189struct IState {
190    /// Variant chosen — for everything except enums, this stays None
191    variant: Option<Variant>,
192
193    /// Fields that were initialized. For scalars, we only track 0
194    fields: ISet,
195
196    /// The depth of the frame in the stack
197    depth: usize,
198
199    /// The special mode of this frame (if any)
200    mode: FrameMode,
201
202    /// If true, must be freed when dropped
203    flags: FrameFlags,
204
205    /// The current index for list elements
206    list_index: Option<usize>,
207
208    /// The current key for map elements
209    #[allow(dead_code)]
210    map_key: Option<String>,
211}
212
213bitflags! {
214    /// Flags that can be applied to frames
215    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
216    pub struct FrameFlags: u64 {
217        /// An empty set of flags
218        const EMPTY = 0;
219
220        /// We allocated this frame on the heap, we need to deallocated it when popping
221        const ALLOCATED = 1 << 0;
222
223        /// This value was moved out of — it's not part of the value we're building and
224        /// we shouldn't error out when we build and we notice it's not initialized.
225        /// In fact, it should not be tracked at all.
226        const MOVED = 1 << 1;
227    }
228
229    // Note: there is no 'initialized' flag because initialization can be partial — it's tracked via `ISet`
230}
231
232impl IState {
233    /// Creates a new `IState` with the given depth.
234    pub fn new(depth: usize, mode: FrameMode, flags: FrameFlags) -> Self {
235        Self {
236            variant: None,
237            fields: Default::default(),
238            depth,
239            mode,
240            flags,
241            list_index: None,
242            map_key: None,
243        }
244    }
245
246    /// Sets the list index and returns self for method chaining
247    #[allow(dead_code)]
248    pub fn with_list_index(mut self, index: usize) -> Self {
249        self.list_index = Some(index);
250        self
251    }
252
253    /// Sets the map key and returns self for method chaining
254    #[allow(dead_code)]
255    pub fn with_map_key(mut self, key: String) -> Self {
256        self.map_key = Some(key);
257        self
258    }
259}
260
261/// Represents the special mode a frame can be in
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum FrameMode {
264    /// Root frame
265    Root,
266    /// Struct field
267    Field,
268    /// Frame represents a list element
269    ListElement,
270    /// Frame represents a map key
271    MapKey,
272    /// Frame represents a map value with the given key frame index
273    MapValue {
274        /// The index of the key frame associated with this map value
275        index: usize,
276    },
277    /// Frame represents the Some variant of an option (that we allocated)
278    OptionSome,
279    /// Frame represents the None variant of an option (no allocation needed)
280    /// Any `put` should fail
281    OptionNone,
282}
283
284/// A work-in-progress heap-allocated value
285pub struct Wip<'facet_lifetime> {
286    /// stack of frames to keep track of deeply nested initialization
287    frames: alloc::vec::Vec<Frame>,
288
289    /// keeps track of initialization of out-of-tree frames
290    istates: FlatMap<ValueId, IState>,
291
292    invariant: PhantomData<fn(&'facet_lifetime ()) -> &'facet_lifetime ()>,
293}
294
295impl<'facet_lifetime> Wip<'facet_lifetime> {
296    /// Puts the value from a Peek into the current frame.
297    pub fn put_peek(
298        self,
299        peek: crate::Peek<'_, 'facet_lifetime>,
300    ) -> Result<Wip<'facet_lifetime>, ReflectError> {
301        self.put_shape(peek.data, peek.shape)
302    }
303
304    /// Returns the number of frames on the stack
305    pub fn frames_count(&self) -> usize {
306        self.frames.len()
307    }
308
309    /// Allocates a new value of the given shape
310    pub fn alloc_shape(shape: &'static Shape) -> Result<Self, ReflectError> {
311        let data = shape
312            .allocate()
313            .map_err(|_| ReflectError::Unsized { shape })?;
314        Ok(Self {
315            frames: alloc::vec![Frame {
316                data,
317                shape,
318                field_index_in_parent: None,
319                istate: IState::new(0, FrameMode::Root, FrameFlags::ALLOCATED),
320            }],
321            istates: Default::default(),
322            invariant: PhantomData,
323        })
324    }
325
326    /// Allocates a new value of type `S`
327    pub fn alloc<S: Facet<'facet_lifetime>>() -> Result<Self, ReflectError> {
328        Self::alloc_shape(S::SHAPE)
329    }
330
331    fn track(&mut self, frame: Frame) {
332        // fields might be partially initialized (in-place) and then
333        // we might come back to them, so because they're popped off
334        // the stack, we still need to track them _somewhere_
335        //
336        // the root also relies on being tracked in the drop impl
337        if frame.istate.flags.contains(FrameFlags::MOVED) {
338            // don't track those
339            return;
340        }
341
342        self.istates.insert(frame.id(), frame.istate);
343    }
344
345    unsafe fn mark_moved_out_of(&mut self, frame: &mut Frame) {
346        // Recursively mark `istates` entries as MOVED and deallocate. Needed because
347        // descendant values might be tracked separately in `istates`.
348        unsafe fn mark_subtree_moved(wip: &mut Wip, id: ValueId) {
349            // Function requires unsafe due to pointer manipulation and potential deallocation.
350            unsafe {
351                // Process only if the value is still tracked off-stack.
352                if let Some(mut istate) = wip.istates.remove(&id) {
353                    // Ensure value is marked as MOVED.
354                    istate.flags.insert(FrameFlags::MOVED);
355
356                    // Ensure all owned fields within structs/enums are also marked.
357                    match id.shape.def {
358                        Def::Struct(sd) => {
359                            let container_ptr = PtrUninit::new(id.ptr as *mut u8);
360                            for field in sd.fields.iter() {
361                                let field_ptr_uninit = container_ptr.field_uninit_at(field.offset);
362                                let field_id =
363                                    ValueId::new(field.shape(), field_ptr_uninit.as_byte_ptr());
364                                // Recurse.
365                                mark_subtree_moved(wip, field_id);
366                            }
367                        }
368                        Def::Enum(_) => {
369                            // Use the variant info from the processed istate.
370                            if let Some(variant) = &istate.variant {
371                                let container_ptr = PtrUninit::new(id.ptr as *mut u8);
372                                for field in variant.data.fields.iter() {
373                                    let field_ptr_uninit =
374                                        container_ptr.field_uninit_at(field.offset);
375                                    let field_id =
376                                        ValueId::new(field.shape(), field_ptr_uninit.as_byte_ptr());
377                                    // Recurse.
378                                    mark_subtree_moved(wip, field_id);
379                                }
380                            }
381                        }
382                        // Only recurse for direct fields (struct/enum). Other owned values
383                        // (list elements, map entries, option Some payload) are handled
384                        // individually when *their* ValueId is processed, if tracked.
385                        _ => {}
386                    }
387
388                    // Prevent memory leaks for heap-allocated values that are now moved.
389                    // Only deallocate AFTER recursively processing child fields to prevent use-after-free.
390                    if istate.flags.contains(FrameFlags::ALLOCATED) {
391                        // `dealloc_if_needed` needs a `Frame`.
392                        let mut temp_frame = Frame::recompose(id, istate);
393                        temp_frame.dealloc_if_needed();
394                    }
395                }
396                // If istate wasn't found, value was already handled or not tracked off-stack.
397            }
398        }
399
400        // Function requires unsafe due to pointer manipulation, potential deallocation,
401        // and calling other unsafe functions/methods.
402        unsafe {
403            // 1. Process the primary frame being moved: mark MOVED, clear state
404            let frame_id = frame.id();
405
406            // Save variant information for recursive processing before we clear it
407            let variant_opt = frame.istate.variant;
408
409            // Mark as MOVED and clear any initialization progress.
410            frame.istate.flags.insert(FrameFlags::MOVED);
411            ISet::clear(&mut frame.istate.fields);
412
413            // 2. Recursively mark descendants (struct/enum fields) in `istates` as MOVED.
414            // This ensures consistency if fields were pushed/popped and stored in `istates`.
415            match frame.shape.def {
416                Def::Struct(sd) => {
417                    let container_ptr = PtrUninit::new(frame_id.ptr as *mut u8);
418                    for field in sd.fields.iter() {
419                        let field_ptr_uninit = container_ptr.field_uninit_at(field.offset);
420                        let field_id = ValueId::new(field.shape(), field_ptr_uninit.as_byte_ptr());
421                        mark_subtree_moved(self, field_id);
422                    }
423                }
424                Def::Enum(_) => {
425                    // Use the saved variant information for recursion
426                    if let Some(variant) = &variant_opt {
427                        let container_ptr = PtrUninit::new(frame_id.ptr as *mut u8);
428                        for field in variant.data.fields.iter() {
429                            let field_ptr_uninit = container_ptr.field_uninit_at(field.offset);
430                            let field_id =
431                                ValueId::new(field.shape(), field_ptr_uninit.as_byte_ptr());
432                            mark_subtree_moved(self, field_id);
433                        }
434                    }
435                }
436                // Other types don't have direct fields requiring recursive marking here.
437                _ => {}
438            }
439
440            // Now clear the variant after processing is done
441            frame.istate.variant = None;
442
443            // Untrack the frame in `istates`
444            self.istates.remove(&frame_id);
445
446            // Deallocate AFTER all processing is complete to prevent use-after-free
447            if frame.istate.flags.contains(FrameFlags::ALLOCATED) {
448                frame.dealloc_if_needed();
449            }
450        }
451    }
452
453    /// Returns the shape of the current frame
454    pub fn shape(&self) -> &'static Shape {
455        self.frames.last().expect("must have frames left").shape
456    }
457
458    /// Returns the innermost shape for the current frame
459    /// If the current shape is a transparent wrapper, this returns the shape of the wrapped type
460    /// Otherwise, returns the current shape
461    pub fn innermost_shape(&self) -> &'static Shape {
462        let mut current_shape = self.shape();
463
464        // Keep unwrapping as long as we find inner shapes
465        while let Some(inner_fn) = current_shape.inner {
466            current_shape = inner_fn();
467        }
468
469        current_shape
470    }
471
472    /// Return true if the last frame is in option mode
473    pub fn in_option(&self) -> bool {
474        let Some(frame) = self.frames.last() else {
475            return false;
476        };
477        matches!(frame.istate.mode, FrameMode::OptionSome)
478    }
479
480    /// Returns the mode of the current frame
481    pub fn mode(&self) -> FrameMode {
482        self.frames.last().unwrap().istate.mode
483    }
484
485    /// Asserts everything is initialized and that invariants are upheld (if any)
486    pub fn build(mut self) -> Result<HeapValue<'facet_lifetime>, ReflectError> {
487        debug!("[{}] ⚒️ It's BUILD time", self.frames.len());
488
489        // 1. Require that there is exactly one frame on the stack (the root frame)
490        if self.frames.is_empty() {
491            panic!("No frames in WIP during build: stack is empty (you popped too much)");
492        }
493        if self.frames.len() != 1 {
494            panic!(
495                "You must pop frames so that only the root frame remains before calling build (frames left: {})",
496                self.frames.len()
497            );
498        }
499
500        // now the root frame is at index 0
501        let root_frame = &self.frames[0];
502
503        enum FrameRef {
504            Root,
505            ById(ValueId),
506        }
507        let mut to_check = alloc::vec![FrameRef::Root];
508
509        // 4. Traverse the tree
510        while let Some(fr) = to_check.pop() {
511            let (id, istate) = match fr {
512                FrameRef::Root => (root_frame.id(), &root_frame.istate),
513                FrameRef::ById(id) => {
514                    // Look up the istate for the frame with this ValueId.
515                    let istate = self.istates.get(&id).unwrap();
516                    (id, istate)
517                }
518            };
519
520            trace!(
521                "Checking shape {} at {:p}, flags={:?}, mode={:?}",
522                id.shape.blue(),
523                id.ptr,
524                istate.flags.bright_magenta(),
525                istate.mode,
526            );
527
528            // Skip moved frames
529            if istate.flags.contains(FrameFlags::MOVED) {
530                trace!(
531                    "{}",
532                    "Frame was moved out of, skipping initialization check".yellow()
533                );
534                continue;
535            }
536
537            // Check initialization for the current frame
538            match id.shape.def {
539                Def::Struct(sd) => {
540                    // find the field that's not initialized
541                    for i in 0..sd.fields.len() {
542                        if !istate.fields.has(i) {
543                            let field = &sd.fields[i];
544                            return Err(ReflectError::UninitializedField {
545                                shape: id.shape,
546                                field_name: field.name,
547                            });
548                        }
549                    }
550
551                    let container_ptr = PtrUninit::new(id.ptr as *mut u8);
552
553                    // If initialized, push children to check stack
554                    #[allow(clippy::unused_enumerate_index)]
555                    for (_i, field) in sd.fields.iter().enumerate() {
556                        let field_shape = field.shape();
557                        let field_ptr = unsafe { container_ptr.field_init_at(field.offset) };
558                        let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
559
560                        if self.istates.contains_key(&field_id) {
561                            debug!(
562                                "Queueing struct field check: #{} '{}' of {}: shape={}, ptr={:p}",
563                                _i.to_string().bright_cyan(),
564                                field.name.bright_blue(),
565                                id.shape.blue(),
566                                field_shape.green(),
567                                field_ptr.as_byte_ptr()
568                            );
569                            to_check.push(FrameRef::ById(field_id));
570                        }
571                    }
572                }
573                Def::Enum(_ed) => {
574                    if let Some(variant) = &istate.variant {
575                        // Check each field, just like for structs
576                        for (i, field) in variant.data.fields.iter().enumerate() {
577                            if !istate.fields.has(i) {
578                                return Err(ReflectError::UninitializedEnumField {
579                                    shape: id.shape,
580                                    variant_name: variant.name,
581                                    field_name: field.name,
582                                });
583                            }
584                        }
585
586                        // All fields initialized, push children to check stack
587                        #[allow(clippy::unused_enumerate_index)]
588                        for (_i, field) in variant.data.fields.iter().enumerate() {
589                            let field_shape = field.shape();
590                            let container_ptr = PtrUninit::new(id.ptr as *mut u8);
591                            // We're in an enum, so get the field ptr out of the variant's payload
592                            let field_ptr = unsafe { container_ptr.field_init_at(field.offset) };
593                            let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
594
595                            if self.istates.contains_key(&field_id) {
596                                debug!(
597                                    "Queueing enum field check: #{} '{}' of variant '{}' of {}: shape={}, ptr={:p}",
598                                    _i.to_string().bright_cyan(),
599                                    field.name.bright_blue(),
600                                    variant.name.yellow(),
601                                    id.shape.blue(),
602                                    field_shape.green(),
603                                    field_ptr.as_byte_ptr()
604                                );
605                                to_check.push(FrameRef::ById(field_id));
606                            }
607                        }
608                    } else {
609                        // No variant selected is an error during build
610                        debug!("Found no variant selected for enum");
611                        return Err(ReflectError::NoVariantSelected { shape: id.shape });
612                    }
613                }
614                // For types that manage their own contents (List, Map, Option, Scalar, etc.),
615                // we just need to check if the *container* itself is marked as initialized.
616                // The recursive check handles struct/enum *elements* within these containers if they exist.
617                Def::List(_)
618                | Def::Map(_)
619                | Def::Option(_)
620                | Def::Scalar(_)
621                | Def::FunctionPointer(_)
622                | Def::SmartPointer(_)
623                | Def::Array(_)
624                | Def::Slice(_) => {
625                    if !istate.fields.are_all_set(1) {
626                        // Check specific modes for better errors
627                        match istate.mode {
628                            FrameMode::OptionNone => {
629                                // This should technically be marked initialized, but if not, treat as uninit Option
630                                debug!("Found uninitialized value (option none)");
631                                return Err(ReflectError::UninitializedValue { shape: id.shape });
632                            }
633                            // Add more specific checks if needed, e.g., for lists/maps that started but weren't finished?
634                            _ => {
635                                debug!("Found uninitialized value (list/map/option/etc.)");
636                                return Err(ReflectError::UninitializedValue { shape: id.shape });
637                            }
638                        }
639                    }
640                    // No children to push onto `to_check` from the perspective of the *container* frame itself.
641                    // If a List contains Structs, those struct frames would have been pushed/popped
642                    // and their states tracked individually in `istates`, and checked when encountered via
643                    // `to_check` if they were fields of another struct/enum.
644                    // The `Drop` logic handles cleaning these contained items based on the container's drop_in_place.
645                    // For `build`, we trust that if the container is marked initialized, its contents are valid
646                    // according to its type's rules.
647                }
648                // Handle other Def variants if necessary
649                _ => {
650                    // Default: Check if initialized using the standard method
651                    if !istate.fields.are_all_set(1) {
652                        debug!("Found uninitialized value (other)");
653                        return Err(ReflectError::UninitializedValue { shape: id.shape });
654                    }
655                }
656            }
657        }
658
659        // If we finished the loop, all reachable and non-moved frames are initialized.
660        debug!("All reachable frames checked and initialized.");
661
662        // 5. Check invariants on the root
663        // We have already checked root is fully initialized above, so we only need to check its invariants.
664        let root_shape = root_frame.shape;
665        let root_data = unsafe { root_frame.data.assume_init() };
666        if let Some(invariant_fn) = root_shape.vtable.invariants {
667            debug!(
668                "Checking invariants for root shape {} at {:p}",
669                root_shape.green(),
670                root_data.as_byte_ptr()
671            );
672            if !unsafe { invariant_fn(PtrConst::new(root_data.as_byte_ptr())) } {
673                return Err(ReflectError::InvariantViolation {
674                    invariant: "Custom validation function returned false",
675                });
676            }
677        } else {
678            debug!(
679                "No invariants to check for root shape {}",
680                root_shape.blue()
681            );
682        }
683
684        // Prevent Drop from running on the successfully built value.
685        {
686            FlatMap::clear(&mut self.istates);
687            self.frames.clear();
688        }
689
690        // Build the guard from the root data.
691        let guard = Guard {
692            ptr: root_data.as_mut_byte_ptr(),
693            layout: match root_shape.layout {
694                facet_core::ShapeLayout::Sized(layout) => layout,
695                facet_core::ShapeLayout::Unsized => panic!("Unsized layout not supported"),
696            },
697        };
698
699        Ok(HeapValue {
700            guard: Some(guard),
701            shape: root_shape,
702            phantom: PhantomData,
703        })
704    }
705
706    /// Selects a field of a struct or enum variant by index and pushes it onto the frame stack.
707    ///
708    /// # Arguments
709    ///
710    /// * `index` - The index of the field to select.
711    ///
712    /// # Returns
713    ///
714    /// * `Ok(Self)` if the field was successfully selected and pushed.
715    /// * `Err(ReflectError)` if the current frame is not a struct or an enum with a selected variant,
716    ///   or if the field doesn't exist.
717    pub fn field(mut self, index: usize) -> Result<Self, ReflectError> {
718        let frame = self.frames.last_mut().unwrap();
719        let shape = frame.shape;
720
721        let (field, field_offset) = match shape.def {
722            Def::Struct(def) => {
723                if index >= def.fields.len() {
724                    return Err(ReflectError::FieldError {
725                        shape,
726                        field_error: FieldError::NoSuchField,
727                    });
728                }
729                let field = &def.fields[index];
730                (field, field.offset)
731            }
732            Def::Enum(_) => {
733                let Some(variant) = frame.istate.variant.as_ref() else {
734                    return Err(ReflectError::OperationFailed {
735                        shape,
736                        operation: "tried to access a field but no variant was selected",
737                    });
738                };
739
740                if index >= variant.data.fields.len() {
741                    return Err(ReflectError::FieldError {
742                        shape,
743                        field_error: FieldError::NoSuchField,
744                    });
745                }
746
747                let field = &variant.data.fields[index];
748                (field, field.offset)
749            }
750            _ => {
751                return Err(ReflectError::WasNotA {
752                    expected: "struct or enum",
753                    actual: shape,
754                });
755            }
756        };
757
758        let field_data = unsafe { frame.data.field_uninit_at(field_offset) };
759
760        let mut frame = Frame {
761            data: field_data,
762            shape: field.shape(),
763            field_index_in_parent: Some(index),
764            // we didn't have to allocate that field, it's a struct field, so it's not allocated
765            istate: IState::new(self.frames.len(), FrameMode::Field, FrameFlags::EMPTY),
766        };
767        debug!(
768            "[{}] Selecting field {} ({}#{}) of {}",
769            self.frames.len(),
770            field.name.blue(),
771            field.shape().green(),
772            index.yellow(),
773            shape.blue(),
774        );
775        if let Some(iset) = self.istates.remove(&frame.id()) {
776            trace!(
777                "[{}] Restoring saved state for {} (istate.mode = {:?}, istate.fields = {:?}, istate.flags = {:?}, istate.depth = {:?})",
778                self.frames.len(),
779                frame.id().shape.blue(),
780                iset.mode,
781                iset.fields,
782                iset.flags,
783                iset.depth
784            );
785            frame.istate = iset;
786        } else {
787            trace!(
788                "[{}] no saved state for field {} ({}#{}) of {}",
789                self.frames.len(),
790                field.name.blue(),
791                field.shape().green(),
792                index.yellow(),
793                shape.blue(),
794            );
795        }
796        self.frames.push(frame);
797        Ok(self)
798    }
799
800    /// Finds the index of a field in a struct or enum variant by name.
801    ///
802    /// # Arguments
803    ///
804    /// * `name` - The name of the field to find.
805    ///
806    /// # Returns
807    ///
808    /// * `Some(usize)` if the field was found.
809    /// * `None` if the current frame is not a struct or an enum with a selected variant,
810    ///   or if the field doesn't exist.
811    pub fn field_index(&self, name: &str) -> Option<usize> {
812        fn find_field_index(fields: &'static [facet_core::Field], name: &str) -> Option<usize> {
813            fields.iter().position(|f| f.name == name)
814        }
815
816        let frame = self.frames.last()?;
817        match frame.shape.def {
818            Def::Struct(def) => find_field_index(def.fields, name),
819            Def::Enum(_) => {
820                let variant = frame.istate.variant.as_ref()?;
821                find_field_index(variant.data.fields, name)
822            }
823            _ => None,
824        }
825    }
826
827    /// Selects a field of a struct or enum variant by name and pushes it onto the frame stack.
828    ///
829    /// # Arguments
830    ///
831    /// * `name` - The name of the field to select.
832    ///
833    /// # Returns
834    ///
835    /// * `Ok(Self)` if the field was successfully selected and pushed.
836    /// * `Err(ReflectError)` if the current frame is not a struct or an enum with a selected variant,
837    ///   or if the field doesn't exist.
838    pub fn field_named(self, name: &str) -> Result<Self, ReflectError> {
839        let frame = self.frames.last().unwrap();
840        let shape = frame.shape;
841
842        // For enums, ensure a variant is selected
843        if let Def::Enum(_) = shape.def {
844            if frame.istate.variant.is_none() {
845                return Err(ReflectError::OperationFailed {
846                    shape,
847                    operation: "tried to access a field by name but no variant was selected",
848                });
849            }
850        }
851
852        let index = self.field_index(name).ok_or(ReflectError::FieldError {
853            shape,
854            field_error: FieldError::NoSuchField,
855        })?;
856
857        self.field(index)
858    }
859
860    /// Puts a value of type `T` into the current frame.
861    ///
862    /// # Arguments
863    ///
864    /// * `t` - The value to put into the frame.
865    ///
866    /// # Returns
867    ///
868    /// * `Ok(Self)` if the value was successfully put into the frame.
869    /// * `Err(ReflectError)` if there was an error putting the value into the frame.
870    pub fn put<T: Facet<'facet_lifetime>>(
871        self,
872        t: T,
873    ) -> Result<Wip<'facet_lifetime>, ReflectError> {
874        let shape = T::SHAPE;
875        let ptr_const = PtrConst::new(&t as *const T as *const u8);
876        let res = self.put_shape(ptr_const, shape);
877        core::mem::forget(t); // avoid double drop; ownership moved into Wip
878        res
879    }
880
881    /// Puts a value of type `T` into the current frame.
882    ///
883    /// # Arguments
884    ///
885    /// * `t` - The value to put into the frame.
886    ///
887    /// # Returns
888    ///
889    /// * `Ok(Self)` if the value was successfully put into the frame.
890    /// * `Err(ReflectError)` if there was an error putting the value into the frame.
891    pub fn try_put<T: Facet<'facet_lifetime>>(
892        self,
893        t: T,
894    ) -> Result<Wip<'facet_lifetime>, ReflectError> {
895        let shape = T::SHAPE;
896        let ptr_const = PtrConst::new(&t as *const T as *const u8);
897        let res = self.put_shape(ptr_const, shape);
898        core::mem::forget(t); // avoid double drop; ownership moved into Wip
899        res
900    }
901
902    /// Puts a value from a `PtrConst` with the given shape into the current frame.
903    pub fn put_shape(
904        mut self,
905        src: PtrConst<'_>,
906        src_shape: &'static Shape,
907    ) -> Result<Wip<'facet_lifetime>, ReflectError> {
908        let Some(frame) = self.frames.last_mut() else {
909            return Err(ReflectError::OperationFailed {
910                shape: src_shape,
911                operation: "tried to put a value but there was no frame to put into",
912            });
913        };
914
915        // Check that the type matches
916        if frame.shape != src_shape {
917            trace!(
918                "Trying to put a {} into a {}",
919                src_shape.yellow(),
920                frame.shape.magenta()
921            );
922
923            // Check if the frame's shape has an inner type (is a transparent wrapper)
924            if let Some(inner_fn) = frame.shape.inner {
925                // Get the inner shape
926                let inner_shape = inner_fn();
927
928                // If the source shape matches the inner shape, we need to build the outer (transparent) wrapper
929                if src_shape == inner_shape {
930                    // Look for a try_from_inner function in the vtable
931                    if let Some(try_from_fn) = frame.shape.vtable.try_from {
932                        match unsafe { (try_from_fn)(src, src_shape, frame.data) } {
933                            Ok(_) => {
934                                unsafe {
935                                    frame.mark_fully_initialized();
936                                }
937
938                                let shape = frame.shape;
939                                let index = frame.field_index_in_parent;
940
941                                // mark the field as initialized
942                                self.mark_field_as_initialized(shape, index)?;
943
944                                debug!(
945                                    "[{}] Just put a {} value into transparent type {}",
946                                    self.frames.len(),
947                                    src_shape.green(),
948                                    shape.blue()
949                                );
950
951                                return Ok(self);
952                            }
953                            Err(e) => {
954                                return Err(ReflectError::TryFromError {
955                                    inner: e,
956                                    src_shape,
957                                    dst_shape: frame.shape,
958                                });
959                            }
960                        }
961                    } else {
962                        // No try_from_inner function, try normal TryFrom
963                        debug!(
964                            "No try_from_inner function for transparent type, falling back to TryFrom"
965                        );
966                    }
967                }
968            }
969
970            // Maybe there's a `TryFrom` impl?
971            if let Some(try_from) = frame.shape.vtable.try_from {
972                match unsafe { try_from(src, src_shape, frame.data) } {
973                    Ok(_) => {
974                        unsafe {
975                            frame.mark_fully_initialized();
976                        }
977
978                        let shape = frame.shape;
979                        let index = frame.field_index_in_parent;
980
981                        // mark the field as initialized
982                        self.mark_field_as_initialized(shape, index)?;
983
984                        debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
985
986                        return Ok(self);
987                    }
988                    Err(e) => {
989                        return Err(ReflectError::TryFromError {
990                            inner: e,
991                            src_shape,
992                            dst_shape: frame.shape,
993                        });
994                    }
995                }
996            }
997
998            // Maybe we're putting into an Option<T>?
999            // Handle Option<Inner>
1000            if let Def::Option(od) = frame.shape.def {
1001                // Check if inner type matches
1002                if od.t() == src_shape {
1003                    debug!("Putting into an Option<T>!");
1004                    if frame.istate.fields.is_any_set() {
1005                        let data = unsafe { frame.data.assume_init() };
1006                        unsafe { (od.vtable.replace_with_fn)(data, Some(src)) };
1007                    } else {
1008                        let data = frame.data;
1009                        unsafe { (od.vtable.init_some_fn)(data, src) };
1010                    }
1011                    unsafe {
1012                        frame.mark_fully_initialized();
1013                    }
1014
1015                    let shape = frame.shape;
1016                    let index = frame.field_index_in_parent;
1017
1018                    // mark the field as initialized
1019                    self.mark_field_as_initialized(shape, index)?;
1020
1021                    debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
1022
1023                    return Ok(self);
1024                }
1025            }
1026
1027            // Maybe we're putting into a tuple, and it just so happens that the first non-initialized
1028            // field has the right type?
1029            // Check if we're putting into a struct with tuple-like fields
1030            if let Def::Struct(sd) = frame.shape.def {
1031                // Look for the first uninitialized field
1032                for (i, field) in sd.fields.iter().enumerate() {
1033                    if !frame.istate.fields.has(i) && field.shape() == src_shape {
1034                        debug!(
1035                            "Found uninitialized field {} with matching type {}",
1036                            i.to_string().blue(),
1037                            src_shape.green()
1038                        );
1039
1040                        // Copy the value to the field
1041                        unsafe {
1042                            let field_data = frame.data.field_uninit_at(field.offset);
1043                            field_data.copy_from(src, field.shape()).map_err(|_| {
1044                                ReflectError::Unsized {
1045                                    shape: field.shape(),
1046                                }
1047                            })?;
1048                            frame.istate.fields.set(i);
1049                        }
1050
1051                        let shape = frame.shape;
1052                        let index = frame.field_index_in_parent;
1053
1054                        // If all fields are now initialized, mark the struct itself as initialized
1055                        if frame.is_fully_initialized() {
1056                            self.mark_field_as_initialized(shape, index)?;
1057                        }
1058
1059                        debug!(
1060                            "[{}] Put a {} value into field {} of {}",
1061                            self.frames.len(),
1062                            src_shape.green(),
1063                            i.to_string().blue(),
1064                            shape.green()
1065                        );
1066
1067                        return Ok(self);
1068                    }
1069                }
1070            }
1071
1072            // Maybe we're putting into an enum, which has a variant selected, which has tuple-like fields,
1073            // and the first field that is uninitialized just so happens to be the right type?
1074            if let Def::Enum(_) = frame.shape.def {
1075                // Check if we're putting into an enum with a selected variant
1076                if let Some(variant) = &frame.istate.variant {
1077                    // Look for the first uninitialized field in the variant
1078                    for (i, field) in variant.data.fields.iter().enumerate() {
1079                        if !frame.istate.fields.has(i) && field.shape() == src_shape {
1080                            debug!(
1081                                "Found uninitialized field {} in enum variant '{}' with matching type {}",
1082                                i.to_string().blue(),
1083                                variant.name.bright_yellow(),
1084                                src_shape.green()
1085                            );
1086
1087                            // Copy the value to the field
1088                            unsafe {
1089                                let field_data = frame.data.field_uninit_at(field.offset);
1090                                field_data.copy_from(src, field.shape()).map_err(|_| {
1091                                    ReflectError::Unsized {
1092                                        shape: field.shape(),
1093                                    }
1094                                })?;
1095                                frame.istate.fields.set(i);
1096                            }
1097
1098                            let shape = frame.shape;
1099                            let index = frame.field_index_in_parent;
1100
1101                            #[allow(unused)]
1102                            let variant_name = variant.name;
1103
1104                            // If all fields are now initialized, mark the enum itself as initialized
1105                            if frame.is_fully_initialized() {
1106                                self.mark_field_as_initialized(shape, index)?;
1107                            }
1108
1109                            debug!(
1110                                "[{}] Put a {} value into field {} of variant '{}' in enum {}",
1111                                self.frames.len(),
1112                                src_shape.green(),
1113                                i.to_string().blue(),
1114                                variant_name.bright_yellow(),
1115                                shape.green()
1116                            );
1117
1118                            return Ok(self);
1119                        }
1120                    }
1121                }
1122            }
1123
1124            return Err(ReflectError::WrongShape {
1125                expected: frame.shape,
1126                actual: src_shape,
1127            });
1128        }
1129
1130        // de-initialize partially initialized fields, if any
1131        if frame.istate.variant.is_some() || frame.istate.fields.is_any_set() {
1132            debug!("De-initializing partially initialized {:?}", frame.yellow());
1133
1134            match frame.shape.def {
1135                Def::Struct(sd) => {
1136                    for (i, field) in sd.fields.iter().enumerate() {
1137                        if frame.istate.fields.has(i) {
1138                            if let Some(drop_fn) = field.shape().vtable.drop_in_place {
1139                                unsafe {
1140                                    let field_ptr = frame.data.as_mut_byte_ptr().add(field.offset);
1141                                    drop_fn(PtrMut::new(field_ptr));
1142                                }
1143                            }
1144                        }
1145                    }
1146                }
1147                Def::Enum(_) => {
1148                    if let Some(variant) = &frame.istate.variant {
1149                        for (i, field) in variant.data.fields.iter().enumerate() {
1150                            if frame.istate.fields.has(i) {
1151                                if let Some(drop_fn) = field.shape().vtable.drop_in_place {
1152                                    unsafe {
1153                                        let field_ptr =
1154                                            frame.data.as_mut_byte_ptr().add(field.offset);
1155                                        drop_fn(PtrMut::new(field_ptr));
1156                                    }
1157                                }
1158                            }
1159                        }
1160                    }
1161                }
1162                _ => {
1163                    // For scalar types and other non-struct/enum, attempt to drop the field in place if initialized
1164                    if frame.istate.fields.is_any_set() {
1165                        debug!("Scalar type was set...");
1166                        if let Some(drop_fn) = frame.shape.vtable.drop_in_place {
1167                            debug!("And it has a drop fn, dropping now!");
1168                            unsafe {
1169                                drop_fn(frame.data.assume_init());
1170                            }
1171                        }
1172                    }
1173                }
1174            }
1175
1176            // Reset initialization state
1177            frame.istate.variant = None;
1178            ISet::clear(&mut frame.istate.fields);
1179        }
1180
1181        unsafe {
1182            // Copy the contents from src to destination
1183            frame
1184                .data
1185                .copy_from(src, frame.shape)
1186                .map_err(|_| ReflectError::Unsized { shape: frame.shape })?;
1187            frame.mark_fully_initialized();
1188        }
1189
1190        let shape = frame.shape;
1191        let index = frame.field_index_in_parent;
1192
1193        // mark the field as initialized
1194        self.mark_field_as_initialized(shape, index)?;
1195
1196        debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
1197
1198        Ok(self)
1199    }
1200
1201    /// Tries to parse the current frame's value from a string
1202    pub fn parse(mut self, s: &str) -> Result<Self, ReflectError> {
1203        let Some(frame) = self.frames.last_mut() else {
1204            return Err(ReflectError::OperationFailed {
1205                shape: <()>::SHAPE,
1206                operation: "tried to parse value but there was no frame",
1207            });
1208        };
1209
1210        let shape = frame.shape;
1211        let index = frame.field_index_in_parent;
1212
1213        let Some(parse_fn) = frame.shape.vtable.parse else {
1214            return Err(ReflectError::OperationFailed {
1215                shape: frame.shape,
1216                operation: "type does not implement Parse",
1217            });
1218        };
1219        match unsafe { (parse_fn)(s, frame.data) } {
1220            Ok(_res) => {
1221                unsafe {
1222                    frame.mark_fully_initialized();
1223                }
1224
1225                // mark the field as initialized
1226                self.mark_field_as_initialized(shape, index)?;
1227
1228                Ok(self)
1229            }
1230            Err(_) => Err(ReflectError::OperationFailed {
1231                shape,
1232                operation: "parsing",
1233            }),
1234        }
1235    }
1236
1237    /// Puts a value using a provided DefaultInPlaceFn in the current frame.
1238    pub fn put_from_fn(mut self, default_in_place: DefaultInPlaceFn) -> Result<Self, ReflectError> {
1239        let Some(frame) = self.frames.last_mut() else {
1240            return Err(ReflectError::OperationFailed {
1241                shape: <()>::SHAPE,
1242                operation: "tried to put value from fn but there was no frame",
1243            });
1244        };
1245
1246        unsafe {
1247            default_in_place(frame.data);
1248            frame.mark_fully_initialized();
1249        }
1250
1251        let shape = frame.shape;
1252        let index = frame.field_index_in_parent;
1253
1254        // mark the field as initialized
1255        self.mark_field_as_initialized(shape, index)?;
1256
1257        Ok(self)
1258    }
1259
1260    /// Puts the default value in the current frame.
1261    pub fn put_default(self) -> Result<Self, ReflectError> {
1262        let Some(frame) = self.frames.last() else {
1263            return Err(ReflectError::OperationFailed {
1264                shape: <()>::SHAPE,
1265                operation: "tried to put default value but there was no frame",
1266            });
1267        };
1268
1269        let vtable = frame.shape.vtable;
1270        let Some(default_in_place) = vtable.default_in_place else {
1271            return Err(ReflectError::OperationFailed {
1272                shape: frame.shape,
1273                operation: "type does not implement Default",
1274            });
1275        };
1276
1277        self.put_from_fn(default_in_place)
1278    }
1279
1280    /// Marks a field as initialized in the parent frame.
1281    fn mark_field_as_initialized(
1282        &mut self,
1283        shape: &'static Shape,
1284        index: Option<usize>,
1285    ) -> Result<(), ReflectError> {
1286        if let Some(index) = index {
1287            let parent_index = self.frames.len().saturating_sub(2);
1288            #[cfg(feature = "log")]
1289            let num_frames = self.frames.len();
1290            let Some(parent) = self.frames.get_mut(parent_index) else {
1291                return Err(ReflectError::OperationFailed {
1292                    shape,
1293                    operation: "was supposed to mark a field as initialized, but there was no parent frame",
1294                });
1295            };
1296            #[cfg(feature = "log")]
1297            let parent_shape = parent.shape;
1298            trace!(
1299                "[{}] {}.{} initialized with {}",
1300                num_frames,
1301                parent_shape.blue(),
1302                index.yellow(),
1303                shape.green()
1304            );
1305
1306            if matches!(parent.shape.def, Def::Enum(_)) && parent.istate.variant.is_none() {
1307                return Err(ReflectError::OperationFailed {
1308                    shape,
1309                    operation: "was supposed to mark a field as initialized, but the parent frame was an enum and didn't have a variant chosen",
1310                });
1311            }
1312
1313            if parent.istate.fields.has(index) {
1314                return Err(ReflectError::OperationFailed {
1315                    shape,
1316                    operation: "was supposed to mark a field as initialized, but the parent frame already had it marked as initialized",
1317                });
1318            }
1319
1320            parent.istate.fields.set(index);
1321        }
1322        Ok(())
1323    }
1324
1325    /// Returns the shape of the element type for a list/array
1326    pub fn element_shape(&self) -> Result<&'static Shape, ReflectError> {
1327        let frame = self.frames.last().unwrap();
1328        let shape = frame.shape;
1329
1330        match shape.def {
1331            Def::List(list_def) => Ok(list_def.t()),
1332            _ => Err(ReflectError::WasNotA {
1333                expected: "list or array",
1334                actual: shape,
1335            }),
1336        }
1337    }
1338
1339    /// Returns the shape of the key type for a map
1340    pub fn key_shape(&self) -> Result<&'static Shape, ReflectError> {
1341        let frame = self.frames.last().unwrap();
1342        let shape = frame.shape;
1343
1344        match shape.def {
1345            Def::Map(map_def) => Ok(map_def.k),
1346            _ => Err(ReflectError::WasNotA {
1347                expected: "map",
1348                actual: shape,
1349            }),
1350        }
1351    }
1352
1353    /// Creates an empty list without pushing any elements
1354    pub fn put_empty_list(mut self) -> Result<Self, ReflectError> {
1355        let Some(frame) = self.frames.last_mut() else {
1356            return Err(ReflectError::OperationFailed {
1357                shape: <()>::SHAPE,
1358                operation: "tried to create empty list but there was no frame",
1359            });
1360        };
1361
1362        if !matches!(frame.shape.def, Def::List(_)) {
1363            return Err(ReflectError::WasNotA {
1364                expected: "list or array",
1365                actual: frame.shape,
1366            });
1367        }
1368
1369        let vtable = frame.shape.vtable;
1370
1371        // Initialize an empty list
1372        let Some(default_in_place) = vtable.default_in_place else {
1373            return Err(ReflectError::OperationFailed {
1374                shape: frame.shape,
1375                operation: "list type does not implement Default",
1376            });
1377        };
1378
1379        unsafe {
1380            default_in_place(frame.data);
1381            frame.mark_fully_initialized();
1382        }
1383
1384        let shape = frame.shape;
1385        let index = frame.field_index_in_parent;
1386
1387        // Mark the field as initialized
1388        self.mark_field_as_initialized(shape, index)?;
1389
1390        Ok(self)
1391    }
1392
1393    /// Creates an empty map without pushing any entries
1394    pub fn put_empty_map(mut self) -> Result<Self, ReflectError> {
1395        let Some(frame) = self.frames.last_mut() else {
1396            return Err(ReflectError::OperationFailed {
1397                shape: <()>::SHAPE,
1398                operation: "tried to create empty map but there was no frame",
1399            });
1400        };
1401
1402        if !matches!(frame.shape.def, Def::Map(_)) {
1403            return Err(ReflectError::WasNotA {
1404                expected: "map or hash map",
1405                actual: frame.shape,
1406            });
1407        }
1408
1409        let vtable = frame.shape.vtable;
1410
1411        // Initialize an empty map
1412        let Some(default_in_place) = vtable.default_in_place else {
1413            return Err(ReflectError::OperationFailed {
1414                shape: frame.shape,
1415                operation: "map type does not implement Default",
1416            });
1417        };
1418
1419        unsafe {
1420            default_in_place(frame.data);
1421            frame.mark_fully_initialized();
1422        }
1423
1424        let shape = frame.shape;
1425        let index = frame.field_index_in_parent;
1426
1427        // Mark the field as initialized
1428        self.mark_field_as_initialized(shape, index)?;
1429
1430        Ok(self)
1431    }
1432
1433    /// Begins pushback mode for a list, array, tuple struct, or enum variant tuple struct,
1434    /// allowing elements to be added one by one.
1435    /// For lists/arrays, initializes an empty container if needed.
1436    /// For tuple structs/variants, does nothing (expects subsequent `push` calls).
1437    pub fn begin_pushback(mut self) -> Result<Self, ReflectError> {
1438        let Some(frame) = self.frames.last_mut() else {
1439            return Err(ReflectError::OperationFailed {
1440                shape: <()>::SHAPE,
1441                operation: "tried to begin pushback but there was no frame",
1442            });
1443        };
1444
1445        let is_list = matches!(frame.shape.def, Def::List(_));
1446        let is_tuple_struct_or_variant = match frame.shape.def {
1447            Def::Struct(sd) => sd.kind == facet_core::StructKind::Tuple,
1448            Def::Enum(_) => {
1449                // Check if a variant is selected and if that variant is a tuple-like struct
1450                if let Some(variant) = &frame.istate.variant {
1451                    variant.data.kind == facet_core::StructKind::Tuple
1452                } else {
1453                    // If no variant is selected yet, we can't determine if it's tuple-like.
1454                    // We allow beginning pushback here, assuming a tuple variant *will* be selected
1455                    // before pushing actual elements. The `push` operation will handle variant selection checks.
1456                    // Alternatively, we could error here if no variant is selected. Let's allow it for now.
1457                    // However, we definitely *don't* initialize anything if no variant is selected.
1458                    // UPDATE: Decided to be stricter. If it's an enum, a variant MUST be selected
1459                    // and it MUST be a tuple struct variant.
1460                    false // Require variant to be selected *and* be a tuple.
1461                }
1462            }
1463            _ => false,
1464        };
1465
1466        if !is_list && !is_tuple_struct_or_variant {
1467            return Err(ReflectError::WasNotA {
1468                expected: "list, array, or tuple-like struct/enum variant",
1469                actual: frame.shape,
1470            });
1471        }
1472
1473        // Only initialize for lists/arrays (which fall under Def::List)
1474        if is_list {
1475            let vtable = frame.shape.vtable;
1476            // Initialize an empty list if it's not already marked as initialized (field 0)
1477            if !frame.istate.fields.has(0) {
1478                let Some(default_in_place) = vtable.default_in_place else {
1479                    return Err(ReflectError::OperationFailed {
1480                        shape: frame.shape,
1481                        operation: "list type does not implement Default, cannot begin pushback",
1482                    });
1483                };
1484
1485                unsafe {
1486                    default_in_place(frame.data);
1487                    // Mark the list itself as initialized (representing the container exists)
1488                    frame.istate.fields.set(0);
1489                }
1490            }
1491        }
1492        // For tuple structs/variants, do nothing here. Initialization happens field-by-field during `push`.
1493
1494        Ok(self)
1495    }
1496
1497    /// Begins insertion mode for a map, allowing key-value pairs to be added one by one
1498    pub fn begin_map_insert(mut self) -> Result<Self, ReflectError> {
1499        let Some(frame) = self.frames.last_mut() else {
1500            return Err(ReflectError::OperationFailed {
1501                shape: <()>::SHAPE,
1502                operation: "tried to begin map insertion but there was no frame",
1503            });
1504        };
1505
1506        if !matches!(frame.shape.def, Def::Map(_)) {
1507            return Err(ReflectError::WasNotA {
1508                expected: "map or hash map",
1509                actual: frame.shape,
1510            });
1511        }
1512
1513        let vtable = frame.shape.vtable;
1514
1515        // Initialize an empty map if it's not already initialized
1516        if !frame.istate.fields.has(0) {
1517            let Some(default_in_place) = vtable.default_in_place else {
1518                return Err(ReflectError::OperationFailed {
1519                    shape: frame.shape,
1520                    operation: "map type does not implement Default",
1521                });
1522            };
1523
1524            unsafe {
1525                default_in_place(frame.data);
1526                frame.istate.fields.set(0);
1527            }
1528        }
1529
1530        Ok(self)
1531    }
1532
1533    /// Pushes a new element onto the list/array/tuple struct/tuple enum variant
1534    ///
1535    /// This creates a new frame for the element. When this frame is popped,
1536    /// the element will be added to the list or the corresponding tuple field will be set.
1537    pub fn push(mut self) -> Result<Self, ReflectError> {
1538        // Get mutable access to the top frame early, we might need it for list_index
1539        let frame_len = self.frames.len();
1540        let frame = self
1541            .frames
1542            .last_mut()
1543            .ok_or(ReflectError::OperationFailed {
1544                shape: <()>::SHAPE,
1545                operation: "tried to push but there was no frame",
1546            })?;
1547        let seq_shape = frame.shape;
1548
1549        // Determine element shape and context string based on the container type
1550        let (element_shape, context_str): (&'static Shape, &'static str) = match seq_shape.def {
1551            Def::List(_) => {
1552                // Check list initialization *before* getting element shape
1553                if !frame.istate.fields.has(0) {
1554                    // Replicate original recursive call pattern to handle initialization
1555                    // Drop mutable borrow of frame before recursive call
1556                    return self.begin_pushback()?.push();
1557                }
1558                // List is initialized, get element shape (requires immutable self)
1559                // Drop mutable borrow of frame before calling immutable method
1560                let shape = self.element_shape()?;
1561                (shape, "list")
1562            }
1563
1564            Def::Struct(sd) if sd.kind == facet_core::StructKind::Tuple => {
1565                // Handle tuple struct (requires mutable frame for list_index)
1566                let field_index = {
1567                    // Borrow frame mutably (already done) to update list_index
1568                    let next_idx = frame.istate.list_index.unwrap_or(0);
1569                    frame.istate.list_index = Some(next_idx + 1);
1570                    next_idx
1571                };
1572                // Check if the field index is valid
1573                if field_index >= sd.fields.len() {
1574                    return Err(ReflectError::FieldError {
1575                        shape: seq_shape,
1576                        field_error: FieldError::NoSuchField, // Or maybe SequenceError::OutOfBounds?
1577                    });
1578                }
1579                // Get the shape of the field at the calculated index
1580                (sd.fields[field_index].shape(), "tuple struct")
1581            }
1582
1583            Def::Enum(_) => {
1584                // Handle tuple enum variant (requires mutable frame for list_index and variant check)
1585                let variant =
1586                    frame
1587                        .istate
1588                        .variant
1589                        .as_ref()
1590                        .ok_or(ReflectError::OperationFailed {
1591                            shape: seq_shape,
1592                            operation: "tried to push onto enum but no variant was selected",
1593                        })?;
1594                // Ensure the selected variant is tuple-like
1595                if variant.data.kind != facet_core::StructKind::Tuple {
1596                    return Err(ReflectError::WasNotA {
1597                        expected: "tuple-like enum variant",
1598                        actual: seq_shape, // Could provide variant name here for clarity
1599                    });
1600                }
1601                // Get the next field index for the tuple variant
1602                let field_index = {
1603                    // Borrow frame mutably (already done) to update list_index
1604                    let next_idx = frame.istate.list_index.unwrap_or(0);
1605                    frame.istate.list_index = Some(next_idx + 1);
1606                    next_idx
1607                };
1608                // Check if the field index is valid within the variant's fields
1609                if field_index >= variant.data.fields.len() {
1610                    return Err(ReflectError::FieldError {
1611                        shape: seq_shape, // Could provide variant name here
1612                        field_error: FieldError::NoSuchField,
1613                    });
1614                }
1615                // Get the shape of the field at the calculated index within the variant
1616                (
1617                    variant.data.fields[field_index].shape(),
1618                    "tuple enum variant",
1619                )
1620            }
1621
1622            _ => {
1623                // If it's not a list, tuple struct, or enum, it's an error
1624                return Err(ReflectError::WasNotA {
1625                    expected: "list, array, tuple struct, or tuple enum variant",
1626                    actual: seq_shape,
1627                });
1628            }
1629        };
1630
1631        // Allocate memory for the element
1632        let element_data = element_shape
1633            .allocate()
1634            .map_err(|_| ReflectError::Unsized {
1635                shape: element_shape,
1636            })?;
1637
1638        // Create a new frame for the element
1639        let element_frame = Frame {
1640            data: element_data,
1641            shape: element_shape,
1642            field_index_in_parent: None, // Mode distinguishes it, not field index
1643            istate: IState::new(
1644                frame_len,              // Use captured length (depth of the new frame)
1645                FrameMode::ListElement, // Keep using this mode for list/tuple elements
1646                FrameFlags::ALLOCATED,
1647            ),
1648        };
1649
1650        trace!(
1651            "[{}] Pushing element of type {} to {} {}",
1652            frame_len,
1653            element_shape.green(),
1654            context_str, // Use the determined context string
1655            seq_shape.blue(),
1656        );
1657        let _ = context_str;
1658
1659        self.frames.push(element_frame);
1660        Ok(self)
1661    }
1662
1663    /// Prepare to push the `Some(T)` variant of an `Option<T>`.
1664    pub fn push_some(mut self) -> Result<Self, ReflectError> {
1665        // Make sure we're initializing an option
1666        let frame = self.frames.last().unwrap();
1667        let option_shape = frame.shape;
1668
1669        // Get the option definition
1670        let Def::Option(option_def) = option_shape.def else {
1671            return Err(ReflectError::WasNotA {
1672                expected: "option",
1673                actual: option_shape,
1674            });
1675        };
1676
1677        // Get the inner type of the option
1678        let inner_shape = option_def.t();
1679
1680        // Allocate memory for the inner value
1681        let inner_data = inner_shape
1682            .allocate()
1683            .map_err(|_| ReflectError::Unsized { shape: inner_shape })?;
1684
1685        // Create a new frame for the inner value
1686        let inner_frame = Frame {
1687            data: inner_data,
1688            shape: inner_shape,
1689            // this is only set when we pop
1690            field_index_in_parent: None,
1691            istate: IState::new(
1692                self.frames.len(),
1693                FrameMode::OptionSome,
1694                // TODO: we could lazy-allocate it when something like `field` is called, tbh
1695                FrameFlags::ALLOCATED,
1696            ),
1697        };
1698
1699        trace!(
1700            "[{}] Pushing option frame for {}",
1701            self.frames.len(),
1702            option_shape.blue(),
1703        );
1704
1705        self.frames.push(inner_frame);
1706        Ok(self)
1707    }
1708
1709    /// Pops a not-yet-initialized option frame, setting it to None in the parent
1710    ///
1711    /// This is used to set an option to None instead of Some.
1712    /// Steps:
1713    ///  1. Asserts the option frame is NOT initialized
1714    ///  2. Frees the memory for the pushed value
1715    ///  3. Pops the frame
1716    ///  4. Sets the parent option to its default value (i.e., None)
1717    ///  5. Pops the parent option (which is the actual `Option<T>`, but no longer in option mode)
1718    pub fn pop_some_push_none(mut self) -> Result<Self, ReflectError> {
1719        // 1. Option frame must exist
1720        let Some(frame) = self.frames.last_mut() else {
1721            return Err(ReflectError::OperationFailed {
1722                shape: <()>::SHAPE,
1723                operation: "tried to pop_some_push_none but there was no frame",
1724            });
1725        };
1726
1727        // 1. Make sure the current frame is an option inner frame in "Option" mode
1728        if frame.istate.mode != FrameMode::OptionSome {
1729            return Err(ReflectError::OperationFailed {
1730                shape: frame.shape,
1731                operation: "pop_some_push_none called, but frame was not in Option mode",
1732            });
1733        }
1734
1735        // 1. Check not initialized
1736        if frame.is_fully_initialized() {
1737            return Err(ReflectError::OperationFailed {
1738                shape: frame.shape,
1739                operation: "option frame already initialized, cannot pop_some_push_none",
1740            });
1741        }
1742
1743        frame.dealloc_if_needed();
1744
1745        // 3. Pop the frame (this discards, doesn't propagate up)
1746        let _frame = self.frames.pop().expect("frame already checked");
1747
1748        // 4. Set parent option (which we just popped into) to default (None)
1749        let parent_frame = self
1750            .frames
1751            .last_mut()
1752            .ok_or(ReflectError::OperationFailed {
1753                shape: <()>::SHAPE,
1754                operation: "tried to pop_some_push_none but there was no parent frame",
1755            })?;
1756
1757        // Safety: option frames are correctly sized, and data is valid
1758        unsafe {
1759            if let Some(default_fn) = parent_frame.shape.vtable.default_in_place {
1760                default_fn(parent_frame.data);
1761            } else {
1762                return Err(ReflectError::OperationFailed {
1763                    shape: parent_frame.shape,
1764                    operation: "option type does not implement Default",
1765                });
1766            }
1767            parent_frame.mark_fully_initialized();
1768        }
1769
1770        let Def::Option(od) = parent_frame.shape.def else {
1771            return Err(ReflectError::OperationFailed {
1772                shape: parent_frame.shape,
1773                operation: "pop_some_push_none and the parent isn't of type Option???",
1774            });
1775        };
1776
1777        // Now push a `None` frame
1778        let data = parent_frame.data;
1779
1780        let mut frame = Frame {
1781            data,
1782            shape: od.t(),
1783            field_index_in_parent: Some(0),
1784            istate: IState::new(self.frames.len(), FrameMode::OptionNone, FrameFlags::EMPTY),
1785        };
1786        unsafe {
1787            frame.mark_fully_initialized();
1788        }
1789
1790        self.frames.push(frame);
1791
1792        Ok(self)
1793    }
1794
1795    /// Pushes a new key frame for a map entry
1796    ///
1797    /// This creates a new frame for the key. After setting the key value,
1798    /// call `push_map_value` to create a frame for the corresponding value.
1799    pub fn push_map_key(mut self) -> Result<Self, ReflectError> {
1800        // Make sure we're initializing a map
1801        let frame = self.frames.last().unwrap();
1802        let map_shape = frame.shape;
1803
1804        if !matches!(map_shape.def, Def::Map(_)) {
1805            return Err(ReflectError::WasNotA {
1806                expected: "map or hash map",
1807                actual: map_shape,
1808            });
1809        }
1810
1811        // If the map isn't initialized yet, initialize it
1812        if !frame.istate.fields.has(0) {
1813            self = self.begin_map_insert()?;
1814        }
1815
1816        // Get the key type
1817        let key_shape = self.key_shape()?;
1818
1819        // Allocate memory for the key
1820        let key_data = key_shape
1821            .allocate()
1822            .map_err(|_| ReflectError::Unsized { shape: key_shape })?;
1823
1824        // Create a new frame for the key
1825        let key_frame = Frame {
1826            data: key_data,
1827            shape: key_shape,
1828            field_index_in_parent: None,
1829            istate: IState::new(self.frames.len(), FrameMode::MapKey, FrameFlags::ALLOCATED),
1830        };
1831
1832        trace!(
1833            "[{}] Pushing key of type {} for map {}",
1834            self.frames.len(),
1835            key_shape.green(),
1836            map_shape.blue(),
1837        );
1838
1839        self.frames.push(key_frame);
1840        Ok(self)
1841    }
1842
1843    /// Pushes a new value frame for a map entry
1844    ///
1845    /// This should be called after pushing and initializing a key frame.
1846    /// When the value frame is popped, the key-value pair will be added to the map.
1847    pub fn push_map_value(mut self) -> Result<Self, ReflectError> {
1848        trace!("Wants to push map value. Frames = ");
1849        #[cfg(feature = "log")]
1850        for (i, f) in self.frames.iter().enumerate() {
1851            trace!("Frame {}: {:?}", i, f);
1852        }
1853
1854        // First, ensure we have a valid key frame
1855        if self.frames.len() < 2 {
1856            return Err(ReflectError::OperationFailed {
1857                shape: <()>::SHAPE,
1858                operation: "tried to push map value but there was no key frame",
1859            });
1860        }
1861
1862        // Check the frame before the last to ensure it's a map key
1863        let key_frame_index = self.frames.len() - 1;
1864        let key_frame = &self.frames[key_frame_index];
1865
1866        // Verify the current frame is a key frame
1867        match key_frame.istate.mode {
1868            FrameMode::MapKey => {} // Valid - continue
1869            _ => {
1870                return Err(ReflectError::OperationFailed {
1871                    shape: key_frame.shape,
1872                    operation: "current frame is not a map key",
1873                });
1874            }
1875        }
1876
1877        // Check that the key is fully initialized
1878        if !key_frame.is_fully_initialized() {
1879            return Err(ReflectError::OperationFailed {
1880                shape: key_frame.shape,
1881                operation: "map key is not fully initialized",
1882            });
1883        }
1884
1885        // Get the parent map frame to verify we're working with a map
1886        let map_frame_index = self.frames.len() - 2;
1887        let map_frame = &self.frames[map_frame_index];
1888        let map_shape = map_frame.shape;
1889
1890        let Def::Map(map_def) = map_shape.def else {
1891            return Err(ReflectError::WasNotA {
1892                expected: "map",
1893                actual: map_frame.shape,
1894            });
1895        };
1896
1897        let value_shape = map_def.v;
1898
1899        // Allocate memory for the value
1900        let value_data = value_shape
1901            .allocate()
1902            .map_err(|_| ReflectError::Unsized { shape: value_shape })?;
1903
1904        // Create a new frame for the value
1905        let value_frame = Frame {
1906            data: value_data,
1907            shape: value_shape,
1908            field_index_in_parent: None,
1909            istate: IState::new(
1910                self.frames.len(),
1911                FrameMode::MapValue {
1912                    index: key_frame_index,
1913                },
1914                FrameFlags::ALLOCATED,
1915            ),
1916        };
1917
1918        trace!(
1919            "[{}] Pushing value of type {} for map {} with key type {}",
1920            self.frames.len(),
1921            value_shape.green(),
1922            map_shape.blue(),
1923            key_frame.shape.yellow(),
1924        );
1925
1926        self.frames.push(value_frame);
1927        Ok(self)
1928    }
1929
1930    /// Pops the current frame — goes back up one level
1931    pub fn pop(mut self) -> Result<Self, ReflectError> {
1932        let frame = match self.pop_inner()? {
1933            Some(frame) => frame,
1934            None => {
1935                return Err(ReflectError::InvariantViolation {
1936                    invariant: "No frame to pop — it was time to call build()",
1937                });
1938            }
1939        };
1940
1941        self.track(frame);
1942        Ok(self)
1943    }
1944
1945    fn pop_inner(&mut self) -> Result<Option<Frame>, ReflectError> {
1946        let mut frame = match self.frames.pop() {
1947            Some(f) => f,
1948            None => return Ok(None),
1949        };
1950        #[cfg(feature = "log")]
1951        let frame_shape = frame.shape;
1952
1953        let init = frame.is_fully_initialized();
1954        trace!(
1955            "[{}] {} popped, {} initialized",
1956            self.frames.len(),
1957            frame_shape.blue(),
1958            if init {
1959                "✅ fully".style(owo_colors::Style::new().green())
1960            } else {
1961                "🚧 partially".style(owo_colors::Style::new().red())
1962            }
1963        );
1964        if init {
1965            if let Some(parent) = self.frames.last_mut() {
1966                if let Some(index) = frame.field_index_in_parent {
1967                    parent.istate.fields.set(index);
1968                }
1969            }
1970        }
1971
1972        // Handle special frame modes
1973        match frame.istate.mode {
1974            // Handle list element frames
1975            FrameMode::ListElement => {
1976                if frame.is_fully_initialized() {
1977                    // This was a list or tuple element, so we need to push it to the parent
1978                    #[cfg(feature = "log")]
1979                    let frame_len = self.frames.len();
1980
1981                    // Get parent frame
1982                    let parent_frame = self.frames.last_mut().unwrap();
1983                    let parent_shape = parent_frame.shape;
1984
1985                    match parent_shape.def {
1986                        // Handle List/Array
1987                        Def::List(list_def) => {
1988                            let list_vtable = list_def.vtable;
1989                            trace!(
1990                                "[{}] Pushing element to list {}",
1991                                frame_len,
1992                                parent_shape.blue()
1993                            );
1994                            unsafe {
1995                                (list_vtable.push)(
1996                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1997                                    PtrMut::new(frame.data.as_mut_byte_ptr()),
1998                                );
1999                                self.mark_moved_out_of(&mut frame);
2000                            }
2001                        }
2002
2003                        // Handle Empty Unit Types (including empty tuple structs)
2004                        Def::Struct(sd)
2005                            if sd.kind == facet_core::StructKind::Tuple && sd.fields.is_empty() =>
2006                        {
2007                            trace!(
2008                                "[{}] Handling empty tuple struct unit type {}",
2009                                frame_len,
2010                                parent_shape.blue()
2011                            );
2012                            // Mark the parent unit struct as fully initialized
2013                            unsafe {
2014                                parent_frame.mark_fully_initialized();
2015                            }
2016                            // Element frame is implicitly moved/consumed, but nothing to dealloc if it was also unit
2017                            unsafe { self.mark_moved_out_of(&mut frame) };
2018                        }
2019                        Def::Scalar(s) if matches!(s.affinity, ScalarAffinity::Empty(_)) => {
2020                            trace!(
2021                                "[{}] Handling scalar empty unit type {}",
2022                                frame_len,
2023                                parent_shape.blue()
2024                            );
2025                            // Mark the parent scalar unit as fully initialized
2026                            unsafe {
2027                                parent_frame.mark_fully_initialized();
2028                                self.mark_moved_out_of(&mut frame);
2029                            }
2030                        }
2031
2032                        // Handle Tuple Structs
2033                        Def::Struct(sd) if sd.kind == facet_core::StructKind::Tuple => {
2034                            // Get the field index from list_index saved during push
2035                            let previous_index = parent_frame.istate.list_index.unwrap_or(1);
2036                            let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
2037
2038                            if field_index >= sd.fields.len() {
2039                                panic!(
2040                                    "Field index {} out of bounds for tuple struct {} with {} fields",
2041                                    field_index,
2042                                    parent_shape,
2043                                    sd.fields.len()
2044                                );
2045                            }
2046
2047                            let field = &sd.fields[field_index];
2048                            trace!(
2049                                "[{}] Setting tuple struct field {} ({}) of {}",
2050                                frame_len,
2051                                field_index.to_string().yellow(),
2052                                field.name.bright_blue(),
2053                                parent_shape.blue()
2054                            );
2055
2056                            unsafe {
2057                                // Copy the element data to the tuple field
2058                                let field_ptr = parent_frame.data.field_uninit_at(field.offset);
2059                                field_ptr
2060                                    .copy_from(
2061                                        PtrConst::new(frame.data.as_byte_ptr()),
2062                                        field.shape(),
2063                                    )
2064                                    .map_err(|_| ReflectError::Unsized {
2065                                        shape: field.shape(),
2066                                    })?; // Use ? to propagate potential unsized error
2067
2068                                // Mark the specific field as initialized using its index
2069                                parent_frame.istate.fields.set(field_index);
2070
2071                                // Mark the element as moved
2072                                self.mark_moved_out_of(&mut frame);
2073                            }
2074                        }
2075
2076                        // Handle Tuple Enum Variants
2077                        Def::Enum(_) => {
2078                            // Ensure a variant is selected and it's a tuple variant
2079                            let variant =
2080                                parent_frame.istate.variant.as_ref().unwrap_or_else(|| {
2081                                    panic!(
2082                                        "Popping element for enum {} but no variant was selected",
2083                                        parent_shape
2084                                    )
2085                                });
2086
2087                            if variant.data.kind != facet_core::StructKind::Tuple {
2088                                panic!(
2089                                    "Popping element for enum {}, but selected variant '{}' is not a tuple variant",
2090                                    parent_shape, variant.name
2091                                );
2092                            }
2093
2094                            // Get the field index from list_index saved during push
2095                            let previous_index = parent_frame.istate.list_index.unwrap_or(1);
2096                            let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
2097
2098                            if field_index >= variant.data.fields.len() {
2099                                panic!(
2100                                    "Field index {} out of bounds for tuple enum variant '{}' of {} with {} fields",
2101                                    field_index,
2102                                    variant.name,
2103                                    parent_shape,
2104                                    variant.data.fields.len()
2105                                );
2106                            }
2107
2108                            let field = &variant.data.fields[field_index];
2109                            trace!(
2110                                "[{}] Setting tuple enum variant field {} ({}) of variant '{}' in {}",
2111                                frame_len,
2112                                field_index.to_string().yellow(),
2113                                field.name.bright_blue(),
2114                                variant.name.yellow(),
2115                                parent_shape.blue()
2116                            );
2117
2118                            unsafe {
2119                                // Copy the element data to the tuple field within the enum's data payload
2120                                let field_ptr = parent_frame.data.field_uninit_at(field.offset);
2121                                field_ptr
2122                                    .copy_from(
2123                                        PtrConst::new(frame.data.as_byte_ptr()),
2124                                        field.shape(),
2125                                    )
2126                                    .map_err(|_| ReflectError::Unsized {
2127                                        shape: field.shape(),
2128                                    })?; // Use ? to propagate potential unsized error
2129
2130                                // Mark the specific field as initialized using its index
2131                                parent_frame.istate.fields.set(field_index);
2132
2133                                // Mark the element as moved
2134                                self.mark_moved_out_of(&mut frame);
2135                            }
2136                        }
2137
2138                        // Unexpected parent type
2139                        _ => {
2140                            panic!(
2141                                "FrameMode::ListElement pop expected parent to be List, Tuple Struct, or Tuple Enum Variant, but got {}",
2142                                parent_shape
2143                            );
2144                        }
2145                    }
2146                } else {
2147                    // Frame not fully initialized, just deallocate if needed (handled by Frame drop later)
2148                    trace!(
2149                        "Popping uninitialized ListElement frame ({}), potential leak if allocated resources are not managed",
2150                        frame.shape.yellow()
2151                    );
2152                }
2153            }
2154
2155            // Handle map value frames
2156            FrameMode::MapValue {
2157                index: key_frame_index,
2158            } if frame.is_fully_initialized() => {
2159                // This was a map value, so we need to insert the key-value pair into the map
2160
2161                // Now let's remove the key frame from the frames array
2162                let mut key_frame = self.frames.remove(key_frame_index);
2163
2164                // Make sure the key is fully initialized
2165                if !key_frame.istate.fields.is_any_set() {
2166                    panic!("key is not initialized when popping value frame");
2167                }
2168
2169                // Get parent map frame
2170                #[cfg(feature = "log")]
2171                let frame_len = self.frames.len();
2172                let parent_frame = self.frames.last_mut().unwrap();
2173                let parent_shape = parent_frame.shape;
2174
2175                // Make sure the parent is a map
2176                match parent_shape.def {
2177                    Def::Map(_) => {
2178                        // Get the map vtable from the MapDef
2179                        if let Def::Map(map_def) = parent_shape.def {
2180                            trace!(
2181                                "[{}] Inserting key-value pair into map {}",
2182                                frame_len,
2183                                parent_shape.blue()
2184                            );
2185                            unsafe {
2186                                // Call the map's insert function with the key and value
2187                                (map_def.vtable.insert_fn)(
2188                                    parent_frame.data.assume_init(),
2189                                    key_frame.data.assume_init(),
2190                                    PtrMut::new(frame.data.as_mut_byte_ptr()),
2191                                );
2192                                self.mark_moved_out_of(&mut key_frame);
2193                                self.mark_moved_out_of(&mut frame);
2194                            }
2195                        } else {
2196                            panic!("parent frame is not a map type");
2197                        }
2198                    }
2199                    _ => {
2200                        panic!("Expected map or hash map, got {}", frame.shape);
2201                    }
2202                }
2203            }
2204
2205            // Handle option frames
2206            FrameMode::OptionSome => {
2207                if frame.is_fully_initialized() {
2208                    trace!("Popping OptionSome (fully init'd)");
2209
2210                    // Get parent frame
2211                    #[cfg(feature = "log")]
2212                    let frames_len = self.frames.len();
2213                    let parent_frame = self.frames.last_mut().unwrap();
2214                    let parent_shape = parent_frame.shape;
2215
2216                    // Make sure the parent is an option
2217                    match parent_shape.def {
2218                        Def::Option(option_def) => {
2219                            trace!(
2220                                "[{}] Setting Some value in option {}",
2221                                frames_len,
2222                                parent_shape.blue()
2223                            );
2224                            unsafe {
2225                                // Call the option's init_some function
2226                                (option_def.vtable.init_some_fn)(
2227                                    parent_frame.data,
2228                                    PtrConst::new(frame.data.as_byte_ptr()),
2229                                );
2230                                trace!("Marking parent frame as fully initialized");
2231                                parent_frame.mark_fully_initialized();
2232
2233                                self.mark_moved_out_of(&mut frame);
2234                            }
2235                        }
2236                        _ => {
2237                            panic!(
2238                                "Expected parent frame to be an option type, got {}",
2239                                frame.shape
2240                            );
2241                        }
2242                    }
2243                } else {
2244                    trace!("Popping OptionSome (not fully init'd)");
2245                }
2246            }
2247
2248            // Map keys are just tracked, they don't need special handling when popped
2249            // FIXME: that's not true, we need to deallocate them at least??
2250            FrameMode::MapKey => {}
2251
2252            // Field frame
2253            FrameMode::Field => {}
2254
2255            // Uninitialized special frames
2256            _ => {}
2257        }
2258
2259        Ok(Some(frame))
2260    }
2261
2262    /// Evict a frame from istates, along with all its children
2263    /// (because we're about to use `drop_in_place` on it — not
2264    /// yet though, we need to know the variant for enums, etc.)
2265    pub fn evict_tree(&mut self, frame: Frame) -> Frame {
2266        match frame.shape.def {
2267            Def::Struct(sd) => {
2268                for f in sd.fields {
2269                    let id = ValueId {
2270                        shape: f.shape(),
2271                        ptr: unsafe { frame.data.field_uninit_at(f.offset) }.as_byte_ptr(),
2272                    };
2273                    if let Some(istate) = self.istates.remove(&id) {
2274                        let frame = Frame::recompose(id, istate);
2275                        self.evict_tree(frame);
2276                    } else {
2277                        trace!("No istate found for field {}", f.name);
2278                    }
2279                }
2280            }
2281            Def::Enum(_ed) => {
2282                // Check if a variant is selected in the istate
2283                if let Some(variant) = &frame.istate.variant {
2284                    trace!(
2285                        "Evicting enum {} variant '{}' fields",
2286                        frame.shape.blue(),
2287                        variant.name.yellow()
2288                    );
2289                    // Iterate over the fields of the selected variant
2290                    for field in variant.data.fields {
2291                        // Calculate the pointer to the field within the enum's data payload
2292                        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
2293                        let field_shape = field.shape();
2294                        let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
2295
2296                        // Try to remove the field's state from istates
2297                        if let Some(field_istate) = self.istates.remove(&field_id) {
2298                            trace!(
2299                                "Evicting field '{}' (shape {}) of enum variant '{}'",
2300                                field.name.bright_blue(),
2301                                field_shape.green(),
2302                                variant.name.yellow()
2303                            );
2304                            // Recompose the frame for the field
2305                            let field_frame = Frame::recompose(field_id, field_istate);
2306                            // Recursively evict the field's subtree
2307                            self.evict_tree(field_frame);
2308                        } else {
2309                            trace!(
2310                                "Field '{}' (shape {}) of enum variant '{}' not found in istates, skipping eviction",
2311                                field.name.red(),
2312                                field_shape.red(),
2313                                variant.name.yellow()
2314                            );
2315                        }
2316                    }
2317                } else {
2318                    // No variant selected, nothing to evict within the enum
2319                    trace!(
2320                        "Enum {} has no variant selected, no fields to evict.",
2321                        frame.shape.blue()
2322                    );
2323                }
2324            }
2325            _ => {}
2326        }
2327        frame
2328    }
2329
2330    #[allow(rustdoc::broken_intra_doc_links)]
2331    /// Returns the current path in the JSON document as a string.
2332    /// For example: "$.users[0].name"
2333    pub fn path(&self) -> String {
2334        let mut path = String::from("$");
2335
2336        for (i, frame) in self.frames.iter().enumerate() {
2337            // Skip the root frame
2338            if i == 0 {
2339                continue;
2340            }
2341
2342            match frame.istate.mode {
2343                FrameMode::ListElement => {
2344                    // For arrays, we use bracket notation with index
2345                    if let Some(index) = frame.istate.list_index {
2346                        path.push_str(&format!("[{}]", index));
2347                    } else {
2348                        path.push_str("[?]");
2349                    }
2350                }
2351                FrameMode::MapKey => {
2352                    path.push_str(".key");
2353                }
2354                FrameMode::MapValue { index: _ } => {
2355                    path.push_str(".value");
2356                }
2357                FrameMode::OptionSome => {
2358                    path.push_str(".some");
2359                }
2360                FrameMode::OptionNone => {
2361                    path.push_str(".none");
2362                }
2363                FrameMode::Root => {
2364                    // Root doesn't add to the path
2365                }
2366                FrameMode::Field => {
2367                    // For struct fields, we use dot notation with field name
2368                    if let Some(index) = frame.field_index_in_parent {
2369                        // Find the parent frame to get the field name
2370                        if let Some(parent) = self.frames.get(i - 1) {
2371                            if let Def::Struct(sd) = parent.shape.def {
2372                                if index < sd.fields.len() {
2373                                    let field_name = sd.fields[index].name;
2374                                    path.push('.');
2375                                    path.push_str(field_name);
2376                                }
2377                            } else if let Def::Enum(_) = parent.shape.def {
2378                                if let Some(variant) = &parent.istate.variant {
2379                                    if index < variant.data.fields.len() {
2380                                        let field_name = variant.data.fields[index].name;
2381                                        path.push('.');
2382                                        path.push_str(field_name);
2383                                    }
2384                                }
2385                            }
2386                        }
2387                    }
2388                }
2389            }
2390        }
2391
2392        path
2393    }
2394
2395    /// Returns true if the field at the given index is set (initialized) in the current frame.
2396    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
2397        let frame = self.frames.last().ok_or(ReflectError::OperationFailed {
2398            shape: <()>::SHAPE,
2399            operation: "tried to check if field is set, but there was no frame",
2400        })?;
2401
2402        match frame.shape.def {
2403            Def::Struct(ref sd) => {
2404                if index >= sd.fields.len() {
2405                    return Err(ReflectError::FieldError {
2406                        shape: frame.shape,
2407                        field_error: FieldError::NoSuchField,
2408                    });
2409                }
2410                Ok(frame.istate.fields.has(index))
2411            }
2412            Def::Enum(_) => {
2413                let variant = frame.istate.variant.as_ref().ok_or(
2414                    ReflectError::OperationFailed {
2415                        shape: frame.shape,
2416                        operation: "tried to check if field is set, but no variant was selected",
2417                    },
2418                )?;
2419                if index >= variant.data.fields.len() {
2420                    return Err(ReflectError::FieldError {
2421                        shape: frame.shape,
2422                        field_error: FieldError::NoSuchField,
2423                    });
2424                }
2425                Ok(frame.istate.fields.has(index))
2426            }
2427            _ => Err(ReflectError::WasNotA {
2428                expected: "struct or enum",
2429                actual: frame.shape,
2430            }),
2431        }
2432    }
2433}
2434
2435impl Drop for Wip<'_> {
2436    fn drop(&mut self) {
2437        trace!("🧹🧹🧹 WIP is dropping");
2438
2439        while let Some(frame) = self.frames.pop() {
2440            self.track(frame);
2441        }
2442
2443        let Some((root_id, _)) = self.istates.iter().find(|(_k, istate)| istate.depth == 0) else {
2444            trace!("No root found, we probably built already");
2445            return;
2446        };
2447
2448        let root_id = *root_id;
2449        let root_istate = self.istates.remove(&root_id).unwrap();
2450        let root = Frame::recompose(root_id, root_istate);
2451        let mut to_clean = vec![root];
2452
2453        let mut _root_guard: Option<Guard> = None;
2454
2455        while let Some(mut frame) = to_clean.pop() {
2456            trace!(
2457                "Cleaning frame: shape={} at {:p}, flags={:?}, mode={:?}, fully_initialized={}",
2458                frame.shape.blue(),
2459                frame.data.as_byte_ptr(),
2460                frame.istate.flags.bright_magenta(),
2461                frame.istate.mode.yellow(),
2462                if frame.is_fully_initialized() {
2463                    "✅"
2464                } else {
2465                    "❌"
2466                }
2467            );
2468
2469            if frame.istate.flags.contains(FrameFlags::MOVED) {
2470                trace!(
2471                    "{}",
2472                    "Frame was moved out of, nothing to dealloc/drop_in_place".yellow()
2473                );
2474                continue;
2475            }
2476
2477            match frame.shape.def {
2478                Def::Struct(sd) => {
2479                    if frame.is_fully_initialized() {
2480                        trace!(
2481                            "Dropping fully initialized struct: {} at {:p}",
2482                            frame.shape.green(),
2483                            frame.data.as_byte_ptr()
2484                        );
2485                        let frame = self.evict_tree(frame);
2486                        unsafe { frame.drop_and_dealloc_if_needed() };
2487                    } else {
2488                        let num_fields = sd.fields.len();
2489                        trace!(
2490                            "De-initializing struct {} at {:p} field-by-field ({} fields)",
2491                            frame.shape.yellow(),
2492                            frame.data.as_byte_ptr(),
2493                            num_fields.to_string().bright_cyan()
2494                        );
2495                        for i in 0..num_fields {
2496                            if frame.istate.fields.has(i) {
2497                                let field = sd.fields[i];
2498                                let field_shape = field.shape();
2499                                let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
2500                                let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
2501                                trace!(
2502                                    "Recursively cleaning field #{} '{}' of {}: field_shape={}, field_ptr={:p}",
2503                                    i.to_string().bright_cyan(),
2504                                    field.name.bright_blue(),
2505                                    frame.shape.blue(),
2506                                    field_shape.green(),
2507                                    field_ptr.as_byte_ptr()
2508                                );
2509                                let istate = self.istates.remove(&field_id).unwrap();
2510                                let field_frame = Frame::recompose(field_id, istate);
2511                                to_clean.push(field_frame);
2512                            } else {
2513                                trace!(
2514                                    "Field #{} '{}' of {} was NOT initialized, skipping",
2515                                    i.to_string().bright_cyan(),
2516                                    sd.fields[i].name.bright_red(),
2517                                    frame.shape.red()
2518                                );
2519                            }
2520                        }
2521
2522                        // we'll also need to clean up if we're root
2523                        if frame.istate.mode == FrameMode::Root {
2524                            if let Ok(layout) = frame.shape.layout.sized_layout() {
2525                                _root_guard = Some(Guard {
2526                                    ptr: frame.data.as_mut_byte_ptr(),
2527                                    layout,
2528                                });
2529                            }
2530                        }
2531                    }
2532                }
2533                Def::Enum(_ed) => {
2534                    trace!(
2535                        "{}",
2536                        format_args!(
2537                            "TODO: handle enum deallocation for {} at {:p}",
2538                            frame.shape.yellow(),
2539                            frame.data.as_byte_ptr()
2540                        )
2541                        .magenta()
2542                    );
2543
2544                    // we'll also need to clean up if we're root
2545                    if frame.istate.mode == FrameMode::Root {
2546                        if let Ok(layout) = frame.shape.layout.sized_layout() {
2547                            _root_guard = Some(Guard {
2548                                ptr: frame.data.as_mut_byte_ptr(),
2549                                layout,
2550                            });
2551                        }
2552                    }
2553                }
2554                Def::Array(_)
2555                | Def::Slice(_)
2556                | Def::List(_)
2557                | Def::Map(_)
2558                | Def::SmartPointer(_)
2559                | Def::Scalar(_)
2560                | Def::FunctionPointer(_)
2561                | Def::Option(_) => {
2562                    trace!(
2563                        "Can drop all at once for shape {} (def variant: {:?}, frame mode {:?}) at {:p}",
2564                        frame.shape.cyan(),
2565                        frame.shape.def,
2566                        frame.istate.mode.yellow(),
2567                        frame.data.as_byte_ptr(),
2568                    );
2569
2570                    if frame.is_fully_initialized() {
2571                        unsafe { frame.drop_and_dealloc_if_needed() }
2572                    } else {
2573                        frame.dealloc_if_needed();
2574                    }
2575                }
2576                _ => {}
2577            }
2578        }
2579
2580        // We might have some frames left over to deallocate for temporary allocations for keymap insertion etc.
2581        let mut all_ids = self.istates.keys().copied().collect::<Vec<_>>();
2582        for frame_id in all_ids.drain(..) {
2583            let frame_istate = self.istates.remove(&frame_id).unwrap();
2584
2585            trace!(
2586                "Checking leftover istate: id.shape={} id.ptr={:p} mode={:?}",
2587                frame_id.shape.cyan(),
2588                frame_id.ptr,
2589                frame_istate.mode.yellow()
2590            );
2591            let mut frame = Frame::recompose(frame_id, frame_istate);
2592
2593            if frame.is_fully_initialized() {
2594                trace!("It's fully initialized, we can drop it");
2595                unsafe { frame.drop_and_dealloc_if_needed() };
2596            } else if frame.istate.flags.contains(FrameFlags::ALLOCATED) {
2597                trace!("Not initialized but allocated, let's free it");
2598                frame.dealloc_if_needed();
2599            }
2600        }
2601    }
2602}