facet_reflect/wip/
mod.rs

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