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}