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, Resolution, 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 resolution from facet-solver describing the field structure.
158        resolution: Resolution,
159
160        /// The frame depth when deferred mode was started.
161        /// Path calculations are relative to this depth.
162        start_depth: usize,
163
164        /// Current path as we navigate (e.g., ["inner", "x"]).
165        // TODO: Intern key paths to avoid repeated allocations. The Resolution
166        // already knows all possible paths, so we could use indices into that.
167        current_path: KeyPath,
168
169        /// Frames saved when popped, keyed by their path.
170        /// When we re-enter a path, we restore the stored frame.
171        // TODO: Consider using path indices instead of cloned KeyPaths as keys.
172        stored_frames: BTreeMap<KeyPath, Frame>,
173    },
174}
175
176impl FrameMode {
177    /// Get a reference to the frame stack.
178    fn stack(&self) -> &Vec<Frame> {
179        match self {
180            FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
181        }
182    }
183
184    /// Get a mutable reference to the frame stack.
185    fn stack_mut(&mut self) -> &mut Vec<Frame> {
186        match self {
187            FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
188        }
189    }
190
191    /// Check if we're in deferred mode.
192    fn is_deferred(&self) -> bool {
193        matches!(self, FrameMode::Deferred { .. })
194    }
195
196    /// Get the start depth if in deferred mode.
197    fn start_depth(&self) -> Option<usize> {
198        match self {
199            FrameMode::Deferred { start_depth, .. } => Some(*start_depth),
200            FrameMode::Strict { .. } => None,
201        }
202    }
203
204    /// Get the current path if in deferred mode.
205    fn current_path(&self) -> Option<&KeyPath> {
206        match self {
207            FrameMode::Deferred { current_path, .. } => Some(current_path),
208            FrameMode::Strict { .. } => None,
209        }
210    }
211
212    /// Get the resolution if in deferred mode.
213    fn resolution(&self) -> Option<&Resolution> {
214        match self {
215            FrameMode::Deferred { resolution, .. } => Some(resolution),
216            FrameMode::Strict { .. } => None,
217        }
218    }
219}
220
221/// A type-erased, heap-allocated, partially-initialized value.
222///
223/// [Partial] keeps track of the state of initialiation of the underlying
224/// value: if we're building `struct S { a: u32, b: String }`, we may
225/// have initialized `a`, or `b`, or both, or neither.
226///
227/// [Partial] allows navigating down nested structs and initializing them
228/// progressively: [Partial::begin_field] pushes a frame onto the stack,
229/// which then has to be initialized, and popped off with [Partial::end].
230///
231/// If [Partial::end] is called but the current frame isn't fully initialized,
232/// an error is returned: in other words, if you navigate down to a field,
233/// you have to fully initialize it one go. You can't go back up and back down
234/// to it again.
235pub struct Partial<'facet, const BORROW: bool = true> {
236    /// Frame management mode (strict or deferred) and associated state.
237    mode: FrameMode,
238
239    /// current state of the Partial
240    state: PartialState,
241
242    invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
243}
244
245#[derive(Clone, Copy, Debug)]
246pub(crate) enum MapInsertState {
247    /// Not currently inserting
248    Idle,
249
250    /// Pushing key - memory allocated, waiting for initialization
251    PushingKey {
252        /// Temporary storage for the key being built
253        key_ptr: PtrUninit,
254        /// Whether the key has been fully initialized
255        key_initialized: bool,
256    },
257
258    /// Pushing value after key is done
259    PushingValue {
260        /// Temporary storage for the key that was built (always initialized)
261        key_ptr: PtrUninit,
262        /// Temporary storage for the value being built
263        value_ptr: Option<PtrUninit>,
264        /// Whether the value has been fully initialized
265        value_initialized: bool,
266    },
267}
268
269#[derive(Debug, Clone, Copy)]
270pub(crate) enum FrameOwnership {
271    /// This frame owns the allocation and should deallocate it on drop
272    Owned,
273
274    /// This frame points to a field/element within a parent's allocation.
275    /// The parent's `iset\[field_idx\]` was CLEARED when this frame was created.
276    /// On drop: deinit if initialized, but do NOT deallocate.
277    /// On successful end(): parent's `iset\[field_idx\]` will be SET.
278    Field { field_idx: usize },
279
280    /// This frame's allocation is managed elsewhere (e.g., in MapInsertState)
281    ManagedElsewhere,
282}
283
284/// Points somewhere in a partially-initialized value. If we're initializing
285/// `a.b.c`, then the first frame would point to the beginning of `a`, the
286/// second to the beginning of the `b` field of `a`, etc.
287///
288/// A frame can point to a complex data structure, like a struct or an enum:
289/// it keeps track of whether a variant was selected, which fields are initialized,
290/// etc. and is able to drop & deinitialize
291#[must_use]
292pub(crate) struct Frame {
293    /// Address of the value being initialized
294    pub(crate) data: PtrUninit,
295
296    /// Shape of the value being initialized
297    pub(crate) shape: &'static Shape,
298
299    /// Whether this frame's data is fully initialized
300    pub(crate) is_init: bool,
301
302    /// Tracks building mode and partial initialization state
303    pub(crate) tracker: Tracker,
304
305    /// Whether this frame owns the allocation or is just a field pointer
306    pub(crate) ownership: FrameOwnership,
307
308    /// Whether this frame is for a custom deserialization pipeline
309    pub(crate) using_custom_deserialization: bool,
310
311    /// Container-level proxy definition (from `#[facet(proxy = ...)]` on the shape).
312    /// Used during custom deserialization to convert from proxy type to target type.
313    pub(crate) shape_level_proxy: Option<&'static facet_core::ProxyDef>,
314}
315
316#[derive(Debug)]
317pub(crate) enum Tracker {
318    /// Simple scalar value - no partial initialization tracking needed.
319    /// Whether it's initialized is tracked by `Frame::is_init`.
320    Scalar,
321
322    /// Partially initialized array
323    Array {
324        /// Track which array elements are initialized (up to 63 elements)
325        iset: ISet,
326        /// If we're pushing another frame, this is set to the array index
327        current_child: Option<usize>,
328    },
329
330    /// Partially initialized struct/tuple-struct etc.
331    Struct {
332        /// fields need to be individually tracked — we only
333        /// support up to 63 fields.
334        iset: ISet,
335        /// if we're pushing another frame, this is set to the index of the struct field
336        current_child: Option<usize>,
337    },
338
339    /// Smart pointer being initialized.
340    /// Whether it's initialized is tracked by `Frame::is_init`.
341    SmartPointer,
342
343    /// We're initializing an `Arc<[T]>`, `Box<[T]>`, `Rc<[T]>`, etc.
344    ///
345    /// We're using the slice builder API to construct the slice
346    SmartPointerSlice {
347        /// The slice builder vtable
348        vtable: &'static SliceBuilderVTable,
349
350        /// Whether we're currently building an item to push
351        building_item: bool,
352    },
353
354    /// Partially initialized enum (but we picked a variant,
355    /// so it's not Uninit)
356    Enum {
357        /// Variant chosen for the enum
358        variant: &'static Variant,
359        /// tracks enum fields (for the given variant)
360        data: ISet,
361        /// If we're pushing another frame, this is set to the field index
362        current_child: Option<usize>,
363    },
364
365    /// Partially initialized list (Vec, etc.)
366    /// Whether it's initialized is tracked by `Frame::is_init`.
367    List {
368        /// If we're pushing another frame for an element
369        current_child: bool,
370    },
371
372    /// Partially initialized map (HashMap, BTreeMap, etc.)
373    /// Whether it's initialized is tracked by `Frame::is_init`.
374    Map {
375        /// State of the current insertion operation
376        insert_state: MapInsertState,
377    },
378
379    /// Partially initialized set (HashSet, BTreeSet, etc.)
380    /// Whether it's initialized is tracked by `Frame::is_init`.
381    Set {
382        /// If we're pushing another frame for an element
383        current_child: bool,
384    },
385
386    /// Option being initialized with Some(inner_value)
387    Option {
388        /// Whether we're currently building the inner value
389        building_inner: bool,
390    },
391
392    /// Result being initialized with Ok or Err
393    Result {
394        /// Whether we're building Ok (true) or Err (false)
395        is_ok: bool,
396        /// Whether we're currently building the inner value
397        building_inner: bool,
398    },
399
400    /// Dynamic value (e.g., facet_value::Value) being initialized
401    DynamicValue {
402        /// What kind of dynamic value we're building
403        state: DynamicValueState,
404    },
405}
406
407/// State for building a dynamic value
408#[derive(Debug)]
409#[allow(dead_code)] // Some variants are for future use (object support)
410pub(crate) enum DynamicValueState {
411    /// Not yet initialized - will be set to scalar, array, or object
412    Uninit,
413    /// Initialized as a scalar (null, bool, number, string, bytes)
414    Scalar,
415    /// Initialized as an array, currently building an element
416    Array { building_element: bool },
417    /// Initialized as an object
418    Object {
419        insert_state: DynamicObjectInsertState,
420    },
421}
422
423/// State for inserting into a dynamic object
424#[derive(Debug)]
425#[allow(dead_code)] // For future use (object support)
426pub(crate) enum DynamicObjectInsertState {
427    /// Idle - ready for a new key-value pair
428    Idle,
429    /// Currently building the value for a key
430    BuildingValue {
431        /// The key for the current entry
432        key: alloc::string::String,
433    },
434}
435
436impl Tracker {
437    fn kind(&self) -> TrackerKind {
438        match self {
439            Tracker::Scalar => TrackerKind::Scalar,
440            Tracker::Array { .. } => TrackerKind::Array,
441            Tracker::Struct { .. } => TrackerKind::Struct,
442            Tracker::SmartPointer => TrackerKind::SmartPointer,
443            Tracker::SmartPointerSlice { .. } => TrackerKind::SmartPointerSlice,
444            Tracker::Enum { .. } => TrackerKind::Enum,
445            Tracker::List { .. } => TrackerKind::List,
446            Tracker::Map { .. } => TrackerKind::Map,
447            Tracker::Set { .. } => TrackerKind::Set,
448            Tracker::Option { .. } => TrackerKind::Option,
449            Tracker::Result { .. } => TrackerKind::Result,
450            Tracker::DynamicValue { .. } => TrackerKind::DynamicValue,
451        }
452    }
453
454    /// Set the current_child index for trackers that support it
455    fn set_current_child(&mut self, idx: usize) {
456        match self {
457            Tracker::Struct { current_child, .. }
458            | Tracker::Enum { current_child, .. }
459            | Tracker::Array { current_child, .. } => {
460                *current_child = Some(idx);
461            }
462            _ => {}
463        }
464    }
465
466    /// Clear the current_child index for trackers that support it
467    fn clear_current_child(&mut self) {
468        match self {
469            Tracker::Struct { current_child, .. }
470            | Tracker::Enum { current_child, .. }
471            | Tracker::Array { current_child, .. } => {
472                *current_child = None;
473            }
474            _ => {}
475        }
476    }
477}
478
479impl Frame {
480    fn new(data: PtrUninit, shape: &'static Shape, ownership: FrameOwnership) -> Self {
481        // For empty structs (structs with 0 fields), start as initialized since there's nothing to initialize
482        // This includes empty tuples () which are zero-sized types with no fields to initialize
483        let is_init = matches!(
484            shape.ty,
485            Type::User(UserType::Struct(struct_type)) if struct_type.fields.is_empty()
486        );
487
488        Self {
489            data,
490            shape,
491            is_init,
492            tracker: Tracker::Scalar,
493            ownership,
494            using_custom_deserialization: false,
495            shape_level_proxy: None,
496        }
497    }
498
499    /// Deinitialize any initialized field: calls `drop_in_place` but does not free any
500    /// memory even if the frame owns that memory.
501    ///
502    /// After this call, `is_init` will be false and `tracker` will be [Tracker::Scalar].
503    fn deinit(&mut self) {
504        // For ManagedElsewhere frames, the parent owns the value and is responsible
505        // for dropping it. We should not drop it here to avoid double-free.
506        if matches!(self.ownership, FrameOwnership::ManagedElsewhere) {
507            self.is_init = false;
508            self.tracker = Tracker::Scalar;
509            return;
510        }
511
512        match &self.tracker {
513            Tracker::Scalar => {
514                // Simple scalar - drop if initialized
515                if self.is_init {
516                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
517                }
518            }
519            Tracker::Array { iset, .. } => {
520                // Drop initialized array elements
521                if let Type::Sequence(facet_core::SequenceType::Array(array_def)) = self.shape.ty {
522                    let element_layout = array_def.t.layout.sized_layout().ok();
523                    if let Some(layout) = element_layout {
524                        for idx in 0..array_def.n {
525                            if iset.get(idx) {
526                                let offset = layout.size() * idx;
527                                let element_ptr = unsafe { self.data.field_init(offset) };
528                                unsafe { array_def.t.call_drop_in_place(element_ptr) };
529                            }
530                        }
531                    }
532                }
533            }
534            Tracker::Struct { iset, .. } => {
535                // Drop initialized struct fields
536                if let Type::User(UserType::Struct(struct_type)) = self.shape.ty {
537                    if iset.all_set() {
538                        unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
539                    } else {
540                        for (idx, field) in struct_type.fields.iter().enumerate() {
541                            if iset.get(idx) {
542                                // This field was initialized, drop it
543                                let field_ptr = unsafe { self.data.field_init(field.offset) };
544                                unsafe { field.shape().call_drop_in_place(field_ptr) };
545                            }
546                        }
547                    }
548                }
549            }
550            Tracker::Enum { variant, data, .. } => {
551                // Drop initialized enum variant fields
552                for (idx, field) in variant.data.fields.iter().enumerate() {
553                    if data.get(idx) {
554                        // This field was initialized, drop it
555                        let field_ptr = unsafe { self.data.field_init(field.offset) };
556                        unsafe { field.shape().call_drop_in_place(field_ptr) };
557                    }
558                }
559            }
560            Tracker::SmartPointer => {
561                // Drop the initialized Box
562                if self.is_init {
563                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
564                }
565                // Note: we don't deallocate the inner value here because
566                // the Box's drop will handle that
567            }
568            Tracker::SmartPointerSlice { vtable, .. } => {
569                // Free the slice builder
570                let builder_ptr = unsafe { self.data.assume_init() };
571                unsafe {
572                    (vtable.free_fn)(builder_ptr);
573                }
574            }
575            Tracker::List { .. } => {
576                // Drop the initialized List
577                if self.is_init {
578                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
579                }
580            }
581            Tracker::Map { insert_state } => {
582                // Drop the initialized Map
583                if self.is_init {
584                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
585                }
586
587                // Clean up any in-progress insertion state
588                match insert_state {
589                    MapInsertState::PushingKey {
590                        key_ptr,
591                        key_initialized,
592                    } => {
593                        if let Def::Map(map_def) = self.shape.def {
594                            // Drop the key if it was initialized
595                            if *key_initialized {
596                                unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
597                            }
598                            // Deallocate the key buffer
599                            if let Ok(key_shape) = map_def.k().layout.sized_layout()
600                                && key_shape.size() > 0
601                            {
602                                unsafe {
603                                    alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape)
604                                };
605                            }
606                        }
607                    }
608                    MapInsertState::PushingValue {
609                        key_ptr,
610                        value_ptr,
611                        value_initialized,
612                    } => {
613                        // Drop and deallocate both key and value buffers
614                        if let Def::Map(map_def) = self.shape.def {
615                            // Drop and deallocate the key (always initialized in PushingValue state)
616                            unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
617                            if let Ok(key_shape) = map_def.k().layout.sized_layout()
618                                && key_shape.size() > 0
619                            {
620                                unsafe {
621                                    alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape)
622                                };
623                            }
624
625                            // Handle the value if it exists
626                            if let Some(value_ptr) = value_ptr {
627                                // Drop the value if it was initialized
628                                if *value_initialized {
629                                    unsafe {
630                                        map_def.v().call_drop_in_place(value_ptr.assume_init())
631                                    };
632                                }
633                                // Deallocate the value buffer
634                                if let Ok(value_shape) = map_def.v().layout.sized_layout()
635                                    && value_shape.size() > 0
636                                {
637                                    unsafe {
638                                        alloc::alloc::dealloc(
639                                            value_ptr.as_mut_byte_ptr(),
640                                            value_shape,
641                                        )
642                                    };
643                                }
644                            }
645                        }
646                    }
647                    MapInsertState::Idle => {}
648                }
649            }
650            Tracker::Set { .. } => {
651                // Drop the initialized Set
652                if self.is_init {
653                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
654                }
655            }
656            Tracker::Option { building_inner } => {
657                // If we're building the inner value, it will be handled by the Option vtable
658                // No special cleanup needed here as the Option will either be properly
659                // initialized or remain uninitialized
660                if !building_inner {
661                    // Option is fully initialized, drop it normally
662                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
663                }
664            }
665            Tracker::Result { building_inner, .. } => {
666                // If we're building the inner value, it will be handled by the Result vtable
667                // No special cleanup needed here as the Result will either be properly
668                // initialized or remain uninitialized
669                if !building_inner {
670                    // Result is fully initialized, drop it normally
671                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
672                }
673            }
674            Tracker::DynamicValue { .. } => {
675                // Drop if initialized
676                if self.is_init {
677                    unsafe { self.shape.call_drop_in_place(self.data.assume_init()) };
678                }
679            }
680        }
681
682        self.is_init = false;
683        self.tracker = Tracker::Scalar;
684    }
685
686    /// This must be called after (fully) initializing a value.
687    ///
688    /// This sets `is_init` to `true` to indicate the value is initialized.
689    /// Composite types (structs, enums, etc.) might be handled differently.
690    ///
691    /// # Safety
692    ///
693    /// This should only be called when `self.data` has been actually initialized.
694    unsafe fn mark_as_init(&mut self) {
695        self.is_init = true;
696    }
697
698    /// Deallocate the memory associated with this frame, if it owns it.
699    ///
700    /// The memory has to be deinitialized first, see [Frame::deinit]
701    fn dealloc(self) {
702        if self.is_init {
703            unreachable!("a frame has to be deinitialized before being deallocated")
704        }
705
706        // Now, deallocate temporary String allocation if necessary
707        if let FrameOwnership::Owned = self.ownership
708            && let Ok(layout) = self.shape.layout.sized_layout()
709            && layout.size() > 0
710        {
711            unsafe { alloc::alloc::dealloc(self.data.as_mut_byte_ptr(), layout) };
712        }
713        // no need to update `self.ownership` since `self` drops at the end of this
714    }
715
716    /// Fill in defaults for any unset fields that have default values.
717    ///
718    /// This handles:
719    /// - Container-level defaults (when no fields set and struct has Default impl)
720    /// - Fields with `#[facet(default = ...)]` - uses the explicit default function
721    /// - Fields with `#[facet(default)]` - uses the type's Default impl
722    /// - `Option<T>` fields - default to None
723    ///
724    /// Returns Ok(()) if successful, or an error if a field has `#[facet(default)]`
725    /// but no default implementation is available.
726    fn fill_defaults(&mut self) -> Result<(), ReflectError> {
727        // First, check if we need to upgrade from Scalar to Struct tracker
728        // This happens when no fields were visited at all in deferred mode
729        if !self.is_init
730            && matches!(self.tracker, Tracker::Scalar)
731            && let Type::User(UserType::Struct(struct_type)) = self.shape.ty
732        {
733            // If no fields were visited and the container has a default, use it
734            // SAFETY: We're about to initialize the entire struct with its default value
735            let data_mut = unsafe { self.data.assume_init() };
736            if unsafe { self.shape.call_default_in_place(data_mut) }.is_some() {
737                self.is_init = true;
738                return Ok(());
739            }
740            // Otherwise initialize the struct tracker with empty iset
741            self.tracker = Tracker::Struct {
742                iset: ISet::new(struct_type.fields.len()),
743                current_child: None,
744            };
745        }
746
747        match &mut self.tracker {
748            Tracker::Struct { iset, .. } => {
749                if let Type::User(UserType::Struct(struct_type)) = self.shape.ty {
750                    // Check if NO fields have been set and the container has a default
751                    let no_fields_set = (0..struct_type.fields.len()).all(|i| !iset.get(i));
752                    if no_fields_set {
753                        // SAFETY: We're about to initialize the entire struct with its default value
754                        let data_mut = unsafe { self.data.assume_init() };
755                        if unsafe { self.shape.call_default_in_place(data_mut) }.is_some() {
756                            self.tracker = Tracker::Scalar;
757                            self.is_init = true;
758                            return Ok(());
759                        }
760                    }
761
762                    // Fill defaults for individual fields
763                    for (idx, field) in struct_type.fields.iter().enumerate() {
764                        // Skip already-initialized fields
765                        if iset.get(idx) {
766                            continue;
767                        }
768
769                        // Calculate field pointer
770                        let field_ptr = unsafe { self.data.field_uninit(field.offset) };
771
772                        // Try to initialize with default
773                        if unsafe { Self::try_init_field_default(field, field_ptr) } {
774                            // Mark field as initialized
775                            iset.set(idx);
776                        } else if field.has_default() {
777                            // Field has #[facet(default)] but we couldn't find a default function.
778                            // This happens with opaque types that don't have default_in_place.
779                            return Err(ReflectError::DefaultAttrButNoDefaultImpl {
780                                shape: field.shape(),
781                            });
782                        }
783                    }
784                }
785            }
786            Tracker::Enum { variant, data, .. } => {
787                // Handle enum variant fields
788                for (idx, field) in variant.data.fields.iter().enumerate() {
789                    // Skip already-initialized fields
790                    if data.get(idx) {
791                        continue;
792                    }
793
794                    // Calculate field pointer within the variant data
795                    let field_ptr = unsafe { self.data.field_uninit(field.offset) };
796
797                    // Try to initialize with default
798                    if unsafe { Self::try_init_field_default(field, field_ptr) } {
799                        // Mark field as initialized
800                        data.set(idx);
801                    } else if field.has_default() {
802                        // Field has #[facet(default)] but we couldn't find a default function.
803                        return Err(ReflectError::DefaultAttrButNoDefaultImpl {
804                            shape: field.shape(),
805                        });
806                    }
807                }
808            }
809            // Other tracker types don't have fields with defaults
810            _ => {}
811        }
812        Ok(())
813    }
814
815    /// Initialize a field with its default value if one is available.
816    ///
817    /// Priority:
818    /// 1. Explicit field-level default_fn (from `#[facet(default = ...)]`)
819    /// 2. Type-level default_in_place (from Default impl, including `Option<T>`)
820    ///    but only if the field has the DEFAULT flag
821    /// 3. Special cases: `Option<T>` (defaults to None), () (unit type)
822    ///
823    /// Returns true if a default was applied, false otherwise.
824    ///
825    /// # Safety
826    ///
827    /// `field_ptr` must point to uninitialized memory of the appropriate type.
828    unsafe fn try_init_field_default(field: &Field, field_ptr: PtrUninit) -> bool {
829        use facet_core::DefaultSource;
830
831        // First check for explicit field-level default
832        if let Some(default_source) = field.default {
833            match default_source {
834                DefaultSource::Custom(default_fn) => {
835                    // Custom default function - it expects PtrUninit
836                    unsafe { default_fn(field_ptr) };
837                    return true;
838                }
839                DefaultSource::FromTrait => {
840                    // Use the type's Default trait - needs PtrMut
841                    let field_ptr_mut = unsafe { field_ptr.assume_init() };
842                    if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
843                        return true;
844                    }
845                }
846            }
847        }
848
849        // Special case: Option<T> always defaults to None, even without explicit #[facet(default)]
850        // This is because Option is fundamentally "optional" - if not set, it should be None
851        if matches!(field.shape().def, Def::Option(_)) {
852            let field_ptr_mut = unsafe { field_ptr.assume_init() };
853            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
854                return true;
855            }
856        }
857
858        // Special case: () unit type always defaults to ()
859        if field.shape().is_type::<()>() {
860            let field_ptr_mut = unsafe { field_ptr.assume_init() };
861            if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
862                return true;
863            }
864        }
865
866        false
867    }
868
869    /// Returns an error if the value is not fully initialized
870    fn require_full_initialization(&self) -> Result<(), ReflectError> {
871        match self.tracker {
872            Tracker::Scalar => {
873                if self.is_init {
874                    Ok(())
875                } else {
876                    Err(ReflectError::UninitializedValue { shape: self.shape })
877                }
878            }
879            Tracker::Array { iset, .. } => {
880                match self.shape.ty {
881                    Type::Sequence(facet_core::SequenceType::Array(array_def)) => {
882                        // Check if all array elements are initialized
883                        if (0..array_def.n).all(|idx| iset.get(idx)) {
884                            Ok(())
885                        } else {
886                            Err(ReflectError::UninitializedValue { shape: self.shape })
887                        }
888                    }
889                    _ => Err(ReflectError::UninitializedValue { shape: self.shape }),
890                }
891            }
892            Tracker::Struct { iset, .. } => {
893                if iset.all_set() {
894                    Ok(())
895                } else {
896                    // Attempt to find the first uninitialized field, if possible
897                    match self.shape.ty {
898                        Type::User(UserType::Struct(struct_type)) => {
899                            // Find index of the first bit not set
900                            let first_missing_idx =
901                                (0..struct_type.fields.len()).find(|&idx| !iset.get(idx));
902                            if let Some(missing_idx) = first_missing_idx {
903                                let field_name = struct_type.fields[missing_idx].name;
904                                Err(ReflectError::UninitializedField {
905                                    shape: self.shape,
906                                    field_name,
907                                })
908                            } else {
909                                // fallback, something went wrong
910                                Err(ReflectError::UninitializedValue { shape: self.shape })
911                            }
912                        }
913                        _ => Err(ReflectError::UninitializedValue { shape: self.shape }),
914                    }
915                }
916            }
917            Tracker::Enum { variant, data, .. } => {
918                // Check if all fields of the variant are initialized
919                let num_fields = variant.data.fields.len();
920                if num_fields == 0 {
921                    // Unit variant, always initialized
922                    Ok(())
923                } else if (0..num_fields).all(|idx| data.get(idx)) {
924                    Ok(())
925                } else {
926                    // Find the first uninitialized field
927                    let first_missing_idx = (0..num_fields).find(|&idx| !data.get(idx));
928                    if let Some(missing_idx) = first_missing_idx {
929                        let field_name = variant.data.fields[missing_idx].name;
930                        Err(ReflectError::UninitializedEnumField {
931                            shape: self.shape,
932                            field_name,
933                            variant_name: variant.name,
934                        })
935                    } else {
936                        Err(ReflectError::UninitializedValue { shape: self.shape })
937                    }
938                }
939            }
940            Tracker::SmartPointer => {
941                if self.is_init {
942                    Ok(())
943                } else {
944                    Err(ReflectError::UninitializedValue { shape: self.shape })
945                }
946            }
947            Tracker::SmartPointerSlice { building_item, .. } => {
948                if building_item {
949                    Err(ReflectError::UninitializedValue { shape: self.shape })
950                } else {
951                    Ok(())
952                }
953            }
954            Tracker::List { current_child } => {
955                if self.is_init && !current_child {
956                    Ok(())
957                } else {
958                    Err(ReflectError::UninitializedValue { shape: self.shape })
959                }
960            }
961            Tracker::Map { insert_state } => {
962                if self.is_init && matches!(insert_state, MapInsertState::Idle) {
963                    Ok(())
964                } else {
965                    Err(ReflectError::UninitializedValue { shape: self.shape })
966                }
967            }
968            Tracker::Set { current_child } => {
969                if self.is_init && !current_child {
970                    Ok(())
971                } else {
972                    Err(ReflectError::UninitializedValue { shape: self.shape })
973                }
974            }
975            Tracker::Option { building_inner } => {
976                if building_inner {
977                    Err(ReflectError::UninitializedValue { shape: self.shape })
978                } else {
979                    Ok(())
980                }
981            }
982            Tracker::Result { building_inner, .. } => {
983                if building_inner {
984                    Err(ReflectError::UninitializedValue { shape: self.shape })
985                } else {
986                    Ok(())
987                }
988            }
989            Tracker::DynamicValue { ref state } => {
990                if matches!(state, DynamicValueState::Uninit) {
991                    Err(ReflectError::UninitializedValue { shape: self.shape })
992                } else {
993                    Ok(())
994                }
995            }
996        }
997    }
998
999    /// Get the [EnumType] of the frame's shape, if it is an enum type
1000    pub(crate) fn get_enum_type(&self) -> Result<EnumType, ReflectError> {
1001        match self.shape.ty {
1002            Type::User(UserType::Enum(e)) => Ok(e),
1003            _ => Err(ReflectError::WasNotA {
1004                expected: "enum",
1005                actual: self.shape,
1006            }),
1007        }
1008    }
1009
1010    pub(crate) fn get_field(&self) -> Option<&Field> {
1011        match self.shape.ty {
1012            Type::User(user_type) => match user_type {
1013                UserType::Struct(struct_type) => {
1014                    // Try to get currently active field index
1015                    if let Tracker::Struct {
1016                        current_child: Some(idx),
1017                        ..
1018                    } = &self.tracker
1019                    {
1020                        struct_type.fields.get(*idx)
1021                    } else {
1022                        None
1023                    }
1024                }
1025                UserType::Enum(_enum_type) => {
1026                    if let Tracker::Enum {
1027                        variant,
1028                        current_child: Some(idx),
1029                        ..
1030                    } = &self.tracker
1031                    {
1032                        variant.data.fields.get(*idx)
1033                    } else {
1034                        None
1035                    }
1036                }
1037                _ => None,
1038            },
1039            _ => None,
1040        }
1041    }
1042}
1043
1044// Convenience methods on Partial for accessing FrameMode internals.
1045// These help minimize changes to the rest of the codebase during the refactor.
1046impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
1047    /// Get a reference to the frame stack.
1048    #[inline]
1049    pub(crate) fn frames(&self) -> &Vec<Frame> {
1050        self.mode.stack()
1051    }
1052
1053    /// Get a mutable reference to the frame stack.
1054    #[inline]
1055    pub(crate) fn frames_mut(&mut self) -> &mut Vec<Frame> {
1056        self.mode.stack_mut()
1057    }
1058
1059    /// Check if we're in deferred mode.
1060    #[inline]
1061    pub fn is_deferred(&self) -> bool {
1062        self.mode.is_deferred()
1063    }
1064
1065    /// Get the start depth if in deferred mode.
1066    #[inline]
1067    pub(crate) fn start_depth(&self) -> Option<usize> {
1068        self.mode.start_depth()
1069    }
1070
1071    /// Get the current path if in deferred mode.
1072    #[inline]
1073    pub(crate) fn current_path(&self) -> Option<&KeyPath> {
1074        self.mode.current_path()
1075    }
1076
1077    /// Get the resolution if in deferred mode.
1078    #[inline]
1079    pub(crate) fn resolution(&self) -> Option<&Resolution> {
1080        self.mode.resolution()
1081    }
1082}
1083
1084impl<'facet, const BORROW: bool> Drop for Partial<'facet, BORROW> {
1085    fn drop(&mut self) {
1086        trace!("🧹 Partial is being dropped");
1087
1088        // With the ownership transfer model:
1089        // - When we enter a field, parent's iset[idx] is cleared
1090        // - Parent won't try to drop fields with iset[idx] = false
1091        // - No double-free possible by construction
1092
1093        // 1. Clean up stored frames from deferred state
1094        if let FrameMode::Deferred { stored_frames, .. } = &mut self.mode {
1095            // Stored frames have ownership of their data (parent's iset was cleared).
1096            for (_, mut frame) in core::mem::take(stored_frames) {
1097                // Always call deinit - it internally handles each tracker type:
1098                // - Scalar: checks is_init
1099                // - Struct/Array/Enum: uses iset to drop individual fields/elements
1100                frame.deinit();
1101
1102                // deinit() doesn't set is_init to false, so we need to do it here
1103                // before calling dealloc() which requires is_init to be false
1104                frame.is_init = false;
1105
1106                // Deallocate if this frame owns the allocation
1107                // (Field ownership means parent owns the memory, but Owned frames must be deallocated)
1108                if let FrameOwnership::Owned = frame.ownership {
1109                    frame.dealloc();
1110                }
1111            }
1112        }
1113
1114        // 2. Pop and deinit stack frames
1115        loop {
1116            let stack = self.mode.stack_mut();
1117            if stack.is_empty() {
1118                break;
1119            }
1120
1121            // Before popping, if this is a ManagedElsewhere frame that's initialized,
1122            // we need to update the parent's tracking state so the parent knows to drop it.
1123            // This handles cases like: begin_key() -> set() -> drop (without end()).
1124            let stack_len = stack.len();
1125            if stack_len >= 2 {
1126                let child_is_managed_elsewhere = matches!(
1127                    stack[stack_len - 1].ownership,
1128                    FrameOwnership::ManagedElsewhere
1129                );
1130                let child_is_init = stack[stack_len - 1].is_init;
1131
1132                if child_is_managed_elsewhere && child_is_init {
1133                    // Update parent's tracking state based on the child's initialization
1134                    let parent_frame = &mut stack[stack_len - 2];
1135                    if let Tracker::Map { insert_state } = &mut parent_frame.tracker {
1136                        match insert_state {
1137                            MapInsertState::PushingKey {
1138                                key_initialized, ..
1139                            } => {
1140                                *key_initialized = true;
1141                            }
1142                            MapInsertState::PushingValue {
1143                                value_initialized, ..
1144                            } => {
1145                                *value_initialized = true;
1146                            }
1147                            _ => {}
1148                        }
1149                    }
1150                }
1151            }
1152
1153            let mut frame = stack.pop().unwrap();
1154            // Always call deinit - it internally handles each tracker type correctly.
1155            // Parent's iset was cleared when we entered this field,
1156            // so parent won't try to drop it.
1157            frame.deinit();
1158
1159            // Only deallocate if this frame owns the allocation
1160            if let FrameOwnership::Owned = frame.ownership {
1161                frame.dealloc();
1162            }
1163        }
1164    }
1165}