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