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