facet_reflect/wip/
mod.rs

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