facet_reflect/wip/
mod.rs

1use crate::{ReflectError, ValueId};
2use crate::{debug, trace};
3#[cfg(feature = "log")]
4use alloc::string::ToString;
5#[cfg(feature = "log")]
6use owo_colors::OwoColorize;
7
8use alloc::format;
9use alloc::{vec, vec::Vec};
10use bitflags::bitflags;
11use core::{fmt, marker::PhantomData};
12use facet_core::{Def, Facet, FieldError, PtrConst, PtrMut, PtrUninit, Shape, Variant};
13use flat_map::FlatMap;
14
15use alloc::string::String;
16
17mod iset;
18pub use iset::*;
19
20mod enum_;
21mod flat_map;
22
23mod heap_value;
24pub use heap_value::*;
25
26fn def_kind(def: &Def) -> &'static str {
27    match def {
28        Def::Scalar(_) => "scalar",
29        Def::Struct(_) => "struct",
30        Def::Map(_) => "map",
31        Def::List(_) => "list",
32        Def::Enum(_) => "enum",
33        Def::Option(_) => "option",
34        Def::SmartPointer(_) => "smart_ptr",
35        _ => "other",
36    }
37}
38
39/// Represents a frame in the initialization stack
40pub struct Frame {
41    /// The value we're initializing
42    data: PtrUninit<'static>,
43
44    /// The shape of the value
45    shape: &'static Shape,
46
47    /// If set, when we're initialized, we must mark the
48    /// parent's indexth field as initialized.
49    field_index_in_parent: Option<usize>,
50
51    /// Tracking which of our fields are initialized
52    /// TODO: I'm not sure we should track "ourselves" as initialized — we always have the
53    /// parent to look out for, right now we're tracking children in two states, which isn't ideal
54    istate: IState,
55}
56
57impl Frame {
58    /// Given a ValueId and an IState, recompose a Frame suitable for tracking
59    fn recompose(id: ValueId, istate: IState) -> Self {
60        Frame {
61            data: PtrUninit::new(id.ptr as *mut u8),
62            shape: id.shape,
63            field_index_in_parent: None,
64            istate,
65        }
66    }
67
68    /// Deallocates the memory used by this frame if it was heap-allocated.
69    fn dealloc_if_needed(&mut self) {
70        if self.istate.flags.contains(FrameFlags::ALLOCATED) {
71            trace!(
72                "[{}] {:p} => deallocating {}",
73                self.istate.depth,
74                self.data.as_mut_byte_ptr().magenta(),
75                self.shape.green(),
76            );
77            if self.shape.layout.size() != 0 {
78                unsafe {
79                    alloc::alloc::dealloc(self.data.as_mut_byte_ptr(), self.shape.layout);
80                }
81            }
82            self.istate.flags.remove(FrameFlags::ALLOCATED);
83        } else {
84            trace!(
85                "[{}] {:p} => NOT deallocating {} (not ALLOCATED)",
86                self.istate.depth,
87                self.data.as_mut_byte_ptr().magenta(),
88                self.shape.green(),
89            );
90        }
91    }
92}
93
94struct DebugToDisplay<T>(T);
95
96impl<T> fmt::Debug for DebugToDisplay<T>
97where
98    T: fmt::Display,
99{
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        fmt::Display::fmt(&self.0, f)
102    }
103}
104
105impl fmt::Debug for Frame {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.debug_struct("Frame")
108            .field("shape", &DebugToDisplay(&self.shape))
109            .field("kind", &def_kind(&self.shape.def))
110            .field("index", &self.field_index_in_parent)
111            .field("mode", &self.istate.mode)
112            .finish()
113    }
114}
115
116impl Frame {
117    /// Returns the value ID for a frame
118    fn id(&self) -> ValueId {
119        ValueId::new(self.shape, self.data.as_byte_ptr())
120    }
121
122    /// Returns true if the frame is fully initialized
123    fn is_fully_initialized(&self) -> bool {
124        match self.shape.def {
125            Def::Struct(sd) => self.istate.fields.are_all_set(sd.fields.len()),
126            Def::Enum(_) => match self.istate.variant.as_ref() {
127                None => false,
128                Some(v) => self.istate.fields.are_all_set(v.data.fields.len()),
129            },
130            _ => self.istate.fields.are_all_set(1),
131        }
132    }
133
134    // Safety: only call if is fully initialized
135    unsafe fn drop_and_dealloc_if_needed(mut self) {
136        trace!(
137            "[Frame::drop] Dropping frame for shape {} at {:p}",
138            self.shape.blue(),
139            self.data.as_byte_ptr()
140        );
141        if let Some(drop_in_place) = self.shape.vtable.drop_in_place {
142            unsafe {
143                trace!(
144                    "[Frame::drop] Invoking drop_in_place for shape {} at {:p}",
145                    self.shape.green(),
146                    self.data.as_byte_ptr()
147                );
148                drop_in_place(self.data.assume_init());
149            }
150        } else {
151            trace!(
152                "[Frame::drop] No drop_in_place function for shape {}",
153                self.shape.blue(),
154            );
155        }
156        self.dealloc_if_needed();
157    }
158
159    /// Marks the frame as fully initialized
160    unsafe fn mark_fully_initialized(&mut self) {
161        match self.shape.def {
162            Def::Struct(sd) => {
163                self.istate.fields = ISet::all(sd.fields);
164            }
165            Def::Enum(_) => {
166                if let Some(variant) = &self.istate.variant {
167                    self.istate.fields = ISet::all(variant.data.fields);
168                }
169            }
170            _ => {
171                self.istate.fields.set(0);
172            }
173        }
174    }
175}
176
177/// Initialization state
178struct IState {
179    /// Variant chosen — for everything except enums, this stays None
180    variant: Option<Variant>,
181
182    /// Fields that were initialized. For scalars, we only track 0
183    fields: ISet,
184
185    /// The depth of the frame in the stack
186    depth: usize,
187
188    /// The special mode of this frame (if any)
189    mode: FrameMode,
190
191    /// If true, must be freed when dropped
192    flags: FrameFlags,
193
194    /// The current index for list elements
195    list_index: Option<usize>,
196
197    /// The current key for map elements
198    #[allow(dead_code)]
199    map_key: Option<String>,
200}
201
202bitflags! {
203    /// Flags that can be applied to frames
204    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205    pub struct FrameFlags: u64 {
206        /// An empty set of flags
207        const EMPTY = 0;
208
209        /// We allocated this frame on the heap, we need to deallocated it when popping
210        const ALLOCATED = 1 << 0;
211
212        /// This value was moved out of — it's not part of the value we're building and
213        /// we shouldn't error out when we build and we notice it's not initialized.
214        /// In fact, it should not be tracked at all.
215        const MOVED = 1 << 1;
216    }
217
218    // Note: there is no 'initialized' flag because initialization can be partial — it's tracked via `ISet`
219}
220
221impl IState {
222    /// Creates a new `IState` with the given depth.
223    pub fn new(depth: usize, mode: FrameMode, flags: FrameFlags) -> Self {
224        Self {
225            variant: None,
226            fields: Default::default(),
227            depth,
228            mode,
229            flags,
230            list_index: None,
231            map_key: None,
232        }
233    }
234
235    /// Sets the list index and returns self for method chaining
236    #[allow(dead_code)]
237    pub fn with_list_index(mut self, index: usize) -> Self {
238        self.list_index = Some(index);
239        self
240    }
241
242    /// Sets the map key and returns self for method chaining
243    #[allow(dead_code)]
244    pub fn with_map_key(mut self, key: String) -> Self {
245        self.map_key = Some(key);
246        self
247    }
248}
249
250/// Represents the special mode a frame can be in
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum FrameMode {
253    /// Root frame
254    Root,
255    /// Struct field
256    Field,
257    /// Frame represents a list element
258    ListElement,
259    /// Frame represents a map key
260    MapKey,
261    /// Frame represents a map value with the given key frame index
262    MapValue {
263        /// The index of the key frame associated with this map value
264        index: usize,
265    },
266    /// Frame represents the Some variant of an option (that we allocated)
267    OptionSome,
268    /// Frame represents the None variant of an option (no allocation needed)
269    /// Any `put` should fail
270    OptionNone,
271}
272
273/// A work-in-progress heap-allocated value
274pub struct Wip<'a> {
275    /// stack of frames to keep track of deeply nested initialization
276    frames: alloc::vec::Vec<Frame>,
277
278    /// keeps track of initialization of out-of-tree frames
279    istates: FlatMap<ValueId, IState>,
280
281    /// lifetime of the shortest reference we hold
282    phantom: PhantomData<&'a ()>,
283}
284
285impl<'a> Wip<'a> {
286    /// Returns the number of frames on the stack
287    pub fn frames_count(&self) -> usize {
288        self.frames.len()
289    }
290
291    /// Allocates a new value of the given shape
292    pub fn alloc_shape(shape: &'static Shape) -> Self {
293        let data = shape.allocate();
294        Self {
295            frames: alloc::vec![Frame {
296                data,
297                shape,
298                field_index_in_parent: None,
299                istate: IState::new(0, FrameMode::Root, FrameFlags::ALLOCATED),
300            }],
301            istates: Default::default(),
302            phantom: PhantomData,
303        }
304    }
305
306    /// Allocates a new value of type `S`
307    pub fn alloc<S: Facet>() -> Self {
308        Self::alloc_shape(S::SHAPE)
309    }
310
311    fn track(&mut self, frame: Frame) {
312        // fields might be partially initialized (in-place) and then
313        // we might come back to them, so because they're popped off
314        // the stack, we still need to track them _somewhere_
315        //
316        // the root also relies on being tracked in the drop impl
317        if !frame.istate.flags.contains(FrameFlags::MOVED) {
318            self.istates.insert(frame.id(), frame.istate);
319        }
320    }
321
322    unsafe fn mark_moved_out_of(&mut self, frame: &mut Frame) {
323        frame.dealloc_if_needed();
324        ISet::clear(&mut frame.istate.fields);
325        frame.istate.variant = None;
326        frame.istate.flags.insert(FrameFlags::MOVED);
327        // make sure this isn't tracked here anymore — we don't want to have
328        // any metadata associated with it that gets restored by mistake
329        self.istates.remove(&frame.id());
330    }
331
332    /// Returns the shape of the current frame
333    pub fn shape(&self) -> &'static Shape {
334        self.frames.last().unwrap().shape
335    }
336
337    /// Return true if the last frame is in option mode
338    pub fn in_option(&self) -> bool {
339        let Some(frame) = self.frames.last() else {
340            return false;
341        };
342        matches!(frame.istate.mode, FrameMode::OptionSome)
343    }
344
345    /// Returns the mode of the current frame
346    pub fn mode(&self) -> FrameMode {
347        self.frames.last().unwrap().istate.mode
348    }
349
350    /// Asserts everything is initialized and that invariants are upheld (if any)
351    pub fn build(mut self) -> Result<HeapValue<'a>, ReflectError> {
352        debug!("[{}] ⚒️ It's BUILD time", self.frames.len());
353
354        // 1. Track all frames currently on the stack into istates
355        while let Some(frame) = self.pop_inner() {
356            self.track(frame);
357        }
358
359        // 2. Find the root frame
360        let Some((root_id, _)) = self.istates.iter().find(|(_k, istate)| istate.depth == 0) else {
361            debug!("No root found, possibly already built or empty WIP");
362            return Err(ReflectError::OperationFailed {
363                shape: <()>::SHAPE,
364                operation: "tried to build a value but there was no root frame tracked",
365            });
366        };
367
368        let root_id = *root_id;
369        // We need to *keep* the root istate for the check, so we clone it or get it immutably.
370        // Let's retrieve it immutably first. The `istates` map will be dropped with `Wip` anyway.
371        let root_istate = self
372            .istates
373            .remove(&root_id)
374            .expect("Root ID found but not present in istates, this is a bug"); // Clone needed to avoid borrowing issues later potentially
375
376        let root_frame = Frame::recompose(root_id, root_istate);
377        let root_shape = root_frame.shape;
378        let root_data_ptr = root_frame.data; // Keep the root pointer for the final HeapValue
379
380        // 6. Transfer ownership of the root data to the HeapValue
381        // The root frame should have had the ALLOCATED flag if it was heap allocated.
382        // We need to ensure the Guard takes ownership correctly.
383        // Find the original root istate again to check the flag.
384        let guard = Guard {
385            ptr: root_data_ptr.as_mut_byte_ptr(),
386            layout: root_shape.layout,
387        };
388
389        // 3. Initialize `to_check`
390        let mut to_check = alloc::vec![root_frame];
391
392        // 4. Traverse the tree
393        while let Some(frame) = to_check.pop() {
394            trace!(
395                "Checking frame: shape={} at {:p}, flags={:?}, mode={:?}",
396                frame.shape.blue(),
397                frame.data.as_byte_ptr(),
398                frame.istate.flags.bright_magenta(),
399                frame.istate.mode,
400            );
401
402            // Skip moved frames
403            if frame.istate.flags.contains(FrameFlags::MOVED) {
404                trace!(
405                    "{}",
406                    "Frame was moved out of, skipping initialization check".yellow()
407                );
408                continue;
409            }
410
411            // Check initialization for the current frame
412            match frame.shape.def {
413                Def::Struct(sd) => {
414                    if !frame.is_fully_initialized() {
415                        // find the field that's not initialized
416                        for i in 0..sd.fields.len() {
417                            if !frame.istate.fields.has(i) {
418                                let field = &sd.fields[i];
419                                return Err(ReflectError::UninitializedField {
420                                    shape: frame.shape,
421                                    field_name: field.name,
422                                });
423                            }
424                        }
425                        // Should be unreachable
426                        unreachable!(
427                            "Enum variant not fully initialized but couldn't find which field"
428                        );
429                    }
430
431                    // If initialized, push children to check stack
432                    #[allow(clippy::unused_enumerate_index)]
433                    for (_i, field) in sd.fields.iter().enumerate() {
434                        let field_shape = field.shape();
435                        let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
436                        let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
437
438                        if let Some(field_istate) = self.istates.remove(&field_id) {
439                            debug!(
440                                "Queueing struct field check: #{} '{}' of {}: shape={}, ptr={:p}",
441                                _i.to_string().bright_cyan(),
442                                field.name.bright_blue(),
443                                frame.shape.blue(),
444                                field_shape.green(),
445                                field_ptr.as_byte_ptr()
446                            );
447                            let field_frame = Frame::recompose(field_id, field_istate);
448                            to_check.push(field_frame);
449                        }
450                    }
451                }
452                Def::Enum(_ed) => {
453                    if let Some(variant) = &frame.istate.variant {
454                        if !frame.istate.fields.are_all_set(variant.data.fields.len()) {
455                            // Find the uninitialized field
456                            for (i, field) in variant.data.fields.iter().enumerate() {
457                                if !frame.istate.fields.has(i) {
458                                    return Err(ReflectError::UninitializedEnumField {
459                                        shape: frame.shape,
460                                        variant_name: variant.name,
461                                        field_name: field.name,
462                                    });
463                                }
464                            }
465                            // Should be unreachable
466                            unreachable!(
467                                "Enum variant not fully initialized but couldn't find which field"
468                            );
469                        }
470
471                        // If initialized, push children to check stack
472                        #[allow(clippy::unused_enumerate_index)]
473                        for (_i, field) in variant.data.fields.iter().enumerate() {
474                            let field_shape = field.shape();
475                            // Enum fields are potentially at different offsets depending on the variant layout.
476                            // We assume the `frame.data` points to the start of the enum's data payload
477                            // (after the discriminant if applicable and handled by layout).
478                            let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
479                            let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
480
481                            if let Some(field_istate) = self.istates.remove(&field_id) {
482                                debug!(
483                                    "Queueing enum field check: #{} '{}' of variant '{}' of {}: shape={}, ptr={:p}",
484                                    _i.to_string().bright_cyan(),
485                                    field.name.bright_blue(),
486                                    variant.name.yellow(),
487                                    frame.shape.blue(),
488                                    field_shape.green(),
489                                    field_ptr.as_byte_ptr()
490                                );
491                                let field_frame = Frame::recompose(field_id, field_istate);
492                                to_check.push(field_frame);
493                            }
494                        }
495                    } else {
496                        // No variant selected is an error during build
497                        return Err(ReflectError::NoVariantSelected { shape: frame.shape });
498                    }
499                }
500                // For types that manage their own contents (List, Map, Option, Scalar, etc.),
501                // we just need to check if the *container* itself is marked as initialized.
502                // The recursive check handles struct/enum *elements* within these containers if they exist.
503                Def::List(_)
504                | Def::Map(_)
505                | Def::Option(_)
506                | Def::Scalar(_)
507                | Def::SmartPointer(_)
508                | Def::Array(_)
509                | Def::Slice(_) => {
510                    if !frame.istate.fields.are_all_set(1) {
511                        // Check specific modes for better errors
512                        match frame.istate.mode {
513                            FrameMode::OptionNone => {
514                                // This should technically be marked initialized, but if not, treat as uninit Option
515                                return Err(ReflectError::UninitializedValue {
516                                    shape: frame.shape,
517                                });
518                            }
519                            // Add more specific checks if needed, e.g., for lists/maps that started but weren't finished?
520                            _ => {
521                                return Err(ReflectError::UninitializedValue {
522                                    shape: frame.shape,
523                                });
524                            }
525                        }
526                    }
527                    // No children to push onto `to_check` from the perspective of the *container* frame itself.
528                    // If a List contains Structs, those struct frames would have been pushed/popped
529                    // and their states tracked individually in `istates`, and checked when encountered via
530                    // `to_check` if they were fields of another struct/enum.
531                    // The `Drop` logic handles cleaning these contained items based on the container's drop_in_place.
532                    // For `build`, we trust that if the container is marked initialized, its contents are valid
533                    // according to its type's rules.
534                }
535                // Handle other Def variants if necessary
536                _ => {
537                    // Default: Check if initialized using the standard method
538                    if !frame.istate.fields.are_all_set(1) {
539                        return Err(ReflectError::UninitializedValue { shape: frame.shape });
540                    }
541                }
542            }
543        }
544
545        // If we finished the loop, all reachable and non-moved frames are initialized.
546        debug!("All reachable frames checked and initialized.");
547
548        // 5. Check invariants on the root
549        let data = unsafe { root_data_ptr.assume_init() };
550        if let Some(invariant_fn) = root_shape.vtable.invariants {
551            debug!(
552                "Checking invariants for root shape {} at {:p}",
553                root_shape.green(),
554                data.as_byte_ptr()
555            );
556            if !unsafe { invariant_fn(PtrConst::new(data.as_byte_ptr())) } {
557                return Err(ReflectError::InvariantViolation {
558                    invariant: "Custom validation function returned false",
559                });
560            }
561        } else {
562            debug!(
563                "No invariants to check for root shape {}",
564                root_shape.blue()
565            );
566        }
567
568        FlatMap::clear(&mut self.istates); // Prevent Drop from running on the successfully built value.
569
570        Ok(HeapValue {
571            guard: Some(guard),
572            shape: root_shape,
573            phantom: PhantomData,
574        })
575    }
576
577    /// Selects a field of a struct or enum variant by index and pushes it onto the frame stack.
578    ///
579    /// # Arguments
580    ///
581    /// * `index` - The index of the field to select.
582    ///
583    /// # Returns
584    ///
585    /// * `Ok(Self)` if the field was successfully selected and pushed.
586    /// * `Err(ReflectError)` if the current frame is not a struct or an enum with a selected variant,
587    ///   or if the field doesn't exist.
588    pub fn field(mut self, index: usize) -> Result<Self, ReflectError> {
589        let frame = self.frames.last_mut().unwrap();
590        let shape = frame.shape;
591
592        let (field, field_offset) = match shape.def {
593            Def::Struct(def) => {
594                if index >= def.fields.len() {
595                    return Err(ReflectError::FieldError {
596                        shape,
597                        field_error: FieldError::NoSuchField,
598                    });
599                }
600                let field = &def.fields[index];
601                (field, field.offset)
602            }
603            Def::Enum(_) => {
604                let Some(variant) = frame.istate.variant.as_ref() else {
605                    return Err(ReflectError::OperationFailed {
606                        shape,
607                        operation: "tried to access a field but no variant was selected",
608                    });
609                };
610
611                if index >= variant.data.fields.len() {
612                    return Err(ReflectError::FieldError {
613                        shape,
614                        field_error: FieldError::NoSuchField,
615                    });
616                }
617
618                let field = &variant.data.fields[index];
619                (field, field.offset)
620            }
621            _ => {
622                return Err(ReflectError::WasNotA {
623                    expected: "struct or enum",
624                    actual: shape,
625                });
626            }
627        };
628
629        let field_data = unsafe { frame.data.field_uninit_at(field_offset) };
630
631        let mut frame = Frame {
632            data: field_data,
633            shape: field.shape(),
634            field_index_in_parent: Some(index),
635            // we didn't have to allocate that field, it's a struct field, so it's not allocated
636            istate: IState::new(self.frames.len(), FrameMode::Field, FrameFlags::EMPTY),
637        };
638        debug!(
639            "[{}] Selecting field {} ({}#{}) of {}",
640            self.frames.len(),
641            field.name.blue(),
642            field.shape().green(),
643            index.yellow(),
644            shape.blue(),
645        );
646        if let Some(iset) = self.istates.remove(&frame.id()) {
647            trace!(
648                "[{}] Restoring saved state for {} (istate.mode = {:?}, istate.fields = {:?}, istate.flags = {:?}, istate.depth = {:?})",
649                self.frames.len(),
650                frame.id().shape.blue(),
651                iset.mode,
652                iset.fields,
653                iset.flags,
654                iset.depth
655            );
656            frame.istate = iset;
657        } else {
658            trace!(
659                "[{}] no saved state for field {} ({}#{}) of {}",
660                self.frames.len(),
661                field.name.blue(),
662                field.shape().green(),
663                index.yellow(),
664                shape.blue(),
665            );
666        }
667        self.frames.push(frame);
668        Ok(self)
669    }
670
671    /// Finds the index of a field in a struct or enum variant by name.
672    ///
673    /// # Arguments
674    ///
675    /// * `name` - The name of the field to find.
676    ///
677    /// # Returns
678    ///
679    /// * `Some(usize)` if the field was found.
680    /// * `None` if the current frame is not a struct or an enum with a selected variant,
681    ///   or if the field doesn't exist.
682    pub fn field_index(&self, name: &str) -> Option<usize> {
683        let frame = self.frames.last()?;
684        match frame.shape.def {
685            Def::Struct(def) => def.fields.iter().position(|f| f.name == name),
686            Def::Enum(_) => {
687                // Get the selected variant
688                let variant = frame.istate.variant.as_ref()?;
689                variant.data.fields.iter().position(|f| f.name == name)
690            }
691            _ => None,
692        }
693    }
694
695    /// Selects a field of a struct or enum variant by name and pushes it onto the frame stack.
696    ///
697    /// # Arguments
698    ///
699    /// * `name` - The name of the field to select.
700    ///
701    /// # Returns
702    ///
703    /// * `Ok(Self)` if the field was successfully selected and pushed.
704    /// * `Err(ReflectError)` if the current frame is not a struct or an enum with a selected variant,
705    ///   or if the field doesn't exist.
706    pub fn field_named(self, name: &str) -> Result<Self, ReflectError> {
707        let frame = self.frames.last().unwrap();
708        let shape = frame.shape;
709
710        // For enums, ensure a variant is selected
711        if let Def::Enum(_) = shape.def {
712            if frame.istate.variant.is_none() {
713                return Err(ReflectError::OperationFailed {
714                    shape,
715                    operation: "tried to access a field by name but no variant was selected",
716                });
717            }
718        }
719
720        let index = self.field_index(name).ok_or(ReflectError::FieldError {
721            shape,
722            field_error: FieldError::NoSuchField,
723        })?;
724
725        self.field(index)
726    }
727
728    /// Puts a value of type `T` into the current frame.
729    ///
730    /// # Arguments
731    ///
732    /// * `t` - The value to put into the frame.
733    ///
734    /// # Returns
735    ///
736    /// * `Ok(Self)` if the value was successfully put into the frame.
737    /// * `Err(ReflectError)` if there was an error putting the value into the frame.
738    pub fn put<'val, T: Facet + 'val>(mut self, t: T) -> Result<Wip<'val>, ReflectError>
739    where
740        'a: 'val,
741    {
742        let Some(frame) = self.frames.last_mut() else {
743            return Err(ReflectError::OperationFailed {
744                shape: T::SHAPE,
745                operation: "tried to put a T but there was no frame to put T into",
746            });
747        };
748
749        // check that the type matches
750        if !frame.shape.is_type::<T>() {
751            // maybe we're putting into an Option<T> ?
752            if frame.shape.is_type::<Option<T>>() {
753                debug!("Putting into an option!");
754                let Def::Option(od) = frame.shape.def else {
755                    unreachable!()
756                };
757
758                // unfortunately this all involves copying data over
759                let src = PtrConst::new(&raw const t);
760                if frame.istate.fields.is_any_set() {
761                    let data = unsafe { frame.data.assume_init() };
762                    unsafe { (od.vtable.replace_with_fn)(data, Some(src)) };
763                } else {
764                    let data = frame.data;
765                    unsafe { (od.vtable.init_some_fn)(data, src) };
766                }
767                unsafe {
768                    frame.mark_fully_initialized();
769                }
770                // t will drop naturally at the end of this function
771
772                let shape = frame.shape;
773                let index = frame.field_index_in_parent;
774
775                // mark the field as initialized
776                self.mark_field_as_initialized(shape, index)?;
777
778                debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
779
780                return Ok(self);
781            }
782
783            return Err(ReflectError::WrongShape {
784                expected: frame.shape,
785                actual: T::SHAPE,
786            });
787        }
788
789        // de-initialize partially initialized fields
790        if frame.istate.variant.is_some() || frame.istate.fields.is_any_set() {
791            debug!(
792                "De-initializing partially initialized fields for {}",
793                frame.shape
794            );
795
796            match frame.shape.def {
797                Def::Struct(sd) => {
798                    for (i, field) in sd.fields.iter().enumerate() {
799                        if frame.istate.fields.has(i) {
800                            if let Some(drop_fn) = field.shape().vtable.drop_in_place {
801                                unsafe {
802                                    let field_ptr = frame.data.as_mut_byte_ptr().add(field.offset);
803                                    drop_fn(PtrMut::new(field_ptr));
804                                }
805                            }
806                        }
807                    }
808                }
809                Def::Enum(_) => {
810                    if let Some(variant) = &frame.istate.variant {
811                        for (i, field) in variant.data.fields.iter().enumerate() {
812                            if frame.istate.fields.has(i) {
813                                if let Some(drop_fn) = field.shape().vtable.drop_in_place {
814                                    unsafe {
815                                        let field_ptr =
816                                            frame.data.as_mut_byte_ptr().add(field.offset);
817                                        drop_fn(PtrMut::new(field_ptr));
818                                    }
819                                }
820                            }
821                        }
822                    }
823                }
824                _ => {
825                    // For scalar types, nothing to do if not fully initialized
826                }
827            }
828
829            // Reset initialization state
830            frame.istate.variant = None;
831            ISet::clear(&mut frame.istate.fields);
832        }
833
834        unsafe {
835            frame.data.put(t);
836            frame.mark_fully_initialized();
837        }
838
839        let shape = frame.shape;
840        let index = frame.field_index_in_parent;
841
842        // mark the field as initialized
843        self.mark_field_as_initialized(shape, index)?;
844
845        debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
846
847        Ok(self)
848    }
849
850    /// Tries to parse the current frame's value from a string
851    pub fn parse(mut self, s: &str) -> Result<Self, ReflectError> {
852        let Some(frame) = self.frames.last_mut() else {
853            return Err(ReflectError::OperationFailed {
854                shape: <()>::SHAPE,
855                operation: "tried to parse value but there was no frame",
856            });
857        };
858
859        let shape = frame.shape;
860        let index = frame.field_index_in_parent;
861
862        let Some(parse_fn) = frame.shape.vtable.parse else {
863            return Err(ReflectError::OperationFailed {
864                shape: frame.shape,
865                operation: "type does not implement Parse",
866            });
867        };
868        match unsafe { (parse_fn)(s, frame.data) } {
869            Ok(_res) => {
870                unsafe {
871                    frame.mark_fully_initialized();
872                }
873
874                // mark the field as initialized
875                self.mark_field_as_initialized(shape, index)?;
876
877                Ok(self)
878            }
879            Err(_) => Err(ReflectError::OperationFailed {
880                shape,
881                operation: "parsing",
882            }),
883        }
884    }
885
886    /// Puts the default value in the current frame.
887    pub fn put_default(mut self) -> Result<Self, ReflectError> {
888        let Some(frame) = self.frames.last_mut() else {
889            return Err(ReflectError::OperationFailed {
890                shape: <()>::SHAPE,
891                operation: "tried to put default value but there was no frame",
892            });
893        };
894
895        let vtable = frame.shape.vtable;
896
897        let Some(default_in_place) = vtable.default_in_place else {
898            return Err(ReflectError::OperationFailed {
899                shape: frame.shape,
900                operation: "type does not implement Default",
901            });
902        };
903        unsafe {
904            default_in_place(frame.data);
905            frame.mark_fully_initialized();
906        }
907
908        let shape = frame.shape;
909        let index = frame.field_index_in_parent;
910
911        // mark the field as initialized
912        self.mark_field_as_initialized(shape, index)?;
913
914        Ok(self)
915    }
916
917    /// Marks a field as initialized in the parent frame.
918    fn mark_field_as_initialized(
919        &mut self,
920        shape: &'static Shape,
921        index: Option<usize>,
922    ) -> Result<(), ReflectError> {
923        if let Some(index) = index {
924            let parent_index = self.frames.len().saturating_sub(2);
925            #[cfg(feature = "log")]
926            let num_frames = self.frames.len();
927            let Some(parent) = self.frames.get_mut(parent_index) else {
928                return Err(ReflectError::OperationFailed {
929                    shape,
930                    operation: "was supposed to mark a field as initialized, but there was no parent frame",
931                });
932            };
933            #[cfg(feature = "log")]
934            let parent_shape = parent.shape;
935            trace!(
936                "[{}] {}.{} initialized with {}",
937                num_frames,
938                parent_shape.blue(),
939                index.yellow(),
940                shape.green()
941            );
942
943            if matches!(parent.shape.def, Def::Enum(_)) && parent.istate.variant.is_none() {
944                return Err(ReflectError::OperationFailed {
945                    shape,
946                    operation: "was supposed to mark a field as initialized, but the parent frame was an enum and didn't have a variant chosen",
947                });
948            }
949
950            if parent.istate.fields.has(index) {
951                return Err(ReflectError::OperationFailed {
952                    shape,
953                    operation: "was supposed to mark a field as initialized, but the parent frame already had it marked as initialized",
954                });
955            }
956
957            parent.istate.fields.set(index);
958        }
959        Ok(())
960    }
961
962    /// Returns the shape of the element type for a list/array
963    pub fn element_shape(&self) -> Result<&'static Shape, ReflectError> {
964        let frame = self.frames.last().unwrap();
965        let shape = frame.shape;
966
967        match shape.def {
968            Def::List(list_def) => Ok(list_def.t()),
969            _ => Err(ReflectError::WasNotA {
970                expected: "list or array",
971                actual: shape,
972            }),
973        }
974    }
975
976    /// Returns the shape of the key type for a map
977    pub fn key_shape(&self) -> Result<&'static Shape, ReflectError> {
978        let frame = self.frames.last().unwrap();
979        let shape = frame.shape;
980
981        match shape.def {
982            Def::Map(map_def) => Ok(map_def.k),
983            _ => Err(ReflectError::WasNotA {
984                expected: "map",
985                actual: shape,
986            }),
987        }
988    }
989
990    /// Creates an empty list without pushing any elements
991    pub fn put_empty_list(mut self) -> Result<Self, ReflectError> {
992        let Some(frame) = self.frames.last_mut() else {
993            return Err(ReflectError::OperationFailed {
994                shape: <()>::SHAPE,
995                operation: "tried to create empty list but there was no frame",
996            });
997        };
998
999        if !matches!(frame.shape.def, Def::List(_)) {
1000            return Err(ReflectError::WasNotA {
1001                expected: "list or array",
1002                actual: frame.shape,
1003            });
1004        }
1005
1006        let vtable = frame.shape.vtable;
1007
1008        // Initialize an empty list
1009        let Some(default_in_place) = vtable.default_in_place else {
1010            return Err(ReflectError::OperationFailed {
1011                shape: frame.shape,
1012                operation: "list type does not implement Default",
1013            });
1014        };
1015
1016        unsafe {
1017            default_in_place(frame.data);
1018            frame.mark_fully_initialized();
1019        }
1020
1021        let shape = frame.shape;
1022        let index = frame.field_index_in_parent;
1023
1024        // Mark the field as initialized
1025        self.mark_field_as_initialized(shape, index)?;
1026
1027        Ok(self)
1028    }
1029
1030    /// Creates an empty map without pushing any entries
1031    pub fn put_empty_map(mut self) -> Result<Self, ReflectError> {
1032        let Some(frame) = self.frames.last_mut() else {
1033            return Err(ReflectError::OperationFailed {
1034                shape: <()>::SHAPE,
1035                operation: "tried to create empty map but there was no frame",
1036            });
1037        };
1038
1039        if !matches!(frame.shape.def, Def::Map(_)) {
1040            return Err(ReflectError::WasNotA {
1041                expected: "map or hash map",
1042                actual: frame.shape,
1043            });
1044        }
1045
1046        let vtable = frame.shape.vtable;
1047
1048        // Initialize an empty map
1049        let Some(default_in_place) = vtable.default_in_place else {
1050            return Err(ReflectError::OperationFailed {
1051                shape: frame.shape,
1052                operation: "map type does not implement Default",
1053            });
1054        };
1055
1056        unsafe {
1057            default_in_place(frame.data);
1058            frame.mark_fully_initialized();
1059        }
1060
1061        let shape = frame.shape;
1062        let index = frame.field_index_in_parent;
1063
1064        // Mark the field as initialized
1065        self.mark_field_as_initialized(shape, index)?;
1066
1067        Ok(self)
1068    }
1069
1070    /// Begins pushback mode for a list/array, allowing elements to be added one by one
1071    pub fn begin_pushback(mut self) -> Result<Self, ReflectError> {
1072        let Some(frame) = self.frames.last_mut() else {
1073            return Err(ReflectError::OperationFailed {
1074                shape: <()>::SHAPE,
1075                operation: "tried to begin pushback but there was no frame",
1076            });
1077        };
1078
1079        if !matches!(frame.shape.def, Def::List(_)) {
1080            return Err(ReflectError::WasNotA {
1081                expected: "list or array",
1082                actual: frame.shape,
1083            });
1084        }
1085
1086        let vtable = frame.shape.vtable;
1087
1088        // Initialize an empty list if it's not already initialized
1089        if !frame.istate.fields.has(0) {
1090            let Some(default_in_place) = vtable.default_in_place else {
1091                return Err(ReflectError::OperationFailed {
1092                    shape: frame.shape,
1093                    operation: "list type does not implement Default",
1094                });
1095            };
1096
1097            unsafe {
1098                default_in_place(frame.data);
1099                frame.istate.fields.set(0);
1100            }
1101        }
1102
1103        Ok(self)
1104    }
1105
1106    /// Begins insertion mode for a map, allowing key-value pairs to be added one by one
1107    pub fn begin_map_insert(mut self) -> Result<Self, ReflectError> {
1108        let Some(frame) = self.frames.last_mut() else {
1109            return Err(ReflectError::OperationFailed {
1110                shape: <()>::SHAPE,
1111                operation: "tried to begin map insertion but there was no frame",
1112            });
1113        };
1114
1115        if !matches!(frame.shape.def, Def::Map(_)) {
1116            return Err(ReflectError::WasNotA {
1117                expected: "map or hash map",
1118                actual: frame.shape,
1119            });
1120        }
1121
1122        let vtable = frame.shape.vtable;
1123
1124        // Initialize an empty map if it's not already initialized
1125        if !frame.istate.fields.has(0) {
1126            let Some(default_in_place) = vtable.default_in_place else {
1127                return Err(ReflectError::OperationFailed {
1128                    shape: frame.shape,
1129                    operation: "map type does not implement Default",
1130                });
1131            };
1132
1133            unsafe {
1134                default_in_place(frame.data);
1135                frame.istate.fields.set(0);
1136            }
1137        }
1138
1139        Ok(self)
1140    }
1141
1142    /// Pushes a new element onto the list/array
1143    ///
1144    /// This creates a new frame for the element. When this frame is popped,
1145    /// the element will be added to the list.
1146    pub fn push(mut self) -> Result<Self, ReflectError> {
1147        // Make sure we're initializing a list
1148        let frame = self.frames.last().unwrap();
1149        let list_shape = frame.shape;
1150
1151        if !matches!(list_shape.def, Def::List(_)) {
1152            return Err(ReflectError::WasNotA {
1153                expected: "list or array",
1154                actual: list_shape,
1155            });
1156        }
1157
1158        // If the list isn't initialized yet, initialize it
1159        if !frame.istate.fields.has(0) {
1160            self = self.begin_pushback()?;
1161        }
1162
1163        // Get the element type
1164        let element_shape = self.element_shape()?;
1165
1166        // Allocate memory for the element
1167        let element_data = element_shape.allocate();
1168
1169        // Create a new frame for the element
1170        let element_frame = Frame {
1171            data: element_data,
1172            shape: element_shape,
1173            field_index_in_parent: None, // No need for an index since we're using mode
1174            istate: IState::new(
1175                self.frames.len(),
1176                FrameMode::ListElement,
1177                FrameFlags::ALLOCATED,
1178            ),
1179        };
1180
1181        trace!(
1182            "[{}] Pushing element of type {} to list {}",
1183            self.frames.len(),
1184            element_shape.green(),
1185            list_shape.blue(),
1186        );
1187
1188        self.frames.push(element_frame);
1189        Ok(self)
1190    }
1191
1192    /// Prepare to push the `Some(T)` variant of an `Option<T>`.
1193    pub fn push_some(mut self) -> Result<Self, ReflectError> {
1194        // Make sure we're initializing an option
1195        let frame = self.frames.last().unwrap();
1196        let option_shape = frame.shape;
1197
1198        // Get the option definition
1199        let Def::Option(option_def) = option_shape.def else {
1200            return Err(ReflectError::WasNotA {
1201                expected: "option",
1202                actual: option_shape,
1203            });
1204        };
1205
1206        // Get the inner type of the option
1207        let inner_shape = option_def.t();
1208
1209        // Allocate memory for the inner value
1210        let inner_data = inner_shape.allocate();
1211
1212        // Create a new frame for the inner value
1213        let inner_frame = Frame {
1214            data: inner_data,
1215            shape: inner_shape,
1216            // this is only set when we pop
1217            field_index_in_parent: None,
1218            istate: IState::new(
1219                self.frames.len(),
1220                FrameMode::OptionSome,
1221                // TODO: we could lazy-allocate it when something like `field` is called, tbh
1222                FrameFlags::ALLOCATED,
1223            ),
1224        };
1225
1226        trace!(
1227            "[{}] Pushing option frame for {}",
1228            self.frames.len(),
1229            option_shape.blue(),
1230        );
1231
1232        self.frames.push(inner_frame);
1233        Ok(self)
1234    }
1235
1236    /// Pops a not-yet-initialized option frame, setting it to None in the parent
1237    ///
1238    /// This is used to set an option to None instead of Some.
1239    /// Steps:
1240    ///  1. Asserts the option frame is NOT initialized
1241    ///  2. Frees the memory for the pushed value
1242    ///  3. Pops the frame
1243    ///  4. Sets the parent option to its default value (i.e., None)
1244    ///  5. Pops the parent option (which is the actual `Option<T>`, but no longer in option mode)
1245    pub fn pop_some_push_none(mut self) -> Result<Self, ReflectError> {
1246        // 1. Option frame must exist
1247        let Some(frame) = self.frames.last_mut() else {
1248            return Err(ReflectError::OperationFailed {
1249                shape: <()>::SHAPE,
1250                operation: "tried to pop_some_push_none but there was no frame",
1251            });
1252        };
1253
1254        // 1. Make sure the current frame is an option inner frame in "Option" mode
1255        if frame.istate.mode != FrameMode::OptionSome {
1256            return Err(ReflectError::OperationFailed {
1257                shape: frame.shape,
1258                operation: "pop_some_push_none called, but frame was not in Option mode",
1259            });
1260        }
1261
1262        // 1. Check not initialized
1263        if frame.is_fully_initialized() {
1264            return Err(ReflectError::OperationFailed {
1265                shape: frame.shape,
1266                operation: "option frame already initialized, cannot pop_some_push_none",
1267            });
1268        }
1269
1270        frame.dealloc_if_needed();
1271
1272        // 3. Pop the frame (this discards, doesn't propagate up)
1273        let _frame = self.frames.pop().expect("frame already checked");
1274
1275        // 4. Set parent option (which we just popped into) to default (None)
1276        let parent_frame = self
1277            .frames
1278            .last_mut()
1279            .ok_or(ReflectError::OperationFailed {
1280                shape: <()>::SHAPE,
1281                operation: "tried to pop_some_push_none but there was no parent frame",
1282            })?;
1283
1284        // Safety: option frames are correctly sized, and data is valid
1285        unsafe {
1286            if let Some(default_fn) = parent_frame.shape.vtable.default_in_place {
1287                default_fn(parent_frame.data);
1288            } else {
1289                return Err(ReflectError::OperationFailed {
1290                    shape: parent_frame.shape,
1291                    operation: "option type does not implement Default",
1292                });
1293            }
1294            parent_frame.mark_fully_initialized();
1295        }
1296
1297        let Def::Option(od) = parent_frame.shape.def else {
1298            return Err(ReflectError::OperationFailed {
1299                shape: parent_frame.shape,
1300                operation: "pop_some_push_none and the parent isn't of type Option???",
1301            });
1302        };
1303
1304        // Now push a `None` frame
1305        let data = parent_frame.data;
1306
1307        let mut frame = Frame {
1308            data,
1309            shape: od.t(),
1310            field_index_in_parent: Some(0),
1311            istate: IState::new(self.frames.len(), FrameMode::OptionNone, FrameFlags::EMPTY),
1312        };
1313        unsafe {
1314            frame.mark_fully_initialized();
1315        }
1316
1317        self.frames.push(frame);
1318
1319        Ok(self)
1320    }
1321
1322    /// Pushes a new key frame for a map entry
1323    ///
1324    /// This creates a new frame for the key. After setting the key value,
1325    /// call `push_map_value` to create a frame for the corresponding value.
1326    pub fn push_map_key(mut self) -> Result<Self, ReflectError> {
1327        // Make sure we're initializing a map
1328        let frame = self.frames.last().unwrap();
1329        let map_shape = frame.shape;
1330
1331        if !matches!(map_shape.def, Def::Map(_)) {
1332            return Err(ReflectError::WasNotA {
1333                expected: "map or hash map",
1334                actual: map_shape,
1335            });
1336        }
1337
1338        // If the map isn't initialized yet, initialize it
1339        if !frame.istate.fields.has(0) {
1340            self = self.begin_map_insert()?;
1341        }
1342
1343        // Get the key type
1344        let key_shape = self.key_shape()?;
1345
1346        // Allocate memory for the key
1347        let key_data = key_shape.allocate();
1348
1349        // Create a new frame for the key
1350        let key_frame = Frame {
1351            data: key_data,
1352            shape: key_shape,
1353            field_index_in_parent: None,
1354            istate: IState::new(self.frames.len(), FrameMode::MapKey, FrameFlags::ALLOCATED),
1355        };
1356
1357        trace!(
1358            "[{}] Pushing key of type {} for map {}",
1359            self.frames.len(),
1360            key_shape.green(),
1361            map_shape.blue(),
1362        );
1363
1364        self.frames.push(key_frame);
1365        Ok(self)
1366    }
1367
1368    /// Pushes a new value frame for a map entry
1369    ///
1370    /// This should be called after pushing and initializing a key frame.
1371    /// When the value frame is popped, the key-value pair will be added to the map.
1372    pub fn push_map_value(mut self) -> Result<Self, ReflectError> {
1373        trace!("Wants to push map value. Frames = ");
1374        #[cfg(feature = "log")]
1375        for (i, f) in self.frames.iter().enumerate() {
1376            trace!("Frame {}: {:?}", i, f);
1377        }
1378
1379        // First, ensure we have a valid key frame
1380        if self.frames.len() < 2 {
1381            return Err(ReflectError::OperationFailed {
1382                shape: <()>::SHAPE,
1383                operation: "tried to push map value but there was no key frame",
1384            });
1385        }
1386
1387        // Check the frame before the last to ensure it's a map key
1388        let key_frame_index = self.frames.len() - 1;
1389        let key_frame = &self.frames[key_frame_index];
1390
1391        // Verify the current frame is a key frame
1392        match key_frame.istate.mode {
1393            FrameMode::MapKey => {} // Valid - continue
1394            _ => {
1395                return Err(ReflectError::OperationFailed {
1396                    shape: key_frame.shape,
1397                    operation: "current frame is not a map key",
1398                });
1399            }
1400        }
1401
1402        // Check that the key is fully initialized
1403        if !key_frame.is_fully_initialized() {
1404            return Err(ReflectError::OperationFailed {
1405                shape: key_frame.shape,
1406                operation: "map key is not fully initialized",
1407            });
1408        }
1409
1410        // Get the parent map frame to verify we're working with a map
1411        let map_frame_index = self.frames.len() - 2;
1412        let map_frame = &self.frames[map_frame_index];
1413        let map_shape = map_frame.shape;
1414
1415        let Def::Map(map_def) = map_shape.def else {
1416            return Err(ReflectError::WasNotA {
1417                expected: "map",
1418                actual: map_frame.shape,
1419            });
1420        };
1421
1422        let value_shape = map_def.v;
1423
1424        // Allocate memory for the value
1425        let value_data = value_shape.allocate();
1426
1427        // Create a new frame for the value
1428        let value_frame = Frame {
1429            data: value_data,
1430            shape: value_shape,
1431            field_index_in_parent: None,
1432            istate: IState::new(
1433                self.frames.len(),
1434                FrameMode::MapValue {
1435                    index: key_frame_index,
1436                },
1437                FrameFlags::ALLOCATED,
1438            ),
1439        };
1440
1441        trace!(
1442            "[{}] Pushing value of type {} for map {} with key type {}",
1443            self.frames.len(),
1444            value_shape.green(),
1445            map_shape.blue(),
1446            key_frame.shape.yellow(),
1447        );
1448
1449        self.frames.push(value_frame);
1450        Ok(self)
1451    }
1452
1453    /// Pops the current frame — goes back up one level
1454    pub fn pop(mut self) -> Result<Self, ReflectError> {
1455        let Some(frame) = self.pop_inner() else {
1456            return Err(ReflectError::InvariantViolation {
1457                invariant: "No frame to pop",
1458            });
1459        };
1460        self.track(frame);
1461        Ok(self)
1462    }
1463
1464    fn pop_inner(&mut self) -> Option<Frame> {
1465        let mut frame = self.frames.pop()?;
1466        #[cfg(feature = "log")]
1467        let frame_shape = frame.shape;
1468
1469        let init = frame.is_fully_initialized();
1470        trace!(
1471            "[{}] {} popped, {} initialized",
1472            self.frames.len(),
1473            frame_shape.blue(),
1474            if init {
1475                "✅ fully".style(owo_colors::Style::new().green())
1476            } else {
1477                "🚧 partially".style(owo_colors::Style::new().red())
1478            }
1479        );
1480        if init {
1481            if let Some(parent) = self.frames.last_mut() {
1482                if let Some(index) = frame.field_index_in_parent {
1483                    parent.istate.fields.set(index);
1484                }
1485            }
1486        }
1487
1488        // Handle special frame modes
1489        match frame.istate.mode {
1490            // Handle list element frames
1491            FrameMode::ListElement => {
1492                if frame.is_fully_initialized() {
1493                    // This was a list element, so we need to push it to the parent list
1494                    // Capture frame length and parent shape before mutable borrow
1495                    #[cfg(feature = "log")]
1496                    let frame_len = self.frames.len();
1497
1498                    // Get parent frame
1499                    let parent_frame = self.frames.last_mut().unwrap();
1500                    let parent_shape = parent_frame.shape;
1501
1502                    // Make sure the parent is a list
1503                    match parent_shape.def {
1504                        Def::List(_) => {
1505                            // Get the list vtable from the ListDef
1506                            if let Def::List(list_def) = parent_shape.def {
1507                                let list_vtable = list_def.vtable;
1508                                trace!(
1509                                    "[{}] Pushing element to list {}",
1510                                    frame_len,
1511                                    parent_shape.blue()
1512                                );
1513                                unsafe {
1514                                    // Convert the frame data pointer to Opaque and call push function from vtable
1515                                    (list_vtable.push)(
1516                                        PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1517                                        PtrMut::new(frame.data.as_mut_byte_ptr()),
1518                                    );
1519                                    self.mark_moved_out_of(&mut frame);
1520                                }
1521                            } else {
1522                                panic!("parent frame is not a list type");
1523                            }
1524                        }
1525                        _ => {
1526                            panic!("Expected list or array, got {}", frame.shape);
1527                        }
1528                    }
1529                }
1530            }
1531
1532            // Handle map value frames
1533            FrameMode::MapValue {
1534                index: key_frame_index,
1535            } if frame.is_fully_initialized() => {
1536                // This was a map value, so we need to insert the key-value pair into the map
1537
1538                // Now let's remove the key frame from the frames array
1539                let mut key_frame = self.frames.remove(key_frame_index);
1540
1541                // Make sure the key is fully initialized
1542                if !key_frame.istate.fields.is_any_set() {
1543                    panic!("key is not initialized when popping value frame");
1544                }
1545
1546                // Get parent map frame
1547                #[cfg(feature = "log")]
1548                let frame_len = self.frames.len();
1549                let parent_frame = self.frames.last_mut().unwrap();
1550                let parent_shape = parent_frame.shape;
1551
1552                // Make sure the parent is a map
1553                match parent_shape.def {
1554                    Def::Map(_) => {
1555                        // Get the map vtable from the MapDef
1556                        if let Def::Map(map_def) = parent_shape.def {
1557                            trace!(
1558                                "[{}] Inserting key-value pair into map {}",
1559                                frame_len,
1560                                parent_shape.blue()
1561                            );
1562                            unsafe {
1563                                // Call the map's insert function with the key and value
1564                                (map_def.vtable.insert_fn)(
1565                                    parent_frame.data.assume_init(),
1566                                    key_frame.data.assume_init(),
1567                                    PtrMut::new(frame.data.as_mut_byte_ptr()),
1568                                );
1569                                self.mark_moved_out_of(&mut key_frame);
1570                                self.mark_moved_out_of(&mut frame);
1571                            }
1572                        } else {
1573                            panic!("parent frame is not a map type");
1574                        }
1575                    }
1576                    _ => {
1577                        panic!("Expected map or hash map, got {}", frame.shape);
1578                    }
1579                }
1580            }
1581
1582            // Handle option frames
1583            FrameMode::OptionSome => {
1584                if frame.is_fully_initialized() {
1585                    trace!("Popping OptionSome (fully init'd)");
1586
1587                    // Get parent frame
1588                    #[cfg(feature = "log")]
1589                    let frames_len = self.frames.len();
1590                    let parent_frame = self.frames.last_mut().unwrap();
1591                    let parent_shape = parent_frame.shape;
1592
1593                    // Make sure the parent is an option
1594                    match parent_shape.def {
1595                        Def::Option(option_def) => {
1596                            trace!(
1597                                "[{}] Setting Some value in option {}",
1598                                frames_len,
1599                                parent_shape.blue()
1600                            );
1601                            unsafe {
1602                                // Call the option's init_some function
1603                                (option_def.vtable.init_some_fn)(
1604                                    parent_frame.data,
1605                                    PtrConst::new(frame.data.as_byte_ptr()),
1606                                );
1607                                trace!("Marking parent frame as fully initialized");
1608                                parent_frame.mark_fully_initialized();
1609
1610                                self.mark_moved_out_of(&mut frame);
1611                            }
1612                        }
1613                        _ => {
1614                            panic!(
1615                                "Expected parent frame to be an option type, got {}",
1616                                frame.shape
1617                            );
1618                        }
1619                    }
1620                } else {
1621                    trace!("Popping OptionSome (not fully init'd)");
1622                }
1623            }
1624
1625            // Map keys are just tracked, they don't need special handling when popped
1626            // FIXME: that's not true, we need to deallocate them at least??
1627            FrameMode::MapKey => {}
1628
1629            // Field frame
1630            FrameMode::Field => {}
1631
1632            // Uninitialized special frames
1633            _ => {}
1634        }
1635
1636        Some(frame)
1637    }
1638
1639    /// Evict a frame from istates, along with all its children
1640    /// (because we're about to use `drop_in_place` on it — not
1641    /// yet though, we need to know the variant for enums, etc.)
1642    pub fn evict_tree(&mut self, frame: Frame) -> Frame {
1643        match frame.shape.def {
1644            Def::Struct(sd) => {
1645                for f in sd.fields {
1646                    let id = ValueId {
1647                        shape: f.shape(),
1648                        ptr: unsafe { frame.data.field_uninit_at(f.offset) }.as_byte_ptr(),
1649                    };
1650                    if let Some(istate) = self.istates.remove(&id) {
1651                        let frame = Frame::recompose(id, istate);
1652                        self.evict_tree(frame);
1653                    } else {
1654                        trace!("No istate found for field {}", f.name);
1655                    }
1656                }
1657            }
1658            Def::Enum(_ed) => {
1659                // Check if a variant is selected in the istate
1660                if let Some(variant) = &frame.istate.variant {
1661                    trace!(
1662                        "Evicting enum {} variant '{}' fields",
1663                        frame.shape.blue(),
1664                        variant.name.yellow()
1665                    );
1666                    // Iterate over the fields of the selected variant
1667                    for field in variant.data.fields {
1668                        // Calculate the pointer to the field within the enum's data payload
1669                        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
1670                        let field_shape = field.shape();
1671                        let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
1672
1673                        // Try to remove the field's state from istates
1674                        if let Some(field_istate) = self.istates.remove(&field_id) {
1675                            trace!(
1676                                "Evicting field '{}' (shape {}) of enum variant '{}'",
1677                                field.name.bright_blue(),
1678                                field_shape.green(),
1679                                variant.name.yellow()
1680                            );
1681                            // Recompose the frame for the field
1682                            let field_frame = Frame::recompose(field_id, field_istate);
1683                            // Recursively evict the field's subtree
1684                            self.evict_tree(field_frame);
1685                        } else {
1686                            trace!(
1687                                "Field '{}' (shape {}) of enum variant '{}' not found in istates, skipping eviction",
1688                                field.name.red(),
1689                                field_shape.red(),
1690                                variant.name.yellow()
1691                            );
1692                        }
1693                    }
1694                } else {
1695                    // No variant selected, nothing to evict within the enum
1696                    trace!(
1697                        "Enum {} has no variant selected, no fields to evict.",
1698                        frame.shape.blue()
1699                    );
1700                }
1701            }
1702            _ => {}
1703        }
1704        frame
1705    }
1706
1707    #[allow(rustdoc::broken_intra_doc_links)]
1708    /// Returns the current path in the JSON document as a string.
1709    /// For example: "$.users[0].name"
1710    pub fn path(&self) -> String {
1711        let mut path = String::from("$");
1712
1713        for (i, frame) in self.frames.iter().enumerate() {
1714            // Skip the root frame
1715            if i == 0 {
1716                continue;
1717            }
1718
1719            match frame.istate.mode {
1720                FrameMode::ListElement => {
1721                    // For arrays, we use bracket notation with index
1722                    if let Some(index) = frame.istate.list_index {
1723                        path.push_str(&format!("[{}]", index));
1724                    } else {
1725                        path.push_str("[?]");
1726                    }
1727                }
1728                FrameMode::MapKey => {
1729                    path.push_str(".key");
1730                }
1731                FrameMode::MapValue { index: _ } => {
1732                    path.push_str(".value");
1733                }
1734                FrameMode::OptionSome => {
1735                    path.push_str(".some");
1736                }
1737                FrameMode::OptionNone => {
1738                    path.push_str(".none");
1739                }
1740                FrameMode::Root => {
1741                    // Root doesn't add to the path
1742                }
1743                FrameMode::Field => {
1744                    // For struct fields, we use dot notation with field name
1745                    if let Some(index) = frame.field_index_in_parent {
1746                        // Find the parent frame to get the field name
1747                        if let Some(parent) = self.frames.get(i - 1) {
1748                            if let Def::Struct(sd) = parent.shape.def {
1749                                if index < sd.fields.len() {
1750                                    let field_name = sd.fields[index].name;
1751                                    path.push('.');
1752                                    path.push_str(field_name);
1753                                }
1754                            } else if let Def::Enum(_) = parent.shape.def {
1755                                if let Some(variant) = &parent.istate.variant {
1756                                    if index < variant.data.fields.len() {
1757                                        let field_name = variant.data.fields[index].name;
1758                                        path.push('.');
1759                                        path.push_str(field_name);
1760                                    }
1761                                }
1762                            }
1763                        }
1764                    }
1765                }
1766            }
1767        }
1768
1769        path
1770    }
1771}
1772
1773impl Drop for Wip<'_> {
1774    fn drop(&mut self) {
1775        trace!("🧹🧹🧹 WIP is dropping");
1776
1777        while let Some(frame) = self.frames.pop() {
1778            self.track(frame);
1779        }
1780
1781        let Some((root_id, _)) = self.istates.iter().find(|(_k, istate)| istate.depth == 0) else {
1782            trace!("No root found, we probably built already");
1783            return;
1784        };
1785
1786        let root_id = *root_id;
1787        let root_istate = self.istates.remove(&root_id).unwrap();
1788        let root = Frame::recompose(root_id, root_istate);
1789        let mut to_clean = vec![root];
1790
1791        let mut _root_guard: Option<Guard> = None;
1792
1793        while let Some(mut frame) = to_clean.pop() {
1794            trace!(
1795                "Cleaning frame: shape={} at {:p}, flags={:?}, mode={:?}, fully_initialized={}",
1796                frame.shape.blue(),
1797                frame.data.as_byte_ptr(),
1798                frame.istate.flags.bright_magenta(),
1799                frame.istate.mode.yellow(),
1800                if frame.is_fully_initialized() {
1801                    "✅"
1802                } else {
1803                    "❌"
1804                }
1805            );
1806
1807            if frame.istate.flags.contains(FrameFlags::MOVED) {
1808                trace!(
1809                    "{}",
1810                    "Frame was moved out of, nothing to dealloc/drop_in_place".yellow()
1811                );
1812                continue;
1813            }
1814
1815            match frame.shape.def {
1816                Def::Struct(sd) => {
1817                    if frame.is_fully_initialized() {
1818                        trace!(
1819                            "Dropping fully initialized struct: {} at {:p}",
1820                            frame.shape.green(),
1821                            frame.data.as_byte_ptr()
1822                        );
1823                        let frame = self.evict_tree(frame);
1824                        unsafe { frame.drop_and_dealloc_if_needed() };
1825                    } else {
1826                        let num_fields = sd.fields.len();
1827                        trace!(
1828                            "De-initializing struct {} at {:p} field-by-field ({} fields)",
1829                            frame.shape.yellow(),
1830                            frame.data.as_byte_ptr(),
1831                            num_fields.to_string().bright_cyan()
1832                        );
1833                        for i in 0..num_fields {
1834                            if frame.istate.fields.has(i) {
1835                                let field = sd.fields[i];
1836                                let field_shape = field.shape();
1837                                let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
1838                                let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
1839                                trace!(
1840                                    "Recursively cleaning field #{} '{}' of {}: field_shape={}, field_ptr={:p}",
1841                                    i.to_string().bright_cyan(),
1842                                    field.name.bright_blue(),
1843                                    frame.shape.blue(),
1844                                    field_shape.green(),
1845                                    field_ptr.as_byte_ptr()
1846                                );
1847                                let istate = self.istates.remove(&field_id).unwrap();
1848                                let field_frame = Frame::recompose(field_id, istate);
1849                                to_clean.push(field_frame);
1850                            } else {
1851                                trace!(
1852                                    "Field #{} '{}' of {} was NOT initialized, skipping",
1853                                    i.to_string().bright_cyan(),
1854                                    sd.fields[i].name.bright_red(),
1855                                    frame.shape.red()
1856                                );
1857                            }
1858                        }
1859
1860                        // we'll also need to clean up if we're root
1861                        if frame.istate.mode == FrameMode::Root {
1862                            _root_guard = Some(Guard {
1863                                ptr: frame.data.as_mut_byte_ptr(),
1864                                layout: frame.shape.layout,
1865                            });
1866                        }
1867                    }
1868                }
1869                Def::Enum(_ed) => {
1870                    trace!(
1871                        "{}",
1872                        format!(
1873                            "TODO: handle enum deallocation for {} at {:p}",
1874                            frame.shape.yellow(),
1875                            frame.data.as_byte_ptr()
1876                        )
1877                        .magenta()
1878                    );
1879
1880                    // we'll also need to clean up if we're root
1881                    if frame.istate.mode == FrameMode::Root {
1882                        _root_guard = Some(Guard {
1883                            ptr: frame.data.as_mut_byte_ptr(),
1884                            layout: frame.shape.layout,
1885                        });
1886                    }
1887                }
1888                Def::Array(_)
1889                | Def::Slice(_)
1890                | Def::List(_)
1891                | Def::Map(_)
1892                | Def::SmartPointer(_)
1893                | Def::Scalar(_)
1894                | Def::Option(_) => {
1895                    trace!(
1896                        "Can drop all at once for shape {} (def variant: {:?}, frame mode {:?}) at {:p}",
1897                        frame.shape.cyan(),
1898                        frame.shape.def,
1899                        frame.istate.mode.yellow(),
1900                        frame.data.as_byte_ptr(),
1901                    );
1902
1903                    if frame.is_fully_initialized() {
1904                        unsafe { frame.drop_and_dealloc_if_needed() }
1905                    } else {
1906                        frame.dealloc_if_needed();
1907                    }
1908                }
1909                _ => {}
1910            }
1911        }
1912
1913        // We might have some frames left over to deallocate for temporary allocations for keymap insertion etc.
1914        let mut all_ids = self.istates.keys().copied().collect::<Vec<_>>();
1915        for frame_id in all_ids.drain(..) {
1916            let frame_istate = self.istates.remove(&frame_id).unwrap();
1917
1918            trace!(
1919                "Checking leftover istate: id.shape={} id.ptr={:p} mode={:?}",
1920                frame_id.shape.cyan(),
1921                frame_id.ptr,
1922                frame_istate.mode.yellow()
1923            );
1924            let mut frame = Frame::recompose(frame_id, frame_istate);
1925
1926            if frame.is_fully_initialized() {
1927                trace!("It's fully initialized, we can drop it");
1928                unsafe { frame.drop_and_dealloc_if_needed() };
1929            } else if frame.istate.flags.contains(FrameFlags::ALLOCATED) {
1930                trace!("Not initialized but allocated, let's free it");
1931                frame.dealloc_if_needed();
1932            }
1933        }
1934    }
1935}