facet_reflect/wip/
mod.rs

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