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