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