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::Scalar(sd) => matches!(sd.affinity, ScalarAffinity::Empty(_)),
1448            Def::Struct(sd) => sd.kind == facet_core::StructKind::Tuple,
1449            Def::Enum(_) => {
1450                // Check if a variant is selected and if that variant is a tuple-like struct
1451                if let Some(variant) = &frame.istate.variant {
1452                    variant.data.kind == facet_core::StructKind::Tuple
1453                } else {
1454                    // If no variant is selected yet, we can't determine if it's tuple-like.
1455                    // We allow beginning pushback here, assuming a tuple variant *will* be selected
1456                    // before pushing actual elements. The `push` operation will handle variant selection checks.
1457                    // Alternatively, we could error here if no variant is selected. Let's allow it for now.
1458                    // However, we definitely *don't* initialize anything if no variant is selected.
1459                    // UPDATE: Decided to be stricter. If it's an enum, a variant MUST be selected
1460                    // and it MUST be a tuple struct variant.
1461                    false // Require variant to be selected *and* be a tuple.
1462                }
1463            }
1464            _ => false,
1465        };
1466
1467        if !is_list && !is_tuple_struct_or_variant {
1468            return Err(ReflectError::WasNotA {
1469                expected: "list, array, or tuple-like struct/enum variant",
1470                actual: frame.shape,
1471            });
1472        }
1473
1474        // Only initialize for lists/arrays (which fall under Def::List)
1475        if is_list {
1476            let vtable = frame.shape.vtable;
1477            // Initialize an empty list if it's not already marked as initialized (field 0)
1478            if !frame.istate.fields.has(0) {
1479                let Some(default_in_place) = vtable.default_in_place else {
1480                    return Err(ReflectError::OperationFailed {
1481                        shape: frame.shape,
1482                        operation: "list type does not implement Default, cannot begin pushback",
1483                    });
1484                };
1485
1486                unsafe {
1487                    default_in_place(frame.data);
1488                    // Mark the list itself as initialized (representing the container exists)
1489                    frame.istate.fields.set(0);
1490                }
1491            }
1492        }
1493        // For tuple structs/variants, do nothing here. Initialization happens field-by-field during `push`.
1494
1495        Ok(self)
1496    }
1497
1498    /// Begins insertion mode for a map, allowing key-value pairs to be added one by one
1499    pub fn begin_map_insert(mut self) -> Result<Self, ReflectError> {
1500        let Some(frame) = self.frames.last_mut() else {
1501            return Err(ReflectError::OperationFailed {
1502                shape: <()>::SHAPE,
1503                operation: "tried to begin map insertion but there was no frame",
1504            });
1505        };
1506
1507        if !matches!(frame.shape.def, Def::Map(_)) {
1508            return Err(ReflectError::WasNotA {
1509                expected: "map or hash map",
1510                actual: frame.shape,
1511            });
1512        }
1513
1514        let vtable = frame.shape.vtable;
1515
1516        // Initialize an empty map if it's not already initialized
1517        if !frame.istate.fields.has(0) {
1518            let Some(default_in_place) = vtable.default_in_place else {
1519                return Err(ReflectError::OperationFailed {
1520                    shape: frame.shape,
1521                    operation: "map type does not implement Default",
1522                });
1523            };
1524
1525            unsafe {
1526                default_in_place(frame.data);
1527                frame.istate.fields.set(0);
1528            }
1529        }
1530
1531        Ok(self)
1532    }
1533
1534    /// Pushes a new element onto the list/array/tuple struct/tuple enum variant
1535    ///
1536    /// This creates a new frame for the element. When this frame is popped,
1537    /// the element will be added to the list or the corresponding tuple field will be set.
1538    pub fn push(mut self) -> Result<Self, ReflectError> {
1539        // Get mutable access to the top frame early, we might need it for list_index
1540        let frame_len = self.frames.len();
1541        let frame = self
1542            .frames
1543            .last_mut()
1544            .ok_or(ReflectError::OperationFailed {
1545                shape: <()>::SHAPE,
1546                operation: "tried to push but there was no frame",
1547            })?;
1548        let seq_shape = frame.shape;
1549
1550        // Determine element shape and context string based on the container type
1551        let (element_shape, context_str): (&'static Shape, &'static str) = match seq_shape.def {
1552            Def::List(_) => {
1553                // Check list initialization *before* getting element shape
1554                if !frame.istate.fields.has(0) {
1555                    // Replicate original recursive call pattern to handle initialization
1556                    // Drop mutable borrow of frame before recursive call
1557                    return self.begin_pushback()?.push();
1558                }
1559                // List is initialized, get element shape (requires immutable self)
1560                // Drop mutable borrow of frame before calling immutable method
1561                let shape = self.element_shape()?;
1562                (shape, "list")
1563            }
1564
1565            Def::Struct(sd) if sd.kind == facet_core::StructKind::Tuple => {
1566                // Handle tuple struct (requires mutable frame for list_index)
1567                let field_index = {
1568                    // Borrow frame mutably (already done) to update list_index
1569                    let next_idx = frame.istate.list_index.unwrap_or(0);
1570                    frame.istate.list_index = Some(next_idx + 1);
1571                    next_idx
1572                };
1573                // Check if the field index is valid
1574                if field_index >= sd.fields.len() {
1575                    return Err(ReflectError::FieldError {
1576                        shape: seq_shape,
1577                        field_error: FieldError::NoSuchField, // Or maybe SequenceError::OutOfBounds?
1578                    });
1579                }
1580                // Get the shape of the field at the calculated index
1581                (sd.fields[field_index].shape(), "tuple struct")
1582            }
1583
1584            Def::Enum(_) => {
1585                // Handle tuple enum variant (requires mutable frame for list_index and variant check)
1586                let variant =
1587                    frame
1588                        .istate
1589                        .variant
1590                        .as_ref()
1591                        .ok_or(ReflectError::OperationFailed {
1592                            shape: seq_shape,
1593                            operation: "tried to push onto enum but no variant was selected",
1594                        })?;
1595                // Ensure the selected variant is tuple-like
1596                if variant.data.kind != facet_core::StructKind::Tuple {
1597                    return Err(ReflectError::WasNotA {
1598                        expected: "tuple-like enum variant",
1599                        actual: seq_shape, // Could provide variant name here for clarity
1600                    });
1601                }
1602                // Get the next field index for the tuple variant
1603                let field_index = {
1604                    // Borrow frame mutably (already done) to update list_index
1605                    let next_idx = frame.istate.list_index.unwrap_or(0);
1606                    frame.istate.list_index = Some(next_idx + 1);
1607                    next_idx
1608                };
1609                // Check if the field index is valid within the variant's fields
1610                if field_index >= variant.data.fields.len() {
1611                    return Err(ReflectError::FieldError {
1612                        shape: seq_shape, // Could provide variant name here
1613                        field_error: FieldError::NoSuchField,
1614                    });
1615                }
1616                // Get the shape of the field at the calculated index within the variant
1617                (
1618                    variant.data.fields[field_index].shape(),
1619                    "tuple enum variant",
1620                )
1621            }
1622
1623            Def::Scalar(sd) if matches!(sd.affinity, ScalarAffinity::Empty(_)) => {
1624                // Handle empty tuple a.k.a. unit type () - cannot push elements
1625                return Err(ReflectError::OperationFailed {
1626                    shape: seq_shape,
1627                    operation: "cannot push elements to unit type ()",
1628                });
1629            }
1630
1631            _ => {
1632                // If it's not a list, tuple struct, or enum, it's an error
1633                return Err(ReflectError::WasNotA {
1634                    expected: "list, array, tuple struct, or tuple enum variant",
1635                    actual: seq_shape,
1636                });
1637            }
1638        };
1639
1640        // Allocate memory for the element
1641        let element_data = element_shape
1642            .allocate()
1643            .map_err(|_| ReflectError::Unsized {
1644                shape: element_shape,
1645            })?;
1646
1647        // Create a new frame for the element
1648        let element_frame = Frame {
1649            data: element_data,
1650            shape: element_shape,
1651            field_index_in_parent: None, // Mode distinguishes it, not field index
1652            istate: IState::new(
1653                frame_len,              // Use captured length (depth of the new frame)
1654                FrameMode::ListElement, // Keep using this mode for list/tuple elements
1655                FrameFlags::ALLOCATED,
1656            ),
1657        };
1658
1659        trace!(
1660            "[{}] Pushing element of type {} to {} {}",
1661            frame_len,
1662            element_shape.green(),
1663            context_str, // Use the determined context string
1664            seq_shape.blue(),
1665        );
1666        let _ = context_str;
1667
1668        self.frames.push(element_frame);
1669        Ok(self)
1670    }
1671
1672    /// Prepare to push the `Some(T)` variant of an `Option<T>`.
1673    pub fn push_some(mut self) -> Result<Self, ReflectError> {
1674        // Make sure we're initializing an option
1675        let frame = self.frames.last().unwrap();
1676        let option_shape = frame.shape;
1677
1678        // Get the option definition
1679        let Def::Option(option_def) = option_shape.def else {
1680            return Err(ReflectError::WasNotA {
1681                expected: "option",
1682                actual: option_shape,
1683            });
1684        };
1685
1686        // Get the inner type of the option
1687        let inner_shape = option_def.t();
1688
1689        // Allocate memory for the inner value
1690        let inner_data = inner_shape
1691            .allocate()
1692            .map_err(|_| ReflectError::Unsized { shape: inner_shape })?;
1693
1694        // Create a new frame for the inner value
1695        let inner_frame = Frame {
1696            data: inner_data,
1697            shape: inner_shape,
1698            // this is only set when we pop
1699            field_index_in_parent: None,
1700            istate: IState::new(
1701                self.frames.len(),
1702                FrameMode::OptionSome,
1703                // TODO: we could lazy-allocate it when something like `field` is called, tbh
1704                FrameFlags::ALLOCATED,
1705            ),
1706        };
1707
1708        trace!(
1709            "[{}] Pushing option frame for {}",
1710            self.frames.len(),
1711            option_shape.blue(),
1712        );
1713
1714        self.frames.push(inner_frame);
1715        Ok(self)
1716    }
1717
1718    /// Pops a not-yet-initialized option frame, setting it to None in the parent
1719    ///
1720    /// This is used to set an option to None instead of Some.
1721    /// Steps:
1722    ///  1. Asserts the option frame is NOT initialized
1723    ///  2. Frees the memory for the pushed value
1724    ///  3. Pops the frame
1725    ///  4. Sets the parent option to its default value (i.e., None)
1726    ///  5. Pops the parent option (which is the actual `Option<T>`, but no longer in option mode)
1727    pub fn pop_some_push_none(mut self) -> Result<Self, ReflectError> {
1728        // 1. Option frame must exist
1729        let Some(frame) = self.frames.last_mut() else {
1730            return Err(ReflectError::OperationFailed {
1731                shape: <()>::SHAPE,
1732                operation: "tried to pop_some_push_none but there was no frame",
1733            });
1734        };
1735
1736        // 1. Make sure the current frame is an option inner frame in "Option" mode
1737        if frame.istate.mode != FrameMode::OptionSome {
1738            return Err(ReflectError::OperationFailed {
1739                shape: frame.shape,
1740                operation: "pop_some_push_none called, but frame was not in Option mode",
1741            });
1742        }
1743
1744        // 1. Check not initialized
1745        if frame.is_fully_initialized() {
1746            return Err(ReflectError::OperationFailed {
1747                shape: frame.shape,
1748                operation: "option frame already initialized, cannot pop_some_push_none",
1749            });
1750        }
1751
1752        frame.dealloc_if_needed();
1753
1754        // 3. Pop the frame (this discards, doesn't propagate up)
1755        let _frame = self.frames.pop().expect("frame already checked");
1756
1757        // 4. Set parent option (which we just popped into) to default (None)
1758        let parent_frame = self
1759            .frames
1760            .last_mut()
1761            .ok_or(ReflectError::OperationFailed {
1762                shape: <()>::SHAPE,
1763                operation: "tried to pop_some_push_none but there was no parent frame",
1764            })?;
1765
1766        // Safety: option frames are correctly sized, and data is valid
1767        unsafe {
1768            if let Some(default_fn) = parent_frame.shape.vtable.default_in_place {
1769                default_fn(parent_frame.data);
1770            } else {
1771                return Err(ReflectError::OperationFailed {
1772                    shape: parent_frame.shape,
1773                    operation: "option type does not implement Default",
1774                });
1775            }
1776            parent_frame.mark_fully_initialized();
1777        }
1778
1779        let Def::Option(od) = parent_frame.shape.def else {
1780            return Err(ReflectError::OperationFailed {
1781                shape: parent_frame.shape,
1782                operation: "pop_some_push_none and the parent isn't of type Option???",
1783            });
1784        };
1785
1786        // Now push a `None` frame
1787        let data = parent_frame.data;
1788
1789        let mut frame = Frame {
1790            data,
1791            shape: od.t(),
1792            field_index_in_parent: Some(0),
1793            istate: IState::new(self.frames.len(), FrameMode::OptionNone, FrameFlags::EMPTY),
1794        };
1795        unsafe {
1796            frame.mark_fully_initialized();
1797        }
1798
1799        self.frames.push(frame);
1800
1801        Ok(self)
1802    }
1803
1804    /// Pushes a new key frame for a map entry
1805    ///
1806    /// This creates a new frame for the key. After setting the key value,
1807    /// call `push_map_value` to create a frame for the corresponding value.
1808    pub fn push_map_key(mut self) -> Result<Self, ReflectError> {
1809        // Make sure we're initializing a map
1810        let frame = self.frames.last().unwrap();
1811        let map_shape = frame.shape;
1812
1813        if !matches!(map_shape.def, Def::Map(_)) {
1814            return Err(ReflectError::WasNotA {
1815                expected: "map or hash map",
1816                actual: map_shape,
1817            });
1818        }
1819
1820        // If the map isn't initialized yet, initialize it
1821        if !frame.istate.fields.has(0) {
1822            self = self.begin_map_insert()?;
1823        }
1824
1825        // Get the key type
1826        let key_shape = self.key_shape()?;
1827
1828        // Allocate memory for the key
1829        let key_data = key_shape
1830            .allocate()
1831            .map_err(|_| ReflectError::Unsized { shape: key_shape })?;
1832
1833        // Create a new frame for the key
1834        let key_frame = Frame {
1835            data: key_data,
1836            shape: key_shape,
1837            field_index_in_parent: None,
1838            istate: IState::new(self.frames.len(), FrameMode::MapKey, FrameFlags::ALLOCATED),
1839        };
1840
1841        trace!(
1842            "[{}] Pushing key of type {} for map {}",
1843            self.frames.len(),
1844            key_shape.green(),
1845            map_shape.blue(),
1846        );
1847
1848        self.frames.push(key_frame);
1849        Ok(self)
1850    }
1851
1852    /// Pushes a new value frame for a map entry
1853    ///
1854    /// This should be called after pushing and initializing a key frame.
1855    /// When the value frame is popped, the key-value pair will be added to the map.
1856    pub fn push_map_value(mut self) -> Result<Self, ReflectError> {
1857        trace!("Wants to push map value. Frames = ");
1858        #[cfg(feature = "log")]
1859        for (i, f) in self.frames.iter().enumerate() {
1860            trace!("Frame {}: {:?}", i, f);
1861        }
1862
1863        // First, ensure we have a valid key frame
1864        if self.frames.len() < 2 {
1865            return Err(ReflectError::OperationFailed {
1866                shape: <()>::SHAPE,
1867                operation: "tried to push map value but there was no key frame",
1868            });
1869        }
1870
1871        // Check the frame before the last to ensure it's a map key
1872        let key_frame_index = self.frames.len() - 1;
1873        let key_frame = &self.frames[key_frame_index];
1874
1875        // Verify the current frame is a key frame
1876        match key_frame.istate.mode {
1877            FrameMode::MapKey => {} // Valid - continue
1878            _ => {
1879                return Err(ReflectError::OperationFailed {
1880                    shape: key_frame.shape,
1881                    operation: "current frame is not a map key",
1882                });
1883            }
1884        }
1885
1886        // Check that the key is fully initialized
1887        if !key_frame.is_fully_initialized() {
1888            return Err(ReflectError::OperationFailed {
1889                shape: key_frame.shape,
1890                operation: "map key is not fully initialized",
1891            });
1892        }
1893
1894        // Get the parent map frame to verify we're working with a map
1895        let map_frame_index = self.frames.len() - 2;
1896        let map_frame = &self.frames[map_frame_index];
1897        let map_shape = map_frame.shape;
1898
1899        let Def::Map(map_def) = map_shape.def else {
1900            return Err(ReflectError::WasNotA {
1901                expected: "map",
1902                actual: map_frame.shape,
1903            });
1904        };
1905
1906        let value_shape = map_def.v;
1907
1908        // Allocate memory for the value
1909        let value_data = value_shape
1910            .allocate()
1911            .map_err(|_| ReflectError::Unsized { shape: value_shape })?;
1912
1913        // Create a new frame for the value
1914        let value_frame = Frame {
1915            data: value_data,
1916            shape: value_shape,
1917            field_index_in_parent: None,
1918            istate: IState::new(
1919                self.frames.len(),
1920                FrameMode::MapValue {
1921                    index: key_frame_index,
1922                },
1923                FrameFlags::ALLOCATED,
1924            ),
1925        };
1926
1927        trace!(
1928            "[{}] Pushing value of type {} for map {} with key type {}",
1929            self.frames.len(),
1930            value_shape.green(),
1931            map_shape.blue(),
1932            key_frame.shape.yellow(),
1933        );
1934
1935        self.frames.push(value_frame);
1936        Ok(self)
1937    }
1938
1939    /// Pops the current frame — goes back up one level
1940    pub fn pop(mut self) -> Result<Self, ReflectError> {
1941        let frame = match self.pop_inner()? {
1942            Some(frame) => frame,
1943            None => {
1944                return Err(ReflectError::InvariantViolation {
1945                    invariant: "No frame to pop — it was time to call build()",
1946                });
1947            }
1948        };
1949
1950        self.track(frame);
1951        Ok(self)
1952    }
1953
1954    fn pop_inner(&mut self) -> Result<Option<Frame>, ReflectError> {
1955        let mut frame = match self.frames.pop() {
1956            Some(f) => f,
1957            None => return Ok(None),
1958        };
1959        #[cfg(feature = "log")]
1960        let frame_shape = frame.shape;
1961
1962        let init = frame.is_fully_initialized();
1963        trace!(
1964            "[{}] {} popped, {} initialized",
1965            self.frames.len(),
1966            frame_shape.blue(),
1967            if init {
1968                "✅ fully".style(owo_colors::Style::new().green())
1969            } else {
1970                "🚧 partially".style(owo_colors::Style::new().red())
1971            }
1972        );
1973        if init {
1974            if let Some(parent) = self.frames.last_mut() {
1975                if let Some(index) = frame.field_index_in_parent {
1976                    parent.istate.fields.set(index);
1977                }
1978            }
1979        }
1980
1981        // Handle special frame modes
1982        match frame.istate.mode {
1983            // Handle list element frames
1984            FrameMode::ListElement => {
1985                if frame.is_fully_initialized() {
1986                    // This was a list or tuple element, so we need to push it to the parent
1987                    #[cfg(feature = "log")]
1988                    let frame_len = self.frames.len();
1989
1990                    // Get parent frame
1991                    let parent_frame = self.frames.last_mut().unwrap();
1992                    let parent_shape = parent_frame.shape;
1993
1994                    match parent_shape.def {
1995                        // Handle List/Array
1996                        Def::List(list_def) => {
1997                            let list_vtable = list_def.vtable;
1998                            trace!(
1999                                "[{}] Pushing element to list {}",
2000                                frame_len,
2001                                parent_shape.blue()
2002                            );
2003                            unsafe {
2004                                (list_vtable.push)(
2005                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
2006                                    PtrMut::new(frame.data.as_mut_byte_ptr()),
2007                                );
2008                                self.mark_moved_out_of(&mut frame);
2009                            }
2010                        }
2011
2012                        // Handle Empty Unit Types (including empty tuple structs)
2013                        Def::Struct(sd)
2014                            if sd.kind == facet_core::StructKind::Tuple && sd.fields.is_empty() =>
2015                        {
2016                            trace!(
2017                                "[{}] Handling empty tuple struct unit type {}",
2018                                frame_len,
2019                                parent_shape.blue()
2020                            );
2021                            // Mark the parent unit struct as fully initialized
2022                            unsafe {
2023                                parent_frame.mark_fully_initialized();
2024                            }
2025                            // Element frame is implicitly moved/consumed, but nothing to dealloc if it was also unit
2026                            unsafe { self.mark_moved_out_of(&mut frame) };
2027                        }
2028                        Def::Scalar(s) if matches!(s.affinity, ScalarAffinity::Empty(_)) => {
2029                            trace!(
2030                                "[{}] Handling scalar empty unit type {}",
2031                                frame_len,
2032                                parent_shape.blue()
2033                            );
2034                            // Mark the parent scalar unit as fully initialized
2035                            unsafe {
2036                                parent_frame.mark_fully_initialized();
2037                                self.mark_moved_out_of(&mut frame);
2038                            }
2039                        }
2040
2041                        // Handle Tuple Structs
2042                        Def::Struct(sd) if sd.kind == facet_core::StructKind::Tuple => {
2043                            // Get the field index from list_index saved during push
2044                            let previous_index = parent_frame.istate.list_index.unwrap_or(1);
2045                            let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
2046
2047                            if field_index >= sd.fields.len() {
2048                                panic!(
2049                                    "Field index {} out of bounds for tuple struct {} with {} fields",
2050                                    field_index,
2051                                    parent_shape,
2052                                    sd.fields.len()
2053                                );
2054                            }
2055
2056                            let field = &sd.fields[field_index];
2057                            trace!(
2058                                "[{}] Setting tuple struct field {} ({}) of {}",
2059                                frame_len,
2060                                field_index.to_string().yellow(),
2061                                field.name.bright_blue(),
2062                                parent_shape.blue()
2063                            );
2064
2065                            unsafe {
2066                                // Copy the element data to the tuple field
2067                                let field_ptr = parent_frame.data.field_uninit_at(field.offset);
2068                                field_ptr
2069                                    .copy_from(
2070                                        PtrConst::new(frame.data.as_byte_ptr()),
2071                                        field.shape(),
2072                                    )
2073                                    .map_err(|_| ReflectError::Unsized {
2074                                        shape: field.shape(),
2075                                    })?; // Use ? to propagate potential unsized error
2076
2077                                // Mark the specific field as initialized using its index
2078                                parent_frame.istate.fields.set(field_index);
2079
2080                                // Mark the element as moved
2081                                self.mark_moved_out_of(&mut frame);
2082                            }
2083                        }
2084
2085                        // Handle Tuple Enum Variants
2086                        Def::Enum(_) => {
2087                            // Ensure a variant is selected and it's a tuple variant
2088                            let variant =
2089                                parent_frame.istate.variant.as_ref().unwrap_or_else(|| {
2090                                    panic!(
2091                                        "Popping element for enum {} but no variant was selected",
2092                                        parent_shape
2093                                    )
2094                                });
2095
2096                            if variant.data.kind != facet_core::StructKind::Tuple {
2097                                panic!(
2098                                    "Popping element for enum {}, but selected variant '{}' is not a tuple variant",
2099                                    parent_shape, variant.name
2100                                );
2101                            }
2102
2103                            // Get the field index from list_index saved during push
2104                            let previous_index = parent_frame.istate.list_index.unwrap_or(1);
2105                            let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
2106
2107                            if field_index >= variant.data.fields.len() {
2108                                panic!(
2109                                    "Field index {} out of bounds for tuple enum variant '{}' of {} with {} fields",
2110                                    field_index,
2111                                    variant.name,
2112                                    parent_shape,
2113                                    variant.data.fields.len()
2114                                );
2115                            }
2116
2117                            let field = &variant.data.fields[field_index];
2118                            trace!(
2119                                "[{}] Setting tuple enum variant field {} ({}) of variant '{}' in {}",
2120                                frame_len,
2121                                field_index.to_string().yellow(),
2122                                field.name.bright_blue(),
2123                                variant.name.yellow(),
2124                                parent_shape.blue()
2125                            );
2126
2127                            unsafe {
2128                                // Copy the element data to the tuple field within the enum's data payload
2129                                let field_ptr = parent_frame.data.field_uninit_at(field.offset);
2130                                field_ptr
2131                                    .copy_from(
2132                                        PtrConst::new(frame.data.as_byte_ptr()),
2133                                        field.shape(),
2134                                    )
2135                                    .map_err(|_| ReflectError::Unsized {
2136                                        shape: field.shape(),
2137                                    })?; // Use ? to propagate potential unsized error
2138
2139                                // Mark the specific field as initialized using its index
2140                                parent_frame.istate.fields.set(field_index);
2141
2142                                // Mark the element as moved
2143                                self.mark_moved_out_of(&mut frame);
2144                            }
2145                        }
2146
2147                        // Unexpected parent type
2148                        _ => {
2149                            panic!(
2150                                "FrameMode::ListElement pop expected parent to be List, Tuple Struct, or Tuple Enum Variant, but got {}",
2151                                parent_shape
2152                            );
2153                        }
2154                    }
2155                } else {
2156                    // Frame not fully initialized, just deallocate if needed (handled by Frame drop later)
2157                    trace!(
2158                        "Popping uninitialized ListElement frame ({}), potential leak if allocated resources are not managed",
2159                        frame.shape.yellow()
2160                    );
2161                }
2162            }
2163
2164            // Handle map value frames
2165            FrameMode::MapValue {
2166                index: key_frame_index,
2167            } if frame.is_fully_initialized() => {
2168                // This was a map value, so we need to insert the key-value pair into the map
2169
2170                // Now let's remove the key frame from the frames array
2171                let mut key_frame = self.frames.remove(key_frame_index);
2172
2173                // Make sure the key is fully initialized
2174                if !key_frame.istate.fields.is_any_set() {
2175                    panic!("key is not initialized when popping value frame");
2176                }
2177
2178                // Get parent map frame
2179                #[cfg(feature = "log")]
2180                let frame_len = self.frames.len();
2181                let parent_frame = self.frames.last_mut().unwrap();
2182                let parent_shape = parent_frame.shape;
2183
2184                // Make sure the parent is a map
2185                match parent_shape.def {
2186                    Def::Map(_) => {
2187                        // Get the map vtable from the MapDef
2188                        if let Def::Map(map_def) = parent_shape.def {
2189                            trace!(
2190                                "[{}] Inserting key-value pair into map {}",
2191                                frame_len,
2192                                parent_shape.blue()
2193                            );
2194                            unsafe {
2195                                // Call the map's insert function with the key and value
2196                                (map_def.vtable.insert_fn)(
2197                                    parent_frame.data.assume_init(),
2198                                    key_frame.data.assume_init(),
2199                                    PtrMut::new(frame.data.as_mut_byte_ptr()),
2200                                );
2201                                self.mark_moved_out_of(&mut key_frame);
2202                                self.mark_moved_out_of(&mut frame);
2203                            }
2204                        } else {
2205                            panic!("parent frame is not a map type");
2206                        }
2207                    }
2208                    _ => {
2209                        panic!("Expected map or hash map, got {}", frame.shape);
2210                    }
2211                }
2212            }
2213
2214            // Handle option frames
2215            FrameMode::OptionSome => {
2216                if frame.is_fully_initialized() {
2217                    trace!("Popping OptionSome (fully init'd)");
2218
2219                    // Get parent frame
2220                    #[cfg(feature = "log")]
2221                    let frames_len = self.frames.len();
2222                    let parent_frame = self.frames.last_mut().unwrap();
2223                    let parent_shape = parent_frame.shape;
2224
2225                    // Make sure the parent is an option
2226                    match parent_shape.def {
2227                        Def::Option(option_def) => {
2228                            trace!(
2229                                "[{}] Setting Some value in option {}",
2230                                frames_len,
2231                                parent_shape.blue()
2232                            );
2233                            unsafe {
2234                                // Call the option's init_some function
2235                                (option_def.vtable.init_some_fn)(
2236                                    parent_frame.data,
2237                                    PtrConst::new(frame.data.as_byte_ptr()),
2238                                );
2239                                trace!("Marking parent frame as fully initialized");
2240                                parent_frame.mark_fully_initialized();
2241
2242                                self.mark_moved_out_of(&mut frame);
2243                            }
2244                        }
2245                        _ => {
2246                            panic!(
2247                                "Expected parent frame to be an option type, got {}",
2248                                frame.shape
2249                            );
2250                        }
2251                    }
2252                } else {
2253                    trace!("Popping OptionSome (not fully init'd)");
2254                }
2255            }
2256
2257            // Map keys are just tracked, they don't need special handling when popped
2258            // FIXME: that's not true, we need to deallocate them at least??
2259            FrameMode::MapKey => {}
2260
2261            // Field frame
2262            FrameMode::Field => {}
2263
2264            // Uninitialized special frames
2265            _ => {}
2266        }
2267
2268        Ok(Some(frame))
2269    }
2270
2271    /// Evict a frame from istates, along with all its children
2272    /// (because we're about to use `drop_in_place` on it — not
2273    /// yet though, we need to know the variant for enums, etc.)
2274    pub fn evict_tree(&mut self, frame: Frame) -> Frame {
2275        match frame.shape.def {
2276            Def::Struct(sd) => {
2277                for f in sd.fields {
2278                    let id = ValueId {
2279                        shape: f.shape(),
2280                        ptr: unsafe { frame.data.field_uninit_at(f.offset) }.as_byte_ptr(),
2281                    };
2282                    if let Some(istate) = self.istates.remove(&id) {
2283                        let frame = Frame::recompose(id, istate);
2284                        self.evict_tree(frame);
2285                    } else {
2286                        trace!("No istate found for field {}", f.name);
2287                    }
2288                }
2289            }
2290            Def::Enum(_ed) => {
2291                // Check if a variant is selected in the istate
2292                if let Some(variant) = &frame.istate.variant {
2293                    trace!(
2294                        "Evicting enum {} variant '{}' fields",
2295                        frame.shape.blue(),
2296                        variant.name.yellow()
2297                    );
2298                    // Iterate over the fields of the selected variant
2299                    for field in variant.data.fields {
2300                        // Calculate the pointer to the field within the enum's data payload
2301                        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
2302                        let field_shape = field.shape();
2303                        let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
2304
2305                        // Try to remove the field's state from istates
2306                        if let Some(field_istate) = self.istates.remove(&field_id) {
2307                            trace!(
2308                                "Evicting field '{}' (shape {}) of enum variant '{}'",
2309                                field.name.bright_blue(),
2310                                field_shape.green(),
2311                                variant.name.yellow()
2312                            );
2313                            // Recompose the frame for the field
2314                            let field_frame = Frame::recompose(field_id, field_istate);
2315                            // Recursively evict the field's subtree
2316                            self.evict_tree(field_frame);
2317                        } else {
2318                            trace!(
2319                                "Field '{}' (shape {}) of enum variant '{}' not found in istates, skipping eviction",
2320                                field.name.red(),
2321                                field_shape.red(),
2322                                variant.name.yellow()
2323                            );
2324                        }
2325                    }
2326                } else {
2327                    // No variant selected, nothing to evict within the enum
2328                    trace!(
2329                        "Enum {} has no variant selected, no fields to evict.",
2330                        frame.shape.blue()
2331                    );
2332                }
2333            }
2334            _ => {}
2335        }
2336        frame
2337    }
2338
2339    #[allow(rustdoc::broken_intra_doc_links)]
2340    /// Returns the current path in the JSON document as a string.
2341    /// For example: "$.users[0].name"
2342    pub fn path(&self) -> String {
2343        let mut path = String::from("$");
2344
2345        for (i, frame) in self.frames.iter().enumerate() {
2346            // Skip the root frame
2347            if i == 0 {
2348                continue;
2349            }
2350
2351            match frame.istate.mode {
2352                FrameMode::ListElement => {
2353                    // For arrays, we use bracket notation with index
2354                    if let Some(index) = frame.istate.list_index {
2355                        path.push_str(&format!("[{}]", index));
2356                    } else {
2357                        path.push_str("[?]");
2358                    }
2359                }
2360                FrameMode::MapKey => {
2361                    path.push_str(".key");
2362                }
2363                FrameMode::MapValue { index: _ } => {
2364                    path.push_str(".value");
2365                }
2366                FrameMode::OptionSome => {
2367                    path.push_str(".some");
2368                }
2369                FrameMode::OptionNone => {
2370                    path.push_str(".none");
2371                }
2372                FrameMode::Root => {
2373                    // Root doesn't add to the path
2374                }
2375                FrameMode::Field => {
2376                    // For struct fields, we use dot notation with field name
2377                    if let Some(index) = frame.field_index_in_parent {
2378                        // Find the parent frame to get the field name
2379                        if let Some(parent) = self.frames.get(i - 1) {
2380                            if let Def::Struct(sd) = parent.shape.def {
2381                                if index < sd.fields.len() {
2382                                    let field_name = sd.fields[index].name;
2383                                    path.push('.');
2384                                    path.push_str(field_name);
2385                                }
2386                            } else if let Def::Enum(_) = parent.shape.def {
2387                                if let Some(variant) = &parent.istate.variant {
2388                                    if index < variant.data.fields.len() {
2389                                        let field_name = variant.data.fields[index].name;
2390                                        path.push('.');
2391                                        path.push_str(field_name);
2392                                    }
2393                                }
2394                            }
2395                        }
2396                    }
2397                }
2398            }
2399        }
2400
2401        path
2402    }
2403
2404    /// Returns true if the field at the given index is set (initialized) in the current frame.
2405    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
2406        let frame = self.frames.last().ok_or(ReflectError::OperationFailed {
2407            shape: <()>::SHAPE,
2408            operation: "tried to check if field is set, but there was no frame",
2409        })?;
2410
2411        match frame.shape.def {
2412            Def::Struct(ref sd) => {
2413                if index >= sd.fields.len() {
2414                    return Err(ReflectError::FieldError {
2415                        shape: frame.shape,
2416                        field_error: FieldError::NoSuchField,
2417                    });
2418                }
2419                Ok(frame.istate.fields.has(index))
2420            }
2421            Def::Enum(_) => {
2422                let variant = frame.istate.variant.as_ref().ok_or(
2423                    ReflectError::OperationFailed {
2424                        shape: frame.shape,
2425                        operation: "tried to check if field is set, but no variant was selected",
2426                    },
2427                )?;
2428                if index >= variant.data.fields.len() {
2429                    return Err(ReflectError::FieldError {
2430                        shape: frame.shape,
2431                        field_error: FieldError::NoSuchField,
2432                    });
2433                }
2434                Ok(frame.istate.fields.has(index))
2435            }
2436            _ => Err(ReflectError::WasNotA {
2437                expected: "struct or enum",
2438                actual: frame.shape,
2439            }),
2440        }
2441    }
2442}
2443
2444impl Drop for Wip<'_> {
2445    fn drop(&mut self) {
2446        trace!("🧹🧹🧹 WIP is dropping");
2447
2448        while let Some(frame) = self.frames.pop() {
2449            self.track(frame);
2450        }
2451
2452        let Some((root_id, _)) = self.istates.iter().find(|(_k, istate)| istate.depth == 0) else {
2453            trace!("No root found, we probably built already");
2454            return;
2455        };
2456
2457        let root_id = *root_id;
2458        let root_istate = self.istates.remove(&root_id).unwrap();
2459        let root = Frame::recompose(root_id, root_istate);
2460        let mut to_clean = vec![root];
2461
2462        let mut _root_guard: Option<Guard> = None;
2463
2464        while let Some(mut frame) = to_clean.pop() {
2465            trace!(
2466                "Cleaning frame: shape={} at {:p}, flags={:?}, mode={:?}, fully_initialized={}",
2467                frame.shape.blue(),
2468                frame.data.as_byte_ptr(),
2469                frame.istate.flags.bright_magenta(),
2470                frame.istate.mode.yellow(),
2471                if frame.is_fully_initialized() {
2472                    "✅"
2473                } else {
2474                    "❌"
2475                }
2476            );
2477
2478            if frame.istate.flags.contains(FrameFlags::MOVED) {
2479                trace!(
2480                    "{}",
2481                    "Frame was moved out of, nothing to dealloc/drop_in_place".yellow()
2482                );
2483                continue;
2484            }
2485
2486            match frame.shape.def {
2487                Def::Struct(sd) => {
2488                    if frame.is_fully_initialized() {
2489                        trace!(
2490                            "Dropping fully initialized struct: {} at {:p}",
2491                            frame.shape.green(),
2492                            frame.data.as_byte_ptr()
2493                        );
2494                        let frame = self.evict_tree(frame);
2495                        unsafe { frame.drop_and_dealloc_if_needed() };
2496                    } else {
2497                        let num_fields = sd.fields.len();
2498                        trace!(
2499                            "De-initializing struct {} at {:p} field-by-field ({} fields)",
2500                            frame.shape.yellow(),
2501                            frame.data.as_byte_ptr(),
2502                            num_fields.to_string().bright_cyan()
2503                        );
2504                        for i in 0..num_fields {
2505                            if frame.istate.fields.has(i) {
2506                                let field = sd.fields[i];
2507                                let field_shape = field.shape();
2508                                let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
2509                                let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
2510                                trace!(
2511                                    "Recursively cleaning field #{} '{}' of {}: field_shape={}, field_ptr={:p}",
2512                                    i.to_string().bright_cyan(),
2513                                    field.name.bright_blue(),
2514                                    frame.shape.blue(),
2515                                    field_shape.green(),
2516                                    field_ptr.as_byte_ptr()
2517                                );
2518                                let istate = self.istates.remove(&field_id).unwrap();
2519                                let field_frame = Frame::recompose(field_id, istate);
2520                                to_clean.push(field_frame);
2521                            } else {
2522                                trace!(
2523                                    "Field #{} '{}' of {} was NOT initialized, skipping",
2524                                    i.to_string().bright_cyan(),
2525                                    sd.fields[i].name.bright_red(),
2526                                    frame.shape.red()
2527                                );
2528                            }
2529                        }
2530
2531                        // we'll also need to clean up if we're root
2532                        if frame.istate.mode == FrameMode::Root {
2533                            if let Ok(layout) = frame.shape.layout.sized_layout() {
2534                                _root_guard = Some(Guard {
2535                                    ptr: frame.data.as_mut_byte_ptr(),
2536                                    layout,
2537                                });
2538                            }
2539                        }
2540                    }
2541                }
2542                Def::Enum(_ed) => {
2543                    trace!(
2544                        "{}",
2545                        format_args!(
2546                            "TODO: handle enum deallocation for {} at {:p}",
2547                            frame.shape.yellow(),
2548                            frame.data.as_byte_ptr()
2549                        )
2550                        .magenta()
2551                    );
2552
2553                    // we'll also need to clean up if we're root
2554                    if frame.istate.mode == FrameMode::Root {
2555                        if let Ok(layout) = frame.shape.layout.sized_layout() {
2556                            _root_guard = Some(Guard {
2557                                ptr: frame.data.as_mut_byte_ptr(),
2558                                layout,
2559                            });
2560                        }
2561                    }
2562                }
2563                Def::Array(_)
2564                | Def::Slice(_)
2565                | Def::List(_)
2566                | Def::Map(_)
2567                | Def::SmartPointer(_)
2568                | Def::Scalar(_)
2569                | Def::FunctionPointer(_)
2570                | Def::Option(_) => {
2571                    trace!(
2572                        "Can drop all at once for shape {} (def variant: {:?}, frame mode {:?}) at {:p}",
2573                        frame.shape.cyan(),
2574                        frame.shape.def,
2575                        frame.istate.mode.yellow(),
2576                        frame.data.as_byte_ptr(),
2577                    );
2578
2579                    if frame.is_fully_initialized() {
2580                        unsafe { frame.drop_and_dealloc_if_needed() }
2581                    } else {
2582                        frame.dealloc_if_needed();
2583                    }
2584                }
2585                _ => {}
2586            }
2587        }
2588
2589        // We might have some frames left over to deallocate for temporary allocations for keymap insertion etc.
2590        let mut all_ids = self.istates.keys().copied().collect::<Vec<_>>();
2591        for frame_id in all_ids.drain(..) {
2592            let frame_istate = self.istates.remove(&frame_id).unwrap();
2593
2594            trace!(
2595                "Checking leftover istate: id.shape={} id.ptr={:p} mode={:?}",
2596                frame_id.shape.cyan(),
2597                frame_id.ptr,
2598                frame_istate.mode.yellow()
2599            );
2600            let mut frame = Frame::recompose(frame_id, frame_istate);
2601
2602            if frame.is_fully_initialized() {
2603                trace!("It's fully initialized, we can drop it");
2604                unsafe { frame.drop_and_dealloc_if_needed() };
2605            } else if frame.istate.flags.contains(FrameFlags::ALLOCATED) {
2606                trace!("Not initialized but allocated, let's free it");
2607                frame.dealloc_if_needed();
2608            }
2609        }
2610    }
2611}