Skip to main content

facet_reflect/partial/
mod.rs

1//! Partial value construction for dynamic reflection
2//!
3//! This module provides APIs for incrementally building values through reflection,
4//! particularly useful when deserializing data from external formats like JSON or YAML.
5//!
6//! # Overview
7//!
8//! The `Partial` type (formerly known as `Wip` - Work In Progress) allows you to:
9//! - Allocate memory for a value based on its `Shape`
10//! - Initialize fields incrementally in a type-safe manner
11//! - Handle complex nested structures including structs, enums, collections, and smart pointers
12//! - Build the final value once all required fields are initialized
13//!
14//! **Note**: This is the only API for partial value construction. The previous `TypedPartial`
15//! wrapper has been removed in favor of using `Partial` directly.
16//!
17//! # Basic Usage
18//!
19//! ```no_run
20//! # use facet_reflect::Partial;
21//! # use facet_core::{Shape, Facet};
22//! # fn example<T: Facet<'static>>() -> Result<(), Box<dyn std::error::Error>> {
23//! // Allocate memory for a struct
24//! let mut partial = Partial::alloc::<T>()?;
25//!
26//! // Set simple fields
27//! partial = partial.set_field("name", "Alice")?;
28//! partial = partial.set_field("age", 30u32)?;
29//!
30//! // Work with nested structures
31//! partial = partial.begin_field("address")?;
32//! partial = partial.set_field("street", "123 Main St")?;
33//! partial = partial.set_field("city", "Springfield")?;
34//! partial = partial.end()?;
35//!
36//! // Build the final value
37//! let value = partial.build()?;
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! # Chaining Style
43//!
44//! The API supports method chaining for cleaner code:
45//!
46//! ```no_run
47//! # use facet_reflect::Partial;
48//! # use facet_core::{Shape, Facet};
49//! # fn example<T: Facet<'static>>() -> Result<(), Box<dyn std::error::Error>> {
50//! let value = Partial::alloc::<T>()?
51//!     .set_field("name", "Bob")?
52//!     .begin_field("scores")?
53//!         .set(vec![95, 87, 92])?
54//!     .end()?
55//!     .build()?;
56//! # Ok(())
57//! # }
58//! ```
59//!
60//! # Working with Collections
61//!
62//! ```no_run
63//! # use facet_reflect::Partial;
64//! # use facet_core::{Shape, Facet};
65//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
66//! let mut partial = Partial::alloc::<Vec<String>>()?;
67//!
68//! // Add items to a list
69//! partial = partial.begin_list_item()?;
70//! partial = partial.set("first")?;
71//! partial = partial.end()?;
72//!
73//! partial = partial.begin_list_item()?;
74//! partial = partial.set("second")?;
75//! partial = partial.end()?;
76//!
77//! let vec = partial.build()?;
78//! # Ok(())
79//! # }
80//! ```
81//!
82//! # Working with Maps
83//!
84//! ```no_run
85//! # use facet_reflect::Partial;
86//! # use facet_core::{Shape, Facet};
87//! # use std::collections::HashMap;
88//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
89//! let mut partial = Partial::alloc::<HashMap<String, i32>>()?;
90//!
91//! // Insert key-value pairs
92//! partial = partial.begin_key()?;
93//! partial = partial.set("score")?;
94//! partial = partial.end()?;
95//! partial = partial.begin_value()?;
96//! partial = partial.set(100i32)?;
97//! partial = partial.end()?;
98//!
99//! let map = partial.build()?;
100//! # Ok(())
101//! # }
102//! ```
103//!
104//! # Safety and Memory Management
105//!
106//! The `Partial` type ensures memory safety by:
107//! - Tracking initialization state of all fields
108//! - Preventing use-after-build through state tracking
109//! - Properly handling drop semantics for partially initialized values
110//! - Supporting both owned and borrowed values through lifetime parameters
111
112use alloc::{collections::BTreeMap, vec::Vec};
113
114mod iset;
115
116mod partial_api;
117
118use crate::{KeyPath, ReflectError, TrackerKind, trace};
119
120use core::marker::PhantomData;
121
122mod heap_value;
123pub use heap_value::*;
124
125use facet_core::{
126    Def, EnumType, Field, PtrUninit, Shape, SliceBuilderVTable, Type, UserType, Variant,
127};
128use iset::ISet;
129
130/// State of a partial value
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132enum PartialState {
133    /// Partial is active and can be modified
134    Active,
135
136    /// Partial has been successfully built and cannot be reused
137    Built,
138}
139
140/// Mode of operation for frame management.
141///
142/// In `Strict` mode, frames must be fully initialized before being popped.
143/// In `Deferred` mode, frames can be stored when popped and restored on re-entry,
144/// with final validation happening in `finish_deferred()`.
145enum FrameMode {
146    /// Strict mode: frames must be fully initialized before popping.
147    Strict {
148        /// Stack of frames for nested initialization.
149        stack: Vec<Frame>,
150    },
151
152    /// Deferred mode: frames are stored when popped, can be re-entered.
153    Deferred {
154        /// Stack of frames for nested initialization.
155        stack: Vec<Frame>,
156
157        /// The frame depth when deferred mode was started.
158        /// Path calculations are relative to this depth.
159        start_depth: usize,
160
161        /// Current path as we navigate (e.g., ["inner", "x"]).
162        // TODO: Intern key paths to avoid repeated allocations. The Resolution
163        // already knows all possible paths, so we could use indices into that.
164        current_path: KeyPath,
165
166        /// Frames saved when popped, keyed by their path.
167        /// When we re-enter a path, we restore the stored frame.
168        // TODO: Consider using path indices instead of cloned KeyPaths as keys.
169        stored_frames: BTreeMap<KeyPath, Frame>,
170    },
171}
172
173impl FrameMode {
174    /// Get a reference to the frame stack.
175    const fn stack(&self) -> &Vec<Frame> {
176        match self {
177            FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
178        }
179    }
180
181    /// Get a mutable reference to the frame stack.
182    const fn stack_mut(&mut self) -> &mut Vec<Frame> {
183        match self {
184            FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
185        }
186    }
187
188    /// Check if we're in deferred mode.
189    const fn is_deferred(&self) -> bool {
190        matches!(self, FrameMode::Deferred { .. })
191    }
192
193    /// Get the start depth if in deferred mode.
194    const fn start_depth(&self) -> Option<usize> {
195        match self {
196            FrameMode::Deferred { start_depth, .. } => Some(*start_depth),
197            FrameMode::Strict { .. } => None,
198        }
199    }
200
201    /// Get the current path if in deferred mode.
202    const fn current_path(&self) -> Option<&KeyPath> {
203        match self {
204            FrameMode::Deferred { current_path, .. } => Some(current_path),
205            FrameMode::Strict { .. } => None,
206        }
207    }
208}
209
210/// A type-erased, heap-allocated, partially-initialized value.
211///
212/// [Partial] keeps track of the state of initialiation of the underlying
213/// value: if we're building `struct S { a: u32, b: String }`, we may
214/// have initialized `a`, or `b`, or both, or neither.
215///
216/// [Partial] allows navigating down nested structs and initializing them
217/// progressively: [Partial::begin_field] pushes a frame onto the stack,
218/// which then has to be initialized, and popped off with [Partial::end].
219///
220/// If [Partial::end] is called but the current frame isn't fully initialized,
221/// an error is returned: in other words, if you navigate down to a field,
222/// you have to fully initialize it one go. You can't go back up and back down
223/// to it again.
224pub struct Partial<'facet, const BORROW: bool = true> {
225    /// Frame management mode (strict or deferred) and associated state.
226    mode: FrameMode,
227
228    /// current state of the Partial
229    state: PartialState,
230
231    invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
232}
233
234#[derive(Clone, Copy, Debug)]
235pub(crate) enum MapInsertState {
236    /// Not currently inserting
237    Idle,
238
239    /// Pushing key - memory allocated, waiting for initialization
240    PushingKey {
241        /// Temporary storage for the key being built
242        key_ptr: PtrUninit,
243        /// Whether the key has been fully initialized
244        key_initialized: bool,
245        /// Whether the key's TrackedBuffer frame is still on the stack.
246        /// When true, the frame handles cleanup. When false (after end()),
247        /// the Map tracker owns the buffer and must clean it up.
248        key_frame_on_stack: bool,
249    },
250
251    /// Pushing value after key is done
252    PushingValue {
253        /// Temporary storage for the key that was built (always initialized)
254        key_ptr: PtrUninit,
255        /// Temporary storage for the value being built
256        value_ptr: Option<PtrUninit>,
257        /// Whether the value has been fully initialized
258        value_initialized: bool,
259        /// Whether the value's TrackedBuffer frame is still on the stack.
260        /// When true, the frame handles cleanup. When false (after end()),
261        /// the Map tracker owns the buffer and must clean it up.
262        value_frame_on_stack: bool,
263    },
264}
265
266#[derive(Debug, Clone, Copy)]
267pub(crate) enum FrameOwnership {
268    /// This frame owns the allocation and should deallocate it on drop
269    Owned,
270
271    /// This frame points to a field/element within a parent's allocation.
272    /// The parent's `iset[field_idx]` was CLEARED when this frame was created.
273    /// On drop: deinit if initialized, but do NOT deallocate.
274    /// On successful end(): parent's `iset[field_idx]` will be SET.
275    Field { field_idx: usize },
276
277    /// Temporary buffer tracked by parent's MapInsertState.
278    /// Used by begin_key(), begin_value() for map insertions.
279    /// Safe to drop on deinit - parent's cleanup respects is_init propagation.
280    TrackedBuffer,
281
282    /// Pointer into existing collection entry (Value object, Option inner, etc.)
283    /// Used by begin_object_entry() on existing key, begin_some() re-entry.
284    /// NOT safe to drop on deinit - parent collection has no per-entry tracking
285    /// and would try to drop the freed value again (double-free).
286    BorrowedInPlace,
287
288    /// Pointer to externally-owned memory (e.g., caller's stack via MaybeUninit).
289    /// Used by `from_raw()` for stack-friendly deserialization.
290    /// On drop: deinit if initialized (drop partially constructed values), but do NOT deallocate.
291    /// The caller owns the memory and is responsible for its lifetime.
292    External,
293}
294
295impl FrameOwnership {
296    /// Returns true if this frame is responsible for deallocating its memory.
297    ///
298    /// Both `Owned` and `TrackedBuffer` frames allocated their memory and need
299    /// to deallocate it. `Field`, `BorrowedInPlace`, and `External` frames borrow from
300    /// parent, existing structures, or caller-provided memory.
301    const fn needs_dealloc(&self) -> bool {
302        matches!(self, FrameOwnership::Owned | FrameOwnership::TrackedBuffer)
303    }
304}
305
306/// Immutable pairing of a shape with its actual allocation size.
307///
308/// This ensures that the shape and allocated size are always in sync and cannot
309/// drift apart, preventing the class of bugs where a frame's shape doesn't match
310/// what was actually allocated (see issue #1568).
311pub(crate) struct AllocatedShape {
312    shape: &'static Shape,
313    allocated_size: usize,
314}
315
316impl AllocatedShape {
317    pub(crate) const fn new(shape: &'static Shape, allocated_size: usize) -> Self {
318        Self {
319            shape,
320            allocated_size,
321        }
322    }
323
324    pub(crate) const fn shape(&self) -> &'static Shape {
325        self.shape
326    }
327
328    pub(crate) const fn allocated_size(&self) -> usize {
329        self.allocated_size
330    }
331}
332
333/// Points somewhere in a partially-initialized value. If we're initializing
334/// `a.b.c`, then the first frame would point to the beginning of `a`, the
335/// second to the beginning of the `b` field of `a`, etc.
336///
337/// A frame can point to a complex data structure, like a struct or an enum:
338/// it keeps track of whether a variant was selected, which fields are initialized,
339/// etc. and is able to drop & deinitialize
340#[must_use]
341pub(crate) struct Frame {
342    /// Address of the value being initialized
343    pub(crate) data: PtrUninit,
344
345    /// Shape of the value being initialized, paired with the actual allocation size
346    pub(crate) allocated: AllocatedShape,
347
348    /// Whether this frame's data is fully initialized
349    pub(crate) is_init: bool,
350
351    /// Tracks building mode and partial initialization state
352    pub(crate) tracker: Tracker,
353
354    /// Whether this frame owns the allocation or is just a field pointer
355    pub(crate) ownership: FrameOwnership,
356
357    /// Whether this frame is for a custom deserialization pipeline
358    pub(crate) using_custom_deserialization: bool,
359
360    /// Container-level proxy definition (from `#[facet(proxy = ...)]` on the shape).
361    /// Used during custom deserialization to convert from proxy type to target type.
362    pub(crate) shape_level_proxy: Option<&'static facet_core::ProxyDef>,
363}
364
365#[derive(Debug)]
366pub(crate) enum Tracker {
367    /// Simple scalar value - no partial initialization tracking needed.
368    /// Whether it's initialized is tracked by `Frame::is_init`.
369    Scalar,
370
371    /// Partially initialized array
372    Array {
373        /// Track which array elements are initialized (up to 63 elements)
374        iset: ISet,
375        /// If we're pushing another frame, this is set to the array index
376        current_child: Option<usize>,
377    },
378
379    /// Partially initialized struct/tuple-struct etc.
380    Struct {
381        /// fields need to be individually tracked — we only
382        /// support up to 63 fields.
383        iset: ISet,
384        /// if we're pushing another frame, this is set to the index of the struct field
385        current_child: Option<usize>,
386    },
387
388    /// Smart pointer being initialized.
389    /// Whether it's initialized is tracked by `Frame::is_init`.
390    SmartPointer,
391
392    /// We're initializing an `Arc<[T]>`, `Box<[T]>`, `Rc<[T]>`, etc.
393    ///
394    /// We're using the slice builder API to construct the slice
395    SmartPointerSlice {
396        /// The slice builder vtable
397        vtable: &'static SliceBuilderVTable,
398
399        /// Whether we're currently building an item to push
400        building_item: bool,
401    },
402
403    /// Partially initialized enum (but we picked a variant,
404    /// so it's not Uninit)
405    Enum {
406        /// Variant chosen for the enum
407        variant: &'static Variant,
408        /// tracks enum fields (for the given variant)
409        data: ISet,
410        /// If we're pushing another frame, this is set to the field index
411        current_child: Option<usize>,
412    },
413
414    /// Partially initialized list (Vec, etc.)
415    /// Whether it's initialized is tracked by `Frame::is_init`.
416    List {
417        /// If we're pushing another frame for an element
418        current_child: bool,
419    },
420
421    /// Partially initialized map (HashMap, BTreeMap, etc.)
422    /// Whether it's initialized is tracked by `Frame::is_init`.
423    Map {
424        /// State of the current insertion operation
425        insert_state: MapInsertState,
426    },
427
428    /// Partially initialized set (HashSet, BTreeSet, etc.)
429    /// Whether it's initialized is tracked by `Frame::is_init`.
430    Set {
431        /// If we're pushing another frame for an element
432        current_child: bool,
433    },
434
435    /// Option being initialized with Some(inner_value)
436    Option {
437        /// Whether we're currently building the inner value
438        building_inner: bool,
439    },
440
441    /// Result being initialized with Ok or Err
442    Result {
443        /// Whether we're building Ok (true) or Err (false)
444        is_ok: bool,
445        /// Whether we're currently building the inner value
446        building_inner: bool,
447    },
448
449    /// Dynamic value (e.g., facet_value::Value) being initialized
450    DynamicValue {
451        /// What kind of dynamic value we're building
452        state: DynamicValueState,
453    },
454}
455
456/// State for building a dynamic value
457#[derive(Debug)]
458#[allow(dead_code)] // Some variants are for future use (object support)
459pub(crate) enum DynamicValueState {
460    /// Not yet initialized - will be set to scalar, array, or object
461    Uninit,
462    /// Initialized as a scalar (null, bool, number, string, bytes)
463    Scalar,
464    /// Initialized as an array, currently building an element
465    Array { building_element: bool },
466    /// Initialized as an object
467    Object {
468        insert_state: DynamicObjectInsertState,
469    },
470}
471
472/// State for inserting into a dynamic object
473#[derive(Debug)]
474#[allow(dead_code)] // For future use (object support)
475pub(crate) enum DynamicObjectInsertState {
476    /// Idle - ready for a new key-value pair
477    Idle,
478    /// Currently building the value for a key
479    BuildingValue {
480        /// The key for the current entry
481        key: alloc::string::String,
482    },
483}
484
485impl Tracker {
486    const fn kind(&self) -> TrackerKind {
487        match self {
488            Tracker::Scalar => TrackerKind::Scalar,
489            Tracker::Array { .. } => TrackerKind::Array,
490            Tracker::Struct { .. } => TrackerKind::Struct,
491            Tracker::SmartPointer => TrackerKind::SmartPointer,
492            Tracker::SmartPointerSlice { .. } => TrackerKind::SmartPointerSlice,
493            Tracker::Enum { .. } => TrackerKind::Enum,
494            Tracker::List { .. } => TrackerKind::List,
495            Tracker::Map { .. } => TrackerKind::Map,
496            Tracker::Set { .. } => TrackerKind::Set,
497            Tracker::Option { .. } => TrackerKind::Option,
498            Tracker::Result { .. } => TrackerKind::Result,
499            Tracker::DynamicValue { .. } => TrackerKind::DynamicValue,
500        }
501    }
502
503    /// Set the current_child index for trackers that support it
504    const fn set_current_child(&mut self, idx: usize) {
505        match self {
506            Tracker::Struct { current_child, .. }
507            | Tracker::Enum { current_child, .. }
508            | Tracker::Array { current_child, .. } => {
509                *current_child = Some(idx);
510            }
511            _ => {}
512        }
513    }
514
515    /// Clear the current_child index for trackers that support it
516    const fn clear_current_child(&mut self) {
517        match self {
518            Tracker::Struct { current_child, .. }
519            | Tracker::Enum { current_child, .. }
520            | Tracker::Array { current_child, .. } => {
521                *current_child = None;
522            }
523            _ => {}
524        }
525    }
526}
527
528impl Frame {
529    const fn new(data: PtrUninit, allocated: AllocatedShape, ownership: FrameOwnership) -> Self {
530        // For empty structs (structs with 0 fields), start as initialized since there's nothing to initialize
531        // This includes empty tuples () which are zero-sized types with no fields to initialize
532        let is_init = matches!(
533            allocated.shape().ty,
534            Type::User(UserType::Struct(struct_type)) if struct_type.fields.is_empty()
535        );
536
537        Self {
538            data,
539            allocated,
540            is_init,
541            tracker: Tracker::Scalar,
542            ownership,
543            using_custom_deserialization: false,
544            shape_level_proxy: None,
545        }
546    }
547
548    /// Deinitialize any initialized field: calls `drop_in_place` but does not free any
549    /// memory even if the frame owns that memory.
550    ///
551    /// After this call, `is_init` will be false and `tracker` will be [Tracker::Scalar].
552    fn deinit(&mut self) {
553        // For BorrowedInPlace frames, we must NOT drop. These point into existing
554        // collection entries (Value objects, Option inners) where the parent has no
555        // per-entry tracking. Dropping here would cause double-free when parent drops.
556        //
557        // For TrackedBuffer frames, we CAN drop. These are temporary buffers where
558        // the parent's MapInsertState tracks initialization via is_init propagation.
559        if matches!(self.ownership, FrameOwnership::BorrowedInPlace) {
560            self.is_init = false;
561            self.tracker = Tracker::Scalar;
562            return;
563        }
564
565        // Field frames are responsible for their value during cleanup.
566        // The ownership model ensures no double-free:
567        // - begin_field: parent's iset[idx] is cleared (parent relinquishes responsibility)
568        // - end: parent's iset[idx] is set (parent reclaims responsibility), frame is popped
569        // So if Field frame is still on stack during cleanup, parent's iset[idx] is false,
570        // meaning the parent won't drop this field - the Field frame must do it.
571
572        match &self.tracker {
573            Tracker::Scalar => {
574                // Simple scalar - drop if initialized
575                if self.is_init {
576                    unsafe {
577                        self.allocated
578                            .shape()
579                            .call_drop_in_place(self.data.assume_init())
580                    };
581                }
582            }
583            Tracker::Array { iset, .. } => {
584                // Drop initialized array elements
585                if let Type::Sequence(facet_core::SequenceType::Array(array_def)) =
586                    self.allocated.shape().ty
587                {
588                    let element_layout = array_def.t.layout.sized_layout().ok();
589                    if let Some(layout) = element_layout {
590                        for idx in 0..array_def.n {
591                            if iset.get(idx) {
592                                let offset = layout.size() * idx;
593                                let element_ptr = unsafe { self.data.field_init(offset) };
594                                unsafe { array_def.t.call_drop_in_place(element_ptr) };
595                            }
596                        }
597                    }
598                }
599            }
600            Tracker::Struct { iset, .. } => {
601                // Drop initialized struct fields
602                if let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty {
603                    if iset.all_set(struct_type.fields.len()) {
604                        unsafe {
605                            self.allocated
606                                .shape()
607                                .call_drop_in_place(self.data.assume_init())
608                        };
609                    } else {
610                        for (idx, field) in struct_type.fields.iter().enumerate() {
611                            if iset.get(idx) {
612                                // This field was initialized, drop it
613                                let field_ptr = unsafe { self.data.field_init(field.offset) };
614                                unsafe { field.shape().call_drop_in_place(field_ptr) };
615                            }
616                        }
617                    }
618                }
619            }
620            Tracker::Enum { variant, data, .. } => {
621                // Drop initialized enum variant fields
622                for (idx, field) in variant.data.fields.iter().enumerate() {
623                    if data.get(idx) {
624                        // This field was initialized, drop it
625                        let field_ptr = unsafe { self.data.field_init(field.offset) };
626                        unsafe { field.shape().call_drop_in_place(field_ptr) };
627                    }
628                }
629            }
630            Tracker::SmartPointer => {
631                // Drop the initialized Box
632                if self.is_init {
633                    unsafe {
634                        self.allocated
635                            .shape()
636                            .call_drop_in_place(self.data.assume_init())
637                    };
638                }
639                // Note: we don't deallocate the inner value here because
640                // the Box's drop will handle that
641            }
642            Tracker::SmartPointerSlice { vtable, .. } => {
643                // Free the slice builder
644                let builder_ptr = unsafe { self.data.assume_init() };
645                unsafe {
646                    (vtable.free_fn)(builder_ptr);
647                }
648            }
649            Tracker::List { .. } => {
650                // Drop the initialized List
651                if self.is_init {
652                    unsafe {
653                        self.allocated
654                            .shape()
655                            .call_drop_in_place(self.data.assume_init())
656                    };
657                }
658            }
659            Tracker::Map { insert_state } => {
660                // Drop the initialized Map
661                if self.is_init {
662                    unsafe {
663                        self.allocated
664                            .shape()
665                            .call_drop_in_place(self.data.assume_init())
666                    };
667                }
668
669                // Clean up key/value buffers based on whether their TrackedBuffer frames
670                // are still on the stack. If a frame is on the stack, it handles cleanup.
671                // If a frame was already popped (via end()), we own the buffer and must clean it.
672                match insert_state {
673                    MapInsertState::PushingKey {
674                        key_ptr,
675                        key_initialized,
676                        key_frame_on_stack,
677                    } => {
678                        // Only clean up if the frame was already popped.
679                        // If key_frame_on_stack is true, the TrackedBuffer frame above us
680                        // will handle dropping and deallocating the key buffer.
681                        if !*key_frame_on_stack
682                            && let Def::Map(map_def) = self.allocated.shape().def
683                        {
684                            // Drop the key if it was initialized
685                            if *key_initialized {
686                                unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
687                            }
688                            // Deallocate the key buffer
689                            if let Ok(key_layout) = map_def.k().layout.sized_layout()
690                                && key_layout.size() > 0
691                            {
692                                unsafe {
693                                    alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_layout)
694                                };
695                            }
696                        }
697                    }
698                    MapInsertState::PushingValue {
699                        key_ptr,
700                        value_ptr,
701                        value_initialized,
702                        value_frame_on_stack,
703                    } => {
704                        if let Def::Map(map_def) = self.allocated.shape().def {
705                            // Key was already popped (that's how we got to PushingValue state),
706                            // so we always own the key buffer and must clean it up.
707                            unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
708                            if let Ok(key_layout) = map_def.k().layout.sized_layout()
709                                && key_layout.size() > 0
710                            {
711                                unsafe {
712                                    alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_layout)
713                                };
714                            }
715
716                            // Only clean up value if the frame was already popped.
717                            // If value_frame_on_stack is true, the TrackedBuffer frame above us
718                            // will handle dropping and deallocating the value buffer.
719                            if !*value_frame_on_stack && let Some(value_ptr) = value_ptr {
720                                // Drop the value if it was initialized
721                                if *value_initialized {
722                                    unsafe {
723                                        map_def.v().call_drop_in_place(value_ptr.assume_init())
724                                    };
725                                }
726                                // Deallocate the value buffer
727                                if let Ok(value_layout) = map_def.v().layout.sized_layout()
728                                    && value_layout.size() > 0
729                                {
730                                    unsafe {
731                                        alloc::alloc::dealloc(
732                                            value_ptr.as_mut_byte_ptr(),
733                                            value_layout,
734                                        )
735                                    };
736                                }
737                            }
738                        }
739                    }
740                    MapInsertState::Idle => {}
741                }
742            }
743            Tracker::Set { .. } => {
744                // Drop the initialized Set
745                if self.is_init {
746                    unsafe {
747                        self.allocated
748                            .shape()
749                            .call_drop_in_place(self.data.assume_init())
750                    };
751                }
752            }
753            Tracker::Option { building_inner } => {
754                // If we're building the inner value, it will be handled by the Option vtable
755                // No special cleanup needed here as the Option will either be properly
756                // initialized or remain uninitialized
757                if !building_inner {
758                    // Option is fully initialized, drop it normally
759                    unsafe {
760                        self.allocated
761                            .shape()
762                            .call_drop_in_place(self.data.assume_init())
763                    };
764                }
765            }
766            Tracker::Result { building_inner, .. } => {
767                // If we're building the inner value, it will be handled by the Result vtable
768                // No special cleanup needed here as the Result will either be properly
769                // initialized or remain uninitialized
770                if !building_inner {
771                    // Result is fully initialized, drop it normally
772                    unsafe {
773                        self.allocated
774                            .shape()
775                            .call_drop_in_place(self.data.assume_init())
776                    };
777                }
778            }
779            Tracker::DynamicValue { .. } => {
780                // Drop if initialized
781                if self.is_init {
782                    let result = unsafe {
783                        self.allocated
784                            .shape()
785                            .call_drop_in_place(self.data.assume_init())
786                    };
787                    if result.is_none() {
788                        // This would be a bug - DynamicValue should always have drop_in_place
789                        panic!(
790                            "DynamicValue type {} has no drop_in_place implementation",
791                            self.allocated.shape()
792                        );
793                    }
794                }
795            }
796        }
797
798        self.is_init = false;
799        self.tracker = Tracker::Scalar;
800    }
801
802    /// Deinitialize any initialized value for REPLACEMENT purposes.
803    ///
804    /// Unlike `deinit()` which is used during error cleanup, this method is used when
805    /// we're about to overwrite a value with a new one (e.g., in `set_shape`).
806    ///
807    /// The difference is important for Field frames with simple trackers:
808    /// - During cleanup: parent struct will drop all initialized fields, so Field frames skip dropping
809    /// - During replacement: we're about to overwrite, so we MUST drop the old value
810    ///
811    /// For BorrowedInPlace frames: same logic applies - we must drop when replacing.
812    fn deinit_for_replace(&mut self) {
813        // For BorrowedInPlace frames, deinit() skips dropping (parent owns on cleanup).
814        // But when REPLACING a value, we must drop the old value first.
815        if matches!(self.ownership, FrameOwnership::BorrowedInPlace) && self.is_init {
816            unsafe {
817                self.allocated
818                    .shape()
819                    .call_drop_in_place(self.data.assume_init());
820            }
821
822            // CRITICAL: For DynamicValue (e.g., facet_value::Value), the parent Object's
823            // HashMap entry still points to this location. If we just drop and leave garbage,
824            // the parent will try to drop that garbage when it's cleaned up, causing
825            // use-after-free. We must reinitialize to a safe default (Null) so the parent
826            // can safely drop it later.
827            if let Def::DynamicValue(dyn_def) = &self.allocated.shape().def {
828                unsafe {
829                    (dyn_def.vtable.set_null)(self.data);
830                }
831                // Keep is_init = true since we just initialized it to Null
832                self.tracker = Tracker::DynamicValue {
833                    state: DynamicValueState::Scalar,
834                };
835                return;
836            }
837
838            self.is_init = false;
839            self.tracker = Tracker::Scalar;
840            return;
841        }
842
843        // Field frames handle their own cleanup in deinit() - no special handling needed here.
844
845        // All other cases: use normal deinit
846        self.deinit();
847    }
848
849    /// This must be called after (fully) initializing a value.
850    ///
851    /// This sets `is_init` to `true` to indicate the value is initialized.
852    /// Composite types (structs, enums, etc.) might be handled differently.
853    ///
854    /// # Safety
855    ///
856    /// This should only be called when `self.data` has been actually initialized.
857    const unsafe fn mark_as_init(&mut self) {
858        self.is_init = true;
859    }
860
861    /// Deallocate the memory associated with this frame, if it owns it.
862    ///
863    /// The memory has to be deinitialized first, see [Frame::deinit]
864    fn dealloc(self) {
865        // Only deallocate if this frame owns its memory
866        if !self.ownership.needs_dealloc() {
867            return;
868        }
869
870        // If we need to deallocate, the frame must be deinitialized first
871        if self.is_init {
872            unreachable!("a frame has to be deinitialized before being deallocated")
873        }
874
875        // Deallocate using the actual allocated size (not derived from shape)
876        if self.allocated.allocated_size() > 0 {
877            // Use the shape for alignment, but the stored size for the actual allocation
878            if let Ok(layout) = self.allocated.shape().layout.sized_layout() {
879                let actual_layout = core::alloc::Layout::from_size_align(
880                    self.allocated.allocated_size(),
881                    layout.align(),
882                )
883                .expect("allocated_size must be valid");
884                unsafe { alloc::alloc::dealloc(self.data.as_mut_byte_ptr(), actual_layout) };
885            }
886        }
887    }
888
889    /// Fill in defaults for any unset fields that have default values.
890    ///
891    /// This handles:
892    /// - Container-level defaults (when no fields set and struct has Default impl)
893    /// - Fields with `#[facet(default = ...)]` - uses the explicit default function
894    /// - Fields with `#[facet(default)]` - uses the type's Default impl
895    /// - `Option<T>` fields - default to None
896    ///
897    /// Returns Ok(()) if successful, or an error if a field has `#[facet(default)]`
898    /// but no default implementation is available.
899    fn fill_defaults(&mut self) -> Result<(), ReflectError> {
900        // First, check if we need to upgrade from Scalar to Struct tracker
901        // This happens when no fields were visited at all in deferred mode
902        if !self.is_init
903            && matches!(self.tracker, Tracker::Scalar)
904            && let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty
905        {
906            // If no fields were visited and the container has a default, use it
907            // SAFETY: We're about to initialize the entire struct with its default value
908            let data_mut = unsafe { self.data.assume_init() };
909            if unsafe { self.allocated.shape().call_default_in_place(data_mut) }.is_some() {
910                self.is_init = true;
911                return Ok(());
912            }
913            // Otherwise initialize the struct tracker with empty iset
914            self.tracker = Tracker::Struct {
915                iset: ISet::new(struct_type.fields.len()),
916                current_child: None,
917            };
918        }
919
920        match &mut self.tracker {
921            Tracker::Struct { iset, .. } => {
922                if let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty {
923                    // Check if NO fields have been set and the container has a default
924                    let no_fields_set = (0..struct_type.fields.len()).all(|i| !iset.get(i));
925                    if no_fields_set {
926                        // SAFETY: We're about to initialize the entire struct with its default value
927                        let data_mut = unsafe { self.data.assume_init() };
928                        if unsafe { self.allocated.shape().call_default_in_place(data_mut) }
929                            .is_some()
930                        {
931                            self.tracker = Tracker::Scalar;
932                            self.is_init = true;
933                            return Ok(());
934                        }
935                    }
936
937                    // Check if the container has #[facet(default)] attribute
938                    let container_has_default = self.allocated.shape().has_default_attr();
939
940                    // Fill defaults for individual fields
941                    for (idx, field) in struct_type.fields.iter().enumerate() {
942                        // Skip already-initialized fields
943                        if iset.get(idx) {
944                            continue;
945                        }
946
947                        // Calculate field pointer
948                        let field_ptr = unsafe { self.data.field_uninit(field.offset) };
949
950                        // Try to initialize with default
951                        if unsafe {
952                            Self::try_init_field_default(field, field_ptr, container_has_default)
953                        } {
954                            // Mark field as initialized
955                            iset.set(idx);
956                        } else if field.has_default() {
957                            // Field has #[facet(default)] but we couldn't find a default function.
958                            // This happens with opaque types that don't have default_in_place.
959                            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
960                                shape: field.shape(),
961                            });
962                        }
963                    }
964                }
965            }
966            Tracker::Enum { variant, data, .. } => {
967                // Check if the container has #[facet(default)] attribute
968                let container_has_default = self.allocated.shape().has_default_attr();
969
970                // Handle enum variant fields
971                for (idx, field) in variant.data.fields.iter().enumerate() {
972                    // Skip already-initialized fields
973                    if data.get(idx) {
974                        continue;
975                    }
976
977                    // Calculate field pointer within the variant data
978                    let field_ptr = unsafe { self.data.field_uninit(field.offset) };
979
980                    // Try to initialize with default
981                    if unsafe {
982                        Self::try_init_field_default(field, field_ptr, container_has_default)
983                    } {
984                        // Mark field as initialized
985                        data.set(idx);
986                    } else if field.has_default() {
987                        // Field has #[facet(default)] but we couldn't find a default function.
988                        return Err(ReflectError::DefaultAttrButNoDefaultImpl {
989                            shape: field.shape(),
990                        });
991                    }
992                }
993            }
994            // Other tracker types don't have fields with defaults
995            _ => {}
996        }
997        Ok(())
998    }
999
1000    /// Initialize a field with its default value if one is available.
1001    ///
1002    /// Priority:
1003    /// 1. Explicit field-level default_fn (from `#[facet(default = ...)]`)
1004    /// 2. Type-level default_in_place (from Default impl, including `Option<T>`)
1005    ///    but only if the field has the DEFAULT flag
1006    /// 3. Container-level default: if the container has `#[facet(default)]` and
1007    ///    the field's type implements Default, use that
1008    /// 4. Special cases: `Option<T>` (defaults to None), () (unit type)
1009    ///
1010    /// Returns true if a default was applied, false otherwise.
1011    ///
1012    /// # Safety
1013    ///
1014    /// `field_ptr` must point to uninitialized memory of the appropriate type.
1015    unsafe fn try_init_field_default(
1016        field: &Field,
1017        field_ptr: PtrUninit,
1018        container_has_default: bool,
1019    ) -> bool {
1020        use facet_core::DefaultSource;
1021
1022        // First check for explicit field-level default
1023        if let Some(default_source) = field.default {
1024            match default_source {
1025                DefaultSource::Custom(default_fn) => {
1026                    // Custom default function - it expects PtrUninit
1027                    unsafe { default_fn(field_ptr) };
1028                    return true;
1029                }
1030                DefaultSource::FromTrait => {
1031                    // Use the type's Default trait - needs PtrMut
1032                    let field_ptr_mut = unsafe { field_ptr.assume_init() };
1033                    if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
1034                        return true;
1035                    }
1036                }
1037            }
1038        }
1039
1040        // If container has #[facet(default)] and the field's type implements Default,
1041        // use the type's Default impl. This allows `#[facet(default)]` on a struct to
1042        // mean "use Default for any missing fields whose types implement Default".
1043        if container_has_default {
1044            let field_ptr_mut = unsafe { field_ptr.assume_init() };
1045            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
1046                return true;
1047            }
1048        }
1049
1050        // Special case: Option<T> always defaults to None, even without explicit #[facet(default)]
1051        // This is because Option is fundamentally "optional" - if not set, it should be None
1052        if matches!(field.shape().def, Def::Option(_)) {
1053            let field_ptr_mut = unsafe { field_ptr.assume_init() };
1054            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
1055                return true;
1056            }
1057        }
1058
1059        // Special case: () unit type always defaults to ()
1060        if field.shape().is_type::<()>() {
1061            let field_ptr_mut = unsafe { field_ptr.assume_init() };
1062            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
1063                return true;
1064            }
1065        }
1066
1067        // Special case: Collection types (Vec, HashMap, HashSet, etc.) default to empty
1068        // These types have obvious "zero values" and it's almost always what you want
1069        // when deserializing data where the collection is simply absent.
1070        if matches!(field.shape().def, Def::List(_) | Def::Map(_) | Def::Set(_)) {
1071            let field_ptr_mut = unsafe { field_ptr.assume_init() };
1072            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
1073                return true;
1074            }
1075        }
1076
1077        false
1078    }
1079
1080    /// Returns an error if the value is not fully initialized
1081    fn require_full_initialization(&self) -> Result<(), ReflectError> {
1082        match &self.tracker {
1083            Tracker::Scalar => {
1084                if self.is_init {
1085                    Ok(())
1086                } else {
1087                    Err(ReflectError::UninitializedValue {
1088                        shape: self.allocated.shape(),
1089                    })
1090                }
1091            }
1092            Tracker::Array { iset, .. } => {
1093                match self.allocated.shape().ty {
1094                    Type::Sequence(facet_core::SequenceType::Array(array_def)) => {
1095                        // Check if all array elements are initialized
1096                        if (0..array_def.n).all(|idx| iset.get(idx)) {
1097                            Ok(())
1098                        } else {
1099                            Err(ReflectError::UninitializedValue {
1100                                shape: self.allocated.shape(),
1101                            })
1102                        }
1103                    }
1104                    _ => Err(ReflectError::UninitializedValue {
1105                        shape: self.allocated.shape(),
1106                    }),
1107                }
1108            }
1109            Tracker::Struct { iset, .. } => {
1110                match self.allocated.shape().ty {
1111                    Type::User(UserType::Struct(struct_type)) => {
1112                        if iset.all_set(struct_type.fields.len()) {
1113                            Ok(())
1114                        } else {
1115                            // Find index of the first bit not set
1116                            let first_missing_idx =
1117                                (0..struct_type.fields.len()).find(|&idx| !iset.get(idx));
1118                            if let Some(missing_idx) = first_missing_idx {
1119                                let field_name = struct_type.fields[missing_idx].name;
1120                                Err(ReflectError::UninitializedField {
1121                                    shape: self.allocated.shape(),
1122                                    field_name,
1123                                })
1124                            } else {
1125                                // fallback, something went wrong
1126                                Err(ReflectError::UninitializedValue {
1127                                    shape: self.allocated.shape(),
1128                                })
1129                            }
1130                        }
1131                    }
1132                    _ => Err(ReflectError::UninitializedValue {
1133                        shape: self.allocated.shape(),
1134                    }),
1135                }
1136            }
1137            Tracker::Enum { variant, data, .. } => {
1138                // Check if all fields of the variant are initialized
1139                let num_fields = variant.data.fields.len();
1140                if num_fields == 0 {
1141                    // Unit variant, always initialized
1142                    Ok(())
1143                } else if (0..num_fields).all(|idx| data.get(idx)) {
1144                    Ok(())
1145                } else {
1146                    // Find the first uninitialized field
1147                    let first_missing_idx = (0..num_fields).find(|&idx| !data.get(idx));
1148                    if let Some(missing_idx) = first_missing_idx {
1149                        let field_name = variant.data.fields[missing_idx].name;
1150                        Err(ReflectError::UninitializedEnumField {
1151                            shape: self.allocated.shape(),
1152                            field_name,
1153                            variant_name: variant.name,
1154                        })
1155                    } else {
1156                        Err(ReflectError::UninitializedValue {
1157                            shape: self.allocated.shape(),
1158                        })
1159                    }
1160                }
1161            }
1162            Tracker::SmartPointer => {
1163                if self.is_init {
1164                    Ok(())
1165                } else {
1166                    Err(ReflectError::UninitializedValue {
1167                        shape: self.allocated.shape(),
1168                    })
1169                }
1170            }
1171            Tracker::SmartPointerSlice { building_item, .. } => {
1172                if *building_item {
1173                    Err(ReflectError::UninitializedValue {
1174                        shape: self.allocated.shape(),
1175                    })
1176                } else {
1177                    Ok(())
1178                }
1179            }
1180            Tracker::List { current_child } => {
1181                if self.is_init && !current_child {
1182                    Ok(())
1183                } else {
1184                    Err(ReflectError::UninitializedValue {
1185                        shape: self.allocated.shape(),
1186                    })
1187                }
1188            }
1189            Tracker::Map { insert_state } => {
1190                if self.is_init && matches!(insert_state, MapInsertState::Idle) {
1191                    Ok(())
1192                } else {
1193                    Err(ReflectError::UninitializedValue {
1194                        shape: self.allocated.shape(),
1195                    })
1196                }
1197            }
1198            Tracker::Set { current_child } => {
1199                if self.is_init && !current_child {
1200                    Ok(())
1201                } else {
1202                    Err(ReflectError::UninitializedValue {
1203                        shape: self.allocated.shape(),
1204                    })
1205                }
1206            }
1207            Tracker::Option { building_inner } => {
1208                if *building_inner {
1209                    Err(ReflectError::UninitializedValue {
1210                        shape: self.allocated.shape(),
1211                    })
1212                } else {
1213                    Ok(())
1214                }
1215            }
1216            Tracker::Result { building_inner, .. } => {
1217                if *building_inner {
1218                    Err(ReflectError::UninitializedValue {
1219                        shape: self.allocated.shape(),
1220                    })
1221                } else {
1222                    Ok(())
1223                }
1224            }
1225            Tracker::DynamicValue { state } => {
1226                if matches!(state, DynamicValueState::Uninit) {
1227                    Err(ReflectError::UninitializedValue {
1228                        shape: self.allocated.shape(),
1229                    })
1230                } else {
1231                    Ok(())
1232                }
1233            }
1234        }
1235    }
1236
1237    /// Get the [EnumType] of the frame's shape, if it is an enum type
1238    pub(crate) const fn get_enum_type(&self) -> Result<EnumType, ReflectError> {
1239        match self.allocated.shape().ty {
1240            Type::User(UserType::Enum(e)) => Ok(e),
1241            _ => Err(ReflectError::WasNotA {
1242                expected: "enum",
1243                actual: self.allocated.shape(),
1244            }),
1245        }
1246    }
1247
1248    pub(crate) fn get_field(&self) -> Option<&Field> {
1249        match self.allocated.shape().ty {
1250            Type::User(user_type) => match user_type {
1251                UserType::Struct(struct_type) => {
1252                    // Try to get currently active field index
1253                    if let Tracker::Struct {
1254                        current_child: Some(idx),
1255                        ..
1256                    } = &self.tracker
1257                    {
1258                        struct_type.fields.get(*idx)
1259                    } else {
1260                        None
1261                    }
1262                }
1263                UserType::Enum(_enum_type) => {
1264                    if let Tracker::Enum {
1265                        variant,
1266                        current_child: Some(idx),
1267                        ..
1268                    } = &self.tracker
1269                    {
1270                        variant.data.fields.get(*idx)
1271                    } else {
1272                        None
1273                    }
1274                }
1275                _ => None,
1276            },
1277            _ => None,
1278        }
1279    }
1280}
1281
1282// Convenience methods on Partial for accessing FrameMode internals.
1283// These help minimize changes to the rest of the codebase during the refactor.
1284impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
1285    /// Get a reference to the frame stack.
1286    #[inline]
1287    pub(crate) const fn frames(&self) -> &Vec<Frame> {
1288        self.mode.stack()
1289    }
1290
1291    /// Get a mutable reference to the frame stack.
1292    #[inline]
1293    pub(crate) const fn frames_mut(&mut self) -> &mut Vec<Frame> {
1294        self.mode.stack_mut()
1295    }
1296
1297    /// Check if we're in deferred mode.
1298    #[inline]
1299    pub const fn is_deferred(&self) -> bool {
1300        self.mode.is_deferred()
1301    }
1302
1303    /// Get the start depth if in deferred mode.
1304    #[inline]
1305    pub(crate) const fn start_depth(&self) -> Option<usize> {
1306        self.mode.start_depth()
1307    }
1308
1309    /// Get the current path if in deferred mode.
1310    #[inline]
1311    pub(crate) const fn current_path(&self) -> Option<&KeyPath> {
1312        self.mode.current_path()
1313    }
1314}
1315
1316impl<'facet, const BORROW: bool> Drop for Partial<'facet, BORROW> {
1317    fn drop(&mut self) {
1318        trace!("🧹 Partial is being dropped");
1319
1320        // With the ownership transfer model:
1321        // - When we enter a field, parent's iset[idx] is cleared
1322        // - Parent won't try to drop fields with iset[idx] = false
1323        // - No double-free possible by construction
1324
1325        // 1. Clean up stored frames from deferred state
1326        if let FrameMode::Deferred { stored_frames, .. } = &mut self.mode {
1327            // Stored frames have ownership of their data (parent's iset was cleared).
1328            // IMPORTANT: Process in deepest-first order so children are dropped before parents.
1329            // Child frames have data pointers into parent memory, so parents must stay valid
1330            // until all their children are cleaned up.
1331            let mut stored_frames = core::mem::take(stored_frames);
1332            let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
1333            paths.sort_by_key(|p| core::cmp::Reverse(p.len()));
1334            for path in paths {
1335                if let Some(mut frame) = stored_frames.remove(&path) {
1336                    frame.deinit();
1337                    frame.dealloc();
1338                }
1339            }
1340        }
1341
1342        // 2. Pop and deinit stack frames
1343        loop {
1344            let stack = self.mode.stack_mut();
1345            if stack.is_empty() {
1346                break;
1347            }
1348
1349            let mut frame = stack.pop().unwrap();
1350            frame.deinit();
1351            frame.dealloc();
1352        }
1353    }
1354}