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