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