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