facet_reflect/partial/partial_api/
misc.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Misc.
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
7    /// Returns true if the Partial is in an active state (not built or poisoned).
8    ///
9    /// After `build()` succeeds or after an error causes poisoning, the Partial
10    /// becomes inactive and most operations will fail.
11    #[inline]
12    pub fn is_active(&self) -> bool {
13        self.state == PartialState::Active
14    }
15
16    /// Returns the current frame count (depth of nesting)
17    ///
18    /// The initial frame count is 1 — `begin_field` would push a new frame,
19    /// bringing it to 2, then `end` would bring it back to `1`.
20    ///
21    /// This is an implementation detail of `Partial`, kinda, but deserializers
22    /// might use this for debug assertions, to make sure the state is what
23    /// they think it is.
24    #[inline]
25    pub fn frame_count(&self) -> usize {
26        self.frames().len()
27    }
28
29    /// Returns the shape of the current frame.
30    ///
31    /// # Panics
32    ///
33    /// Panics if the Partial has been poisoned or built, or if there are no frames
34    /// (which indicates a bug in the Partial implementation).
35    #[inline]
36    pub fn shape(&self) -> &'static Shape {
37        if self.state != PartialState::Active {
38            panic!(
39                "Partial::shape() called on non-active Partial (state: {:?})",
40                self.state
41            );
42        }
43        self.frames()
44            .last()
45            .expect("Partial::shape() called but no frames exist - this is a bug")
46            .shape
47    }
48
49    /// Returns the shape of the current frame, or `None` if the Partial is
50    /// inactive (poisoned or built) or has no frames.
51    ///
52    /// This is useful for debugging/logging where you want to inspect the state
53    /// without risking a panic.
54    #[inline]
55    pub fn try_shape(&self) -> Option<&'static Shape> {
56        if self.state != PartialState::Active {
57            return None;
58        }
59        self.frames().last().map(|f| f.shape)
60    }
61
62    /// Returns true if the current frame is building a smart pointer slice (Arc<\[T\]>, Rc<\[T\]>, Box<\[T\]>).
63    ///
64    /// This is used by deserializers to determine if they should deserialize as a list
65    /// rather than recursing into the smart pointer type.
66    #[inline]
67    pub fn is_building_smart_ptr_slice(&self) -> bool {
68        if self.state != PartialState::Active {
69            return false;
70        }
71        self.frames()
72            .last()
73            .is_some_and(|f| matches!(f.tracker, Tracker::SmartPointerSlice { .. }))
74    }
75
76    /// Returns the current deferred resolution, if in deferred mode.
77    #[inline]
78    pub fn deferred_resolution(&self) -> Option<&Resolution> {
79        self.resolution()
80    }
81
82    /// Returns the current path in deferred mode as a slice (for debugging/tracing).
83    #[inline]
84    pub fn current_path_slice(&self) -> Option<&[&'static str]> {
85        self.current_path().map(|p| p.as_slice())
86    }
87
88    /// Enables deferred materialization mode with the given Resolution.
89    ///
90    /// When deferred mode is enabled:
91    /// - `end()` stores frames instead of validating them
92    /// - Re-entering a path restores the stored frame with its state intact
93    /// - `finish_deferred()` performs final validation and materialization
94    ///
95    /// This allows deserializers to handle interleaved fields (e.g., TOML dotted
96    /// keys, flattened structs) where nested fields aren't contiguous in the input.
97    ///
98    /// # Use Cases
99    ///
100    /// - TOML dotted keys: `inner.x = 1` followed by `count = 2` then `inner.y = 3`
101    /// - Flattened structs where nested fields appear at the parent level
102    /// - Any format where field order doesn't match struct nesting
103    ///
104    /// # Errors
105    ///
106    /// Returns an error if already in deferred mode.
107    #[inline]
108    pub fn begin_deferred(mut self, resolution: Resolution) -> Result<Self, ReflectError> {
109        // Cannot enable deferred mode if already in deferred mode
110        if self.is_deferred() {
111            return Err(ReflectError::InvariantViolation {
112                invariant: "begin_deferred() called but already in deferred mode",
113            });
114        }
115
116        // Take the stack out of Strict mode and wrap in Deferred mode
117        let FrameMode::Strict { stack } = core::mem::replace(
118            &mut self.mode,
119            FrameMode::Strict { stack: Vec::new() }, // temporary placeholder
120        ) else {
121            unreachable!("just checked we're not in deferred mode");
122        };
123
124        let start_depth = stack.len();
125        self.mode = FrameMode::Deferred {
126            stack,
127            resolution,
128            start_depth,
129            current_path: Vec::new(),
130            stored_frames: BTreeMap::new(),
131        };
132        Ok(self)
133    }
134
135    /// Finishes deferred mode: validates all stored frames and finalizes.
136    ///
137    /// This method:
138    /// 1. Validates that all stored frames are fully initialized
139    /// 2. Processes frames from deepest to shallowest, updating parent ISets
140    /// 3. Validates the root frame
141    ///
142    /// # Errors
143    ///
144    /// Returns an error if any required fields are missing or if the partial is
145    /// not in deferred mode.
146    pub fn finish_deferred(mut self) -> Result<Self, ReflectError> {
147        // Check if we're in deferred mode first, before extracting state
148        if !self.is_deferred() {
149            return Err(ReflectError::InvariantViolation {
150                invariant: "finish_deferred() called but deferred mode is not enabled",
151            });
152        }
153
154        // Extract deferred state, transitioning back to Strict mode
155        let FrameMode::Deferred {
156            stack,
157            start_depth,
158            mut stored_frames,
159            ..
160        } = core::mem::replace(&mut self.mode, FrameMode::Strict { stack: Vec::new() })
161        else {
162            unreachable!("just checked is_deferred()");
163        };
164
165        // Restore the stack to self.mode
166        self.mode = FrameMode::Strict { stack };
167
168        // Sort paths by depth (deepest first) so we process children before parents
169        let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
170        paths.sort_by_key(|b| core::cmp::Reverse(b.len()));
171
172        trace!(
173            "finish_deferred: Processing {} stored frames in order: {:?}",
174            paths.len(),
175            paths
176        );
177
178        // Process each stored frame from deepest to shallowest
179        for path in paths {
180            let mut frame = stored_frames.remove(&path).unwrap();
181
182            trace!(
183                "finish_deferred: Processing frame at {:?}, shape {}, tracker {:?}",
184                path,
185                frame.shape,
186                frame.tracker.kind()
187            );
188
189            // Fill in defaults for unset fields that have defaults
190            if let Err(e) = frame.fill_defaults() {
191                // Couldn't fill defaults (e.g., opaque field with #[facet(default)] but no default impl)
192                frame.deinit();
193                // Deallocate if this frame owns the allocation
194                if let FrameOwnership::Owned = frame.ownership {
195                    frame.dealloc();
196                }
197                for (_, mut remaining_frame) in stored_frames {
198                    remaining_frame.deinit();
199                    // Deallocate if this frame owns the allocation
200                    if let FrameOwnership::Owned = remaining_frame.ownership {
201                        remaining_frame.dealloc();
202                    }
203                }
204                return Err(e);
205            }
206
207            // Validate the frame is fully initialized
208            if let Err(e) = frame.require_full_initialization() {
209                // With the ownership transfer model:
210                // - Parent's iset was cleared when we entered this field
211                // - Parent won't drop it, so we must deinit it ourselves
212                frame.deinit();
213                // Deallocate if this frame owns the allocation
214                if let FrameOwnership::Owned = frame.ownership {
215                    frame.dealloc();
216                }
217
218                // Clean up remaining stored frames before returning error.
219                // All stored frames have their parent's iset cleared, so we must deinit them.
220                // Note: we must call deinit() even for partially initialized frames, since
221                // deinit() properly handles partial initialization via the tracker's iset.
222                for (_, mut remaining_frame) in stored_frames {
223                    remaining_frame.deinit();
224                    // Deallocate if this frame owns the allocation
225                    if let FrameOwnership::Owned = remaining_frame.ownership {
226                        remaining_frame.dealloc();
227                    }
228                }
229
230                // No need to poison - returning Err consumes self, Drop will handle cleanup
231                return Err(e);
232            }
233
234            // Update parent's ISet to mark this field as initialized.
235            // The parent could be:
236            // 1. On the frames stack (if path.len() == 1, parent is at start_depth - 1)
237            // 2. On the frames stack (if parent was pushed but never ended)
238            // 3. In stored_frames (if parent was ended during deferred mode)
239            if let Some(field_name) = path.last() {
240                let parent_path: Vec<_> = path[..path.len() - 1].to_vec();
241
242                // Special handling for Option inner values: when path ends with "Some",
243                // the parent is an Option frame and we need to complete the Option by
244                // writing the inner value into the Option's memory.
245                if *field_name == "Some" {
246                    // Find the Option frame (parent)
247                    let option_frame = if parent_path.is_empty() {
248                        let parent_index = start_depth.saturating_sub(1);
249                        self.frames_mut().get_mut(parent_index)
250                    } else if let Some(parent_frame) = stored_frames.get_mut(&parent_path) {
251                        Some(parent_frame)
252                    } else {
253                        let parent_frame_index = start_depth + parent_path.len() - 1;
254                        self.frames_mut().get_mut(parent_frame_index)
255                    };
256
257                    if let Some(option_frame) = option_frame {
258                        // The frame contains the inner value - write it into the Option's memory
259                        Self::complete_option_frame(option_frame, frame);
260                        // Frame data has been transferred to Option - don't drop it
261                        continue;
262                    }
263                }
264
265                if parent_path.is_empty() {
266                    // Parent is the frame that was current when deferred mode started.
267                    // It's at index (start_depth - 1) because deferred mode stores frames
268                    // relative to the position at start_depth.
269                    let parent_index = start_depth.saturating_sub(1);
270                    if let Some(root_frame) = self.frames_mut().get_mut(parent_index) {
271                        Self::mark_field_initialized(root_frame, field_name);
272                    }
273                } else {
274                    // Try stored_frames first
275                    if let Some(parent_frame) = stored_frames.get_mut(&parent_path) {
276                        Self::mark_field_initialized(parent_frame, field_name);
277                    } else {
278                        // Parent might still be on the frames stack (never ended).
279                        // The frame at index (start_depth + parent_path.len() - 1) should be the parent.
280                        let parent_frame_index = start_depth + parent_path.len() - 1;
281                        if let Some(parent_frame) = self.frames_mut().get_mut(parent_frame_index) {
282                            Self::mark_field_initialized(parent_frame, field_name);
283                        }
284                    }
285                }
286            }
287
288            // Frame is validated and parent is updated - frame is no longer needed
289            // For Field ownership, data is in parent's memory - no deallocation needed
290            // For Owned frames (e.g., from begin_object_entry), we must deallocate
291            if let FrameOwnership::Owned = frame.ownership {
292                frame.dealloc(); // Consumes frame
293            } else {
294                drop(frame);
295            }
296        }
297
298        // Invariant check: we must have at least one frame after finish_deferred
299        if self.frames().is_empty() {
300            // No need to poison - returning Err consumes self, Drop will handle cleanup
301            return Err(ReflectError::InvariantViolation {
302                invariant: "finish_deferred() left Partial with no frames",
303            });
304        }
305
306        // Fill defaults and validate the root frame is fully initialized
307        if let Some(frame) = self.frames_mut().last_mut() {
308            // Fill defaults - this can fail if a field has #[facet(default)] but no default impl
309            frame.fill_defaults()?;
310            // Root validation failed. At this point, all stored frames have been
311            // processed and their parent isets updated.
312            // No need to poison - returning Err consumes self, Drop will handle cleanup
313            frame.require_full_initialization()?;
314        }
315
316        Ok(self)
317    }
318
319    /// Mark a field as initialized in a frame's tracker
320    fn mark_field_initialized(frame: &mut Frame, field_name: &str) {
321        if let Some(idx) = Self::find_field_index(frame, field_name) {
322            // If the tracker is Scalar but this is a struct type, upgrade to Struct tracker.
323            // This can happen if the frame was deinit'd (e.g., by a failed set_default)
324            // which resets the tracker to Scalar.
325            if matches!(frame.tracker, Tracker::Scalar)
326                && let Type::User(UserType::Struct(struct_type)) = frame.shape.ty
327            {
328                frame.tracker = Tracker::Struct {
329                    iset: ISet::new(struct_type.fields.len()),
330                    current_child: None,
331                };
332            }
333
334            match &mut frame.tracker {
335                Tracker::Struct { iset, .. } => {
336                    iset.set(idx);
337                }
338                Tracker::Enum { data, .. } => {
339                    data.set(idx);
340                }
341                Tracker::Array { iset, .. } => {
342                    iset.set(idx);
343                }
344                _ => {}
345            }
346        }
347    }
348
349    /// Complete an Option frame by writing the inner value and marking it initialized.
350    /// Used in finish_deferred when processing a stored frame at a path ending with "Some".
351    fn complete_option_frame(option_frame: &mut Frame, inner_frame: Frame) {
352        if let Def::Option(option_def) = option_frame.shape.def {
353            // Use the Option vtable to initialize Some(inner_value)
354            let init_some_fn = option_def.vtable.init_some;
355
356            // The inner frame contains the inner value
357            let inner_value_ptr = unsafe { inner_frame.data.assume_init().as_const() };
358
359            // Initialize the Option as Some(inner_value)
360            unsafe {
361                init_some_fn(option_frame.data, inner_value_ptr);
362            }
363
364            // Deallocate the inner value's memory since init_some_fn moved it
365            if let FrameOwnership::Owned = inner_frame.ownership
366                && let Ok(layout) = inner_frame.shape.layout.sized_layout()
367                && layout.size() > 0
368            {
369                unsafe {
370                    ::alloc::alloc::dealloc(inner_frame.data.as_mut_byte_ptr(), layout);
371                }
372            }
373
374            // Mark the Option as initialized
375            option_frame.tracker = Tracker::Option {
376                building_inner: false,
377            };
378            option_frame.is_init = true;
379        }
380    }
381
382    /// Find the field index for a given field name in a frame
383    fn find_field_index(frame: &Frame, field_name: &str) -> Option<usize> {
384        match frame.shape.ty {
385            Type::User(UserType::Struct(struct_type)) => {
386                struct_type.fields.iter().position(|f| f.name == field_name)
387            }
388            Type::User(UserType::Enum(_)) => {
389                if let Tracker::Enum { variant, .. } = &frame.tracker {
390                    variant
391                        .data
392                        .fields
393                        .iter()
394                        .position(|f| f.name == field_name)
395                } else {
396                    None
397                }
398            }
399            _ => None,
400        }
401    }
402
403    /// Pops the current frame off the stack, indicating we're done initializing the current field
404    pub fn end(mut self) -> Result<Self, ReflectError> {
405        if let Some(_frame) = self.frames().last() {
406            crate::trace!(
407                "end() called: shape={}, tracker={:?}, is_init={}",
408                _frame.shape,
409                _frame.tracker.kind(),
410                _frame.is_init
411            );
412        }
413
414        // Special handling for SmartPointerSlice - convert builder to Arc
415        // Check if the current (top) frame is a SmartPointerSlice that needs conversion
416        let needs_slice_conversion = {
417            let frames = self.frames();
418            if frames.is_empty() {
419                false
420            } else {
421                let top_idx = frames.len() - 1;
422                crate::trace!(
423                    "end(): frames.len()={}, top tracker={:?}",
424                    frames.len(),
425                    frames[top_idx].tracker.kind()
426                );
427                matches!(
428                    frames[top_idx].tracker,
429                    Tracker::SmartPointerSlice {
430                        building_item: false,
431                        ..
432                    }
433                )
434            }
435        };
436
437        crate::trace!("end(): needs_slice_conversion={}", needs_slice_conversion);
438
439        if needs_slice_conversion {
440            let frames = self.frames_mut();
441            let top_idx = frames.len() - 1;
442
443            if let Tracker::SmartPointerSlice { vtable, .. } = &frames[top_idx].tracker {
444                // Convert the builder to Arc<[T]>
445                let vtable = *vtable;
446                let builder_ptr = unsafe { frames[top_idx].data.assume_init() };
447                let arc_ptr = unsafe { (vtable.convert_fn)(builder_ptr) };
448
449                match frames[top_idx].ownership {
450                    FrameOwnership::Field { field_idx } => {
451                        // Arc<[T]> is a field in a struct
452                        // The field frame's original data pointer was overwritten with the builder pointer,
453                        // so we need to reconstruct where the Arc should be written.
454
455                        // Get parent frame and field info
456                        let parent_idx = top_idx - 1;
457                        let parent_frame = &frames[parent_idx];
458                        let current_shape = frames[top_idx].shape;
459
460                        // Get the field to find its offset
461                        let field = if let Type::User(UserType::Struct(struct_type)) =
462                            parent_frame.shape.ty
463                        {
464                            &struct_type.fields[field_idx]
465                        } else {
466                            return Err(ReflectError::InvariantViolation {
467                                invariant: "SmartPointerSlice field frame parent must be a struct",
468                            });
469                        };
470
471                        // Calculate where the Arc should be written (parent.data + field.offset)
472                        let field_location =
473                            unsafe { parent_frame.data.field_uninit(field.offset) };
474
475                        // Write the Arc to the parent struct's field location
476                        let arc_size = current_shape
477                            .layout
478                            .sized_layout()
479                            .map_err(|_| ReflectError::Unsized {
480                                shape: current_shape,
481                                operation: "SmartPointerSlice conversion requires sized Arc",
482                            })?
483                            .size();
484                        unsafe {
485                            core::ptr::copy_nonoverlapping(
486                                arc_ptr.as_byte_ptr(),
487                                field_location.as_mut_byte_ptr(),
488                                arc_size,
489                            );
490                        }
491
492                        // Update the frame to point to the correct field location and mark as initialized
493                        frames[top_idx].data = field_location;
494                        frames[top_idx].tracker = Tracker::Scalar;
495                        frames[top_idx].is_init = true;
496
497                        // Return WITHOUT popping - the field frame will be popped by the next end() call
498                        return Ok(self);
499                    }
500                    FrameOwnership::Owned => {
501                        // Arc<[T]> is the root type or owned independently
502                        // The frame already has the allocation, we just need to update it with the Arc
503
504                        // The frame's data pointer is currently the builder, but we allocated
505                        // the Arc memory in the convert_fn. Update to point to the Arc.
506                        frames[top_idx].data = PtrUninit::new(arc_ptr.as_byte_ptr() as *mut u8);
507                        frames[top_idx].tracker = Tracker::Scalar;
508                        frames[top_idx].is_init = true;
509                        // Keep Owned ownership so Guard will properly deallocate
510
511                        // Return WITHOUT popping - the frame stays and will be built/dropped normally
512                        return Ok(self);
513                    }
514                    FrameOwnership::ManagedElsewhere => {
515                        return Err(ReflectError::InvariantViolation {
516                            invariant: "SmartPointerSlice cannot have ManagedElsewhere ownership after conversion",
517                        });
518                    }
519                }
520            }
521        }
522
523        if self.frames().len() <= 1 {
524            // Never pop the last/root frame - this indicates a broken state machine
525            // No need to poison - returning Err consumes self, Drop will handle cleanup
526            return Err(ReflectError::InvariantViolation {
527                invariant: "Partial::end() called with only one frame on the stack",
528            });
529        }
530
531        // In deferred mode, cannot pop below the start depth
532        if let Some(start_depth) = self.start_depth()
533            && self.frames().len() <= start_depth
534        {
535            // No need to poison - returning Err consumes self, Drop will handle cleanup
536            return Err(ReflectError::InvariantViolation {
537                invariant: "Partial::end() called but would pop below deferred start depth",
538            });
539        }
540
541        // Require that the top frame is fully initialized before popping.
542        // Skip this check in deferred mode - validation happens in finish_deferred().
543        // EXCEPT for collection items (map, list, set, option) which must be fully
544        // initialized before insertion/completion.
545        let requires_full_init = if !self.is_deferred() {
546            true
547        } else {
548            // In deferred mode, first check if this frame will be stored (tracked field).
549            // If so, skip full init check - the frame will be stored for later completion.
550            let is_tracked_frame = if let FrameMode::Deferred {
551                stack,
552                start_depth,
553                current_path,
554                ..
555            } = &self.mode
556            {
557                // Path depth should match the relative frame depth for a tracked field.
558                // frames.len() - start_depth should equal path.len() for tracked fields.
559                let relative_depth = stack.len() - *start_depth;
560                !current_path.is_empty() && current_path.len() == relative_depth
561            } else {
562                false
563            };
564
565            if is_tracked_frame {
566                // This frame will be stored in deferred mode - don't require full init
567                false
568            } else {
569                // Check if parent is a collection that requires fully initialized items
570                if self.frames().len() >= 2 {
571                    let frame_len = self.frames().len();
572                    let parent_frame = &self.frames()[frame_len - 2];
573                    matches!(
574                        parent_frame.tracker,
575                        Tracker::Map { .. }
576                            | Tracker::List { .. }
577                            | Tracker::Set { .. }
578                            | Tracker::Option { .. }
579                            | Tracker::Result { .. }
580                            | Tracker::DynamicValue {
581                                state: DynamicValueState::Array { .. }
582                            }
583                    )
584                } else {
585                    false
586                }
587            }
588        };
589
590        if requires_full_init {
591            // Fill defaults before checking full initialization
592            // This is important for structs in deferred mode that are children of collections
593            // (lists, maps, etc.) - they must be fully initialized before being inserted,
594            // but defaults should be applied first.
595            if self.is_deferred()
596                && let Some(frame) = self.frames_mut().last_mut()
597            {
598                crate::trace!(
599                    "end(): Filling defaults before full init check for {}, tracker={:?}",
600                    frame.shape,
601                    frame.tracker.kind()
602                );
603                frame.fill_defaults()?;
604            }
605
606            let frame = self.frames().last().unwrap();
607            crate::trace!(
608                "end(): Checking full init for {}, tracker={:?}, is_init={}",
609                frame.shape,
610                frame.tracker.kind(),
611                frame.is_init
612            );
613            let result = frame.require_full_initialization();
614            crate::trace!(
615                "end(): require_full_initialization result: {:?}",
616                result.is_ok()
617            );
618            result?
619        }
620
621        // Pop the frame and save its data pointer for SmartPointer handling
622        let mut popped_frame = self.frames_mut().pop().unwrap();
623
624        // In deferred mode, store the frame for potential re-entry and skip
625        // the normal parent-updating logic. The frame will be finalized later
626        // in finish_deferred().
627        //
628        // We only store if the path depth matches the frame depth, meaning we're
629        // ending a tracked struct/enum field, not something like begin_some()
630        // or a field inside a collection item.
631        if let FrameMode::Deferred {
632            stack,
633            start_depth,
634            current_path,
635            stored_frames,
636            ..
637        } = &mut self.mode
638        {
639            // Path depth should match the relative frame depth for a tracked field.
640            // After popping: frames.len() - start_depth + 1 should equal path.len()
641            // for fields entered via begin_field (not begin_some/begin_inner).
642            let relative_depth = stack.len() - *start_depth + 1;
643            let is_tracked_field = !current_path.is_empty() && current_path.len() == relative_depth;
644
645            if is_tracked_field {
646                trace!(
647                    "end(): Storing frame for deferred path {:?}, shape {}",
648                    current_path, popped_frame.shape
649                );
650
651                // Store the frame at the current path
652                let path = current_path.clone();
653                stored_frames.insert(path, popped_frame);
654
655                // Pop from current_path
656                current_path.pop();
657
658                // Clear parent's current_child tracking
659                if let Some(parent_frame) = stack.last_mut() {
660                    parent_frame.tracker.clear_current_child();
661                }
662
663                return Ok(self);
664            }
665        }
666
667        // check if this needs deserialization from a different shape
668        if popped_frame.using_custom_deserialization {
669            // Check for field-level proxy first, then fall back to shape-level proxy
670            let deserialize_with: Option<facet_core::ProxyConvertInFn> = self
671                .parent_field()
672                .and_then(|f| f.proxy().map(|p| p.convert_in));
673
674            // Fall back to shape-level proxy stored in the frame
675            let deserialize_with =
676                deserialize_with.or_else(|| popped_frame.shape_level_proxy.map(|p| p.convert_in));
677
678            if let Some(deserialize_with) = deserialize_with {
679                let parent_frame = self.frames_mut().last_mut().unwrap();
680
681                trace!(
682                    "Detected custom conversion needed from {} to {}",
683                    popped_frame.shape, parent_frame.shape
684                );
685
686                unsafe {
687                    let res = {
688                        let inner_value_ptr = popped_frame.data.assume_init().as_const();
689                        (deserialize_with)(inner_value_ptr, parent_frame.data)
690                    };
691                    let popped_frame_shape = popped_frame.shape;
692
693                    // Note: We do NOT call deinit() here because deserialize_with uses
694                    // ptr::read to take ownership of the source value. Calling deinit()
695                    // would cause a double-free. We mark is_init as false to satisfy
696                    // dealloc()'s assertion, then deallocate the memory.
697                    popped_frame.is_init = false;
698                    popped_frame.dealloc();
699                    let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
700                        message,
701                        src_shape: popped_frame_shape,
702                        dst_shape: parent_frame.shape,
703                    })?;
704                    if rptr.as_uninit() != parent_frame.data {
705                        return Err(ReflectError::CustomDeserializationError {
706                            message: "deserialize_with did not return the expected pointer".into(),
707                            src_shape: popped_frame_shape,
708                            dst_shape: parent_frame.shape,
709                        });
710                    }
711                    parent_frame.mark_as_init();
712                }
713                return Ok(self);
714            }
715        }
716
717        // Update parent frame's tracking when popping from a child
718        // Capture deferred state before borrowing frames mutably
719        let is_deferred = self.is_deferred();
720        let parent_frame = self.frames_mut().last_mut().unwrap();
721
722        crate::trace!(
723            "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
724            popped_frame.shape,
725            popped_frame.tracker.kind(),
726            parent_frame.shape,
727            parent_frame.tracker.kind()
728        );
729
730        // Check if we need to do a conversion - this happens when:
731        // 1. The parent frame has a builder_shape or inner type that matches the popped frame's shape
732        // 2. The parent frame has try_from
733        // 3. The parent frame is not yet initialized
734        // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
735        //    This ensures we only do conversion when begin_inner was used, not begin_some
736        let needs_conversion = !parent_frame.is_init
737            && matches!(parent_frame.tracker, Tracker::Scalar)
738            && ((parent_frame.shape.builder_shape.is_some()
739                && parent_frame.shape.builder_shape.unwrap() == popped_frame.shape)
740                || (parent_frame.shape.inner.is_some()
741                    && parent_frame.shape.inner.unwrap() == popped_frame.shape))
742            && match parent_frame.shape.vtable {
743                facet_core::VTableErased::Direct(vt) => vt.try_from.is_some(),
744                facet_core::VTableErased::Indirect(vt) => vt.try_from.is_some(),
745            };
746
747        if needs_conversion {
748            trace!(
749                "Detected implicit conversion needed from {} to {}",
750                popped_frame.shape, parent_frame.shape
751            );
752
753            // The conversion requires the source frame to be fully initialized
754            // (we're about to call assume_init() and pass to try_from)
755            if let Err(e) = popped_frame.require_full_initialization() {
756                // Deallocate the memory since the frame wasn't fully initialized
757                if let FrameOwnership::Owned = popped_frame.ownership
758                    && let Ok(layout) = popped_frame.shape.layout.sized_layout()
759                    && layout.size() > 0
760                {
761                    trace!(
762                        "Deallocating uninitialized conversion frame memory: size={}, align={}",
763                        layout.size(),
764                        layout.align()
765                    );
766                    unsafe {
767                        ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
768                    }
769                }
770                return Err(e);
771            }
772
773            // Perform the conversion
774            let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
775            let inner_shape = popped_frame.shape;
776
777            trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
778
779            // Handle Direct and Indirect vtables differently due to different return types
780            let result = match parent_frame.shape.vtable {
781                facet_core::VTableErased::Direct(vt) => {
782                    if let Some(try_from_fn) = vt.try_from {
783                        unsafe {
784                            try_from_fn(
785                                parent_frame.data.as_mut_byte_ptr() as *mut (),
786                                inner_shape,
787                                inner_ptr,
788                            )
789                        }
790                    } else {
791                        return Err(ReflectError::OperationFailed {
792                            shape: parent_frame.shape,
793                            operation: "try_from not available for this type",
794                        });
795                    }
796                }
797                facet_core::VTableErased::Indirect(vt) => {
798                    if let Some(try_from_fn) = vt.try_from {
799                        let ox_mut = facet_core::OxMut::new(
800                            unsafe { parent_frame.data.assume_init() },
801                            parent_frame.shape,
802                        );
803                        match unsafe { try_from_fn(ox_mut.into(), inner_shape, inner_ptr) } {
804                            Some(result) => result,
805                            None => {
806                                return Err(ReflectError::OperationFailed {
807                                    shape: parent_frame.shape,
808                                    operation: "try_from not available for inner type",
809                                });
810                            }
811                        }
812                    } else {
813                        return Err(ReflectError::OperationFailed {
814                            shape: parent_frame.shape,
815                            operation: "try_from not available for this type",
816                        });
817                    }
818                }
819            };
820
821            if let Err(e) = result {
822                trace!("Conversion failed: {e:?}");
823
824                // Deallocate the inner value's memory since conversion failed
825                if let FrameOwnership::Owned = popped_frame.ownership
826                    && let Ok(layout) = popped_frame.shape.layout.sized_layout()
827                    && layout.size() > 0
828                {
829                    trace!(
830                        "Deallocating conversion frame memory after failure: size={}, align={}",
831                        layout.size(),
832                        layout.align()
833                    );
834                    unsafe {
835                        ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
836                    }
837                }
838
839                return Err(ReflectError::TryFromError {
840                    src_shape: inner_shape,
841                    dst_shape: parent_frame.shape,
842                    inner: facet_core::TryFromError::Generic(e),
843                });
844            }
845
846            trace!("Conversion succeeded, marking parent as initialized");
847            parent_frame.is_init = true;
848
849            // Deallocate the inner value's memory since try_from consumed it
850            if let FrameOwnership::Owned = popped_frame.ownership
851                && let Ok(layout) = popped_frame.shape.layout.sized_layout()
852                && layout.size() > 0
853            {
854                trace!(
855                    "Deallocating conversion frame memory: size={}, align={}",
856                    layout.size(),
857                    layout.align()
858                );
859                unsafe {
860                    ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
861                }
862            }
863
864            return Ok(self);
865        }
866
867        // For Field-owned frames, reclaim responsibility in parent's tracker
868        // Only mark as initialized if the child frame was actually initialized.
869        // This prevents double-free when begin_inner/begin_some drops a value via
870        // prepare_for_reinitialization but then fails, leaving the child uninitialized.
871        //
872        // We use require_full_initialization() rather than just is_init because:
873        // - Scalar frames use is_init as the source of truth
874        // - Struct/Array/Enum frames use their iset/data as the source of truth
875        //   (is_init may never be set to true for these tracker types)
876        if let FrameOwnership::Field { field_idx } = popped_frame.ownership {
877            // In deferred mode, fill defaults on the child frame before checking initialization.
878            // This handles cases like struct fields inside enum variants inside map values -
879            // the struct's optional fields need defaults filled before we can mark the field
880            // as initialized in the parent enum.
881            if is_deferred {
882                popped_frame.fill_defaults()?;
883            }
884            let child_is_initialized = popped_frame.require_full_initialization().is_ok();
885            match &mut parent_frame.tracker {
886                Tracker::Struct {
887                    iset,
888                    current_child,
889                } => {
890                    if child_is_initialized {
891                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
892                    }
893                    *current_child = None;
894                }
895                Tracker::Array {
896                    iset,
897                    current_child,
898                } => {
899                    if child_is_initialized {
900                        iset.set(field_idx); // Parent reclaims responsibility only if child was init
901                    }
902                    *current_child = None;
903                }
904                Tracker::Enum {
905                    data,
906                    current_child,
907                    ..
908                } => {
909                    if child_is_initialized {
910                        data.set(field_idx); // Parent reclaims responsibility only if child was init
911                    }
912                    *current_child = None;
913                }
914                _ => {}
915            }
916            return Ok(self);
917        }
918
919        match &mut parent_frame.tracker {
920            Tracker::SmartPointer => {
921                // We just popped the inner value frame, so now we need to create the smart pointer
922                if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
923                    // The inner value must be fully initialized before we can create the smart pointer
924                    if let Err(e) = popped_frame.require_full_initialization() {
925                        // Inner value wasn't initialized, deallocate and return error
926                        popped_frame.deinit();
927                        popped_frame.dealloc();
928                        return Err(e);
929                    }
930
931                    let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
932                        popped_frame.deinit();
933                        popped_frame.dealloc();
934                        return Err(ReflectError::OperationFailed {
935                            shape: parent_frame.shape,
936                            operation: "SmartPointer missing new_into_fn",
937                        });
938                    };
939
940                    // The child frame contained the inner value
941                    let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
942
943                    // Use new_into_fn to create the Box
944                    unsafe {
945                        new_into_fn(parent_frame.data, inner_ptr);
946                    }
947
948                    // We just moved out of it
949                    popped_frame.tracker = Tracker::Scalar;
950                    popped_frame.is_init = false;
951
952                    // Deallocate the inner value's memory since new_into_fn moved it
953                    popped_frame.dealloc();
954
955                    parent_frame.is_init = true;
956                }
957            }
958            Tracker::List { current_child } if parent_frame.is_init => {
959                if *current_child {
960                    // We just popped an element frame, now push it to the list
961                    if let Def::List(list_def) = parent_frame.shape.def {
962                        let Some(push_fn) = list_def.push() else {
963                            return Err(ReflectError::OperationFailed {
964                                shape: parent_frame.shape,
965                                operation: "List missing push function",
966                            });
967                        };
968
969                        // The child frame contained the element value
970                        let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
971
972                        // Use push to add element to the list
973                        unsafe {
974                            push_fn(
975                                PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
976                                element_ptr,
977                            );
978                        }
979
980                        // Push moved out of popped_frame
981                        popped_frame.tracker = Tracker::Scalar;
982                        popped_frame.is_init = false;
983                        popped_frame.dealloc();
984
985                        *current_child = false;
986                    }
987                }
988            }
989            Tracker::Map { insert_state } if parent_frame.is_init => {
990                match insert_state {
991                    MapInsertState::PushingKey { key_ptr, .. } => {
992                        // We just popped the key frame - mark key as initialized and transition
993                        // to PushingValue state
994                        *insert_state = MapInsertState::PushingValue {
995                            key_ptr: *key_ptr,
996                            value_ptr: None,
997                            value_initialized: false,
998                        };
999                    }
1000                    MapInsertState::PushingValue {
1001                        key_ptr, value_ptr, ..
1002                    } => {
1003                        // We just popped the value frame, now insert the pair
1004                        if let (Some(value_ptr), Def::Map(map_def)) =
1005                            (value_ptr, parent_frame.shape.def)
1006                        {
1007                            let insert = map_def.vtable.insert;
1008
1009                            // Use insert to add key-value pair to the map
1010                            unsafe {
1011                                insert(
1012                                    PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1013                                    PtrMut::new(key_ptr.as_mut_byte_ptr()),
1014                                    PtrMut::new(value_ptr.as_mut_byte_ptr()),
1015                                );
1016                            }
1017
1018                            // Note: We don't deallocate the key and value memory here.
1019                            // The insert function has semantically moved the values into the map,
1020                            // but we still need to deallocate the temporary buffers.
1021                            // However, since we don't have frames for them anymore (they were popped),
1022                            // we need to handle deallocation here.
1023                            if let Ok(key_shape) = map_def.k().layout.sized_layout()
1024                                && key_shape.size() > 0
1025                            {
1026                                unsafe {
1027                                    ::alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
1028                                }
1029                            }
1030                            if let Ok(value_shape) = map_def.v().layout.sized_layout()
1031                                && value_shape.size() > 0
1032                            {
1033                                unsafe {
1034                                    ::alloc::alloc::dealloc(
1035                                        value_ptr.as_mut_byte_ptr(),
1036                                        value_shape,
1037                                    );
1038                                }
1039                            }
1040
1041                            // Reset to idle state
1042                            *insert_state = MapInsertState::Idle;
1043                        }
1044                    }
1045                    MapInsertState::Idle => {
1046                        // Nothing to do
1047                    }
1048                }
1049            }
1050            Tracker::Set { current_child } if parent_frame.is_init => {
1051                if *current_child {
1052                    // We just popped an element frame, now insert it into the set
1053                    if let Def::Set(set_def) = parent_frame.shape.def {
1054                        let insert = set_def.vtable.insert;
1055
1056                        // The child frame contained the element value
1057                        let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
1058
1059                        // Use insert to add element to the set
1060                        unsafe {
1061                            insert(
1062                                PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1063                                element_ptr,
1064                            );
1065                        }
1066
1067                        // Insert moved out of popped_frame
1068                        popped_frame.tracker = Tracker::Scalar;
1069                        popped_frame.is_init = false;
1070                        popped_frame.dealloc();
1071
1072                        *current_child = false;
1073                    }
1074                }
1075            }
1076            Tracker::Option { building_inner } => {
1077                crate::trace!(
1078                    "end(): matched Tracker::Option, building_inner={}",
1079                    *building_inner
1080                );
1081                // We just popped the inner value frame for an Option's Some variant
1082                if *building_inner {
1083                    if let Def::Option(option_def) = parent_frame.shape.def {
1084                        // Use the Option vtable to initialize Some(inner_value)
1085                        let init_some_fn = option_def.vtable.init_some;
1086
1087                        // The popped frame contains the inner value
1088                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
1089
1090                        // Initialize the Option as Some(inner_value)
1091                        unsafe {
1092                            init_some_fn(parent_frame.data, inner_value_ptr);
1093                        }
1094
1095                        // Deallocate the inner value's memory since init_some_fn moved it
1096                        if let FrameOwnership::Owned = popped_frame.ownership
1097                            && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1098                            && layout.size() > 0
1099                        {
1100                            unsafe {
1101                                ::alloc::alloc::dealloc(
1102                                    popped_frame.data.as_mut_byte_ptr(),
1103                                    layout,
1104                                );
1105                            }
1106                        }
1107
1108                        // Mark that we're no longer building the inner value
1109                        *building_inner = false;
1110                        crate::trace!("end(): set building_inner to false");
1111                        // Mark the Option as initialized
1112                        parent_frame.is_init = true;
1113                        crate::trace!("end(): set parent_frame.is_init to true");
1114                    } else {
1115                        return Err(ReflectError::OperationFailed {
1116                            shape: parent_frame.shape,
1117                            operation: "Option frame without Option definition",
1118                        });
1119                    }
1120                } else {
1121                    // building_inner is false - the Option was already initialized but
1122                    // begin_some was called again. The popped frame was not used to
1123                    // initialize the Option, so we need to clean it up.
1124                    popped_frame.deinit();
1125                    if let FrameOwnership::Owned = popped_frame.ownership
1126                        && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1127                        && layout.size() > 0
1128                    {
1129                        unsafe {
1130                            ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
1131                        }
1132                    }
1133                }
1134            }
1135            Tracker::Result {
1136                is_ok,
1137                building_inner,
1138            } => {
1139                crate::trace!(
1140                    "end(): matched Tracker::Result, is_ok={}, building_inner={}",
1141                    *is_ok,
1142                    *building_inner
1143                );
1144                // We just popped the inner value frame for a Result's Ok or Err variant
1145                if *building_inner {
1146                    if let Def::Result(result_def) = parent_frame.shape.def {
1147                        // The popped frame contains the inner value
1148                        let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
1149
1150                        // Initialize the Result as Ok(inner_value) or Err(inner_value)
1151                        if *is_ok {
1152                            let init_ok_fn = result_def.vtable.init_ok;
1153                            unsafe {
1154                                init_ok_fn(parent_frame.data, inner_value_ptr);
1155                            }
1156                        } else {
1157                            let init_err_fn = result_def.vtable.init_err;
1158                            unsafe {
1159                                init_err_fn(parent_frame.data, inner_value_ptr);
1160                            }
1161                        }
1162
1163                        // Deallocate the inner value's memory since init_ok/err_fn moved it
1164                        if let FrameOwnership::Owned = popped_frame.ownership
1165                            && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1166                            && layout.size() > 0
1167                        {
1168                            unsafe {
1169                                ::alloc::alloc::dealloc(
1170                                    popped_frame.data.as_mut_byte_ptr(),
1171                                    layout,
1172                                );
1173                            }
1174                        }
1175
1176                        // Mark that we're no longer building the inner value
1177                        *building_inner = false;
1178                        crate::trace!("end(): set building_inner to false");
1179                        // Mark the Result as initialized
1180                        parent_frame.is_init = true;
1181                        crate::trace!("end(): set parent_frame.is_init to true");
1182                    } else {
1183                        return Err(ReflectError::OperationFailed {
1184                            shape: parent_frame.shape,
1185                            operation: "Result frame without Result definition",
1186                        });
1187                    }
1188                } else {
1189                    // building_inner is false - the Result was already initialized but
1190                    // begin_ok/begin_err was called again. The popped frame was not used to
1191                    // initialize the Result, so we need to clean it up.
1192                    popped_frame.deinit();
1193                    if let FrameOwnership::Owned = popped_frame.ownership
1194                        && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1195                        && layout.size() > 0
1196                    {
1197                        unsafe {
1198                            ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
1199                        }
1200                    }
1201                }
1202            }
1203            Tracker::Scalar => {
1204                // the main case here is: the popped frame was a `String` and the
1205                // parent frame is an `Arc<str>`, `Box<str>` etc.
1206                match &parent_frame.shape.def {
1207                    Def::Pointer(smart_ptr_def) => {
1208                        let pointee =
1209                            smart_ptr_def
1210                                .pointee()
1211                                .ok_or(ReflectError::InvariantViolation {
1212                                    invariant: "pointer type doesn't have a pointee",
1213                                })?;
1214
1215                        if !pointee.is_shape(str::SHAPE) {
1216                            return Err(ReflectError::InvariantViolation {
1217                                invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
1218                            });
1219                        }
1220
1221                        if !popped_frame.shape.is_shape(String::SHAPE) {
1222                            return Err(ReflectError::InvariantViolation {
1223                                invariant: "the popped frame should be String when building a SmartPointer<T>",
1224                            });
1225                        }
1226
1227                        popped_frame.require_full_initialization()?;
1228
1229                        // if the just-popped frame was a SmartPointerStr, we have some conversion to do:
1230                        // Special-case: SmartPointer<str> (Box<str>, Arc<str>, Rc<str>) via SmartPointerStr tracker
1231                        // Here, popped_frame actually contains a value for String that should be moved into the smart pointer.
1232                        // We convert the String into Box<str>, Arc<str>, or Rc<str> as appropriate and write it to the parent frame.
1233                        use ::alloc::{rc::Rc, string::String, sync::Arc};
1234                        let parent_shape = parent_frame.shape;
1235
1236                        let Some(known) = smart_ptr_def.known else {
1237                            return Err(ReflectError::OperationFailed {
1238                                shape: parent_shape,
1239                                operation: "SmartPointerStr for unknown smart pointer kind",
1240                            });
1241                        };
1242
1243                        parent_frame.deinit();
1244
1245                        // Interpret the memory as a String, then convert and write.
1246                        let string_ptr = popped_frame.data.as_mut_byte_ptr() as *mut String;
1247                        let string_value = unsafe { core::ptr::read(string_ptr) };
1248
1249                        match known {
1250                            KnownPointer::Box => {
1251                                let boxed: Box<str> = string_value.into_boxed_str();
1252                                unsafe {
1253                                    core::ptr::write(
1254                                        parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1255                                        boxed,
1256                                    );
1257                                }
1258                            }
1259                            KnownPointer::Arc => {
1260                                let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1261                                unsafe {
1262                                    core::ptr::write(
1263                                        parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1264                                        arc,
1265                                    );
1266                                }
1267                            }
1268                            KnownPointer::Rc => {
1269                                let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
1270                                unsafe {
1271                                    core::ptr::write(
1272                                        parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
1273                                        rc,
1274                                    );
1275                                }
1276                            }
1277                            _ => {
1278                                return Err(ReflectError::OperationFailed {
1279                                    shape: parent_shape,
1280                                    operation: "Don't know how to build this pointer type",
1281                                });
1282                            }
1283                        }
1284
1285                        parent_frame.is_init = true;
1286
1287                        popped_frame.tracker = Tracker::Scalar;
1288                        popped_frame.is_init = false;
1289                        popped_frame.dealloc();
1290                    }
1291                    _ => {
1292                        // This can happen if begin_inner() was called on a type that
1293                        // has shape.inner but isn't a SmartPointer (e.g., Option).
1294                        // In this case, we can't complete the conversion, so return error.
1295                        return Err(ReflectError::OperationFailed {
1296                            shape: parent_frame.shape,
1297                            operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
1298                        });
1299                    }
1300                }
1301            }
1302            Tracker::SmartPointerSlice {
1303                vtable,
1304                building_item,
1305            } => {
1306                if *building_item {
1307                    // We just popped an element frame, now push it to the slice builder
1308                    let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
1309
1310                    // Use the slice builder's push_fn to add the element
1311                    crate::trace!("Pushing element to slice builder");
1312                    unsafe {
1313                        let parent_ptr = parent_frame.data.assume_init();
1314                        (vtable.push_fn)(parent_ptr, element_ptr);
1315                    }
1316
1317                    popped_frame.tracker = Tracker::Scalar;
1318                    popped_frame.is_init = false;
1319                    popped_frame.dealloc();
1320
1321                    if let Tracker::SmartPointerSlice {
1322                        building_item: bi, ..
1323                    } = &mut parent_frame.tracker
1324                    {
1325                        *bi = false;
1326                    }
1327                }
1328            }
1329            Tracker::DynamicValue {
1330                state: DynamicValueState::Array { building_element },
1331            } => {
1332                if *building_element {
1333                    // Check that the element is initialized before pushing
1334                    if !popped_frame.is_init {
1335                        // Element was never set - clean up and return error
1336                        let shape = parent_frame.shape;
1337                        popped_frame.dealloc();
1338                        *building_element = false;
1339                        // No need to poison - returning Err consumes self, Drop will handle cleanup
1340                        return Err(ReflectError::OperationFailed {
1341                            shape,
1342                            operation: "end() called but array element was never initialized",
1343                        });
1344                    }
1345
1346                    // We just popped an element frame, now push it to the dynamic array
1347                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
1348                        // Get mutable pointers - both array and element need PtrMut
1349                        let array_ptr = unsafe { parent_frame.data.assume_init() };
1350                        let element_ptr = unsafe { popped_frame.data.assume_init() };
1351
1352                        // Use push_array_element to add element to the array
1353                        unsafe {
1354                            (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
1355                        }
1356
1357                        // Push moved out of popped_frame
1358                        popped_frame.tracker = Tracker::Scalar;
1359                        popped_frame.is_init = false;
1360                        popped_frame.dealloc();
1361
1362                        *building_element = false;
1363                    }
1364                }
1365            }
1366            Tracker::DynamicValue {
1367                state: DynamicValueState::Object { insert_state },
1368            } => {
1369                if let DynamicObjectInsertState::BuildingValue { key } = insert_state {
1370                    // Check that the value is initialized before inserting
1371                    if !popped_frame.is_init {
1372                        // Value was never set - clean up and return error
1373                        let shape = parent_frame.shape;
1374                        popped_frame.dealloc();
1375                        *insert_state = DynamicObjectInsertState::Idle;
1376                        // No need to poison - returning Err consumes self, Drop will handle cleanup
1377                        return Err(ReflectError::OperationFailed {
1378                            shape,
1379                            operation: "end() called but object entry value was never initialized",
1380                        });
1381                    }
1382
1383                    // We just popped a value frame, now insert it into the dynamic object
1384                    if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
1385                        // Get mutable pointers - both object and value need PtrMut
1386                        let object_ptr = unsafe { parent_frame.data.assume_init() };
1387                        let value_ptr = unsafe { popped_frame.data.assume_init() };
1388
1389                        // Use insert_object_entry to add the key-value pair
1390                        unsafe {
1391                            (dyn_def.vtable.insert_object_entry)(object_ptr, key, value_ptr);
1392                        }
1393
1394                        // Insert moved out of popped_frame
1395                        popped_frame.tracker = Tracker::Scalar;
1396                        popped_frame.is_init = false;
1397                        popped_frame.dealloc();
1398
1399                        // Reset insert state to Idle
1400                        *insert_state = DynamicObjectInsertState::Idle;
1401                    }
1402                }
1403            }
1404            _ => {}
1405        }
1406
1407        Ok(self)
1408    }
1409
1410    /// Returns a human-readable path representing the current traversal in the builder,
1411    /// e.g., `RootStruct.fieldName[index].subfield`.
1412    pub fn path(&self) -> String {
1413        let mut out = String::new();
1414
1415        let mut path_components = Vec::new();
1416        // The stack of enum/struct/sequence names currently in context.
1417        // Start from root and build upwards.
1418        for (i, frame) in self.frames().iter().enumerate() {
1419            match frame.shape.ty {
1420                Type::User(user_type) => match user_type {
1421                    UserType::Struct(struct_type) => {
1422                        // Try to get currently active field index
1423                        let mut field_str = None;
1424                        if let Tracker::Struct {
1425                            current_child: Some(idx),
1426                            ..
1427                        } = &frame.tracker
1428                            && let Some(field) = struct_type.fields.get(*idx)
1429                        {
1430                            field_str = Some(field.name);
1431                        }
1432                        if i == 0 {
1433                            // Use Display for the root struct shape
1434                            path_components.push(format!("{}", frame.shape));
1435                        }
1436                        if let Some(field_name) = field_str {
1437                            path_components.push(format!(".{field_name}"));
1438                        }
1439                    }
1440                    UserType::Enum(_enum_type) => {
1441                        // Try to get currently active variant and field
1442                        if let Tracker::Enum {
1443                            variant,
1444                            current_child,
1445                            ..
1446                        } = &frame.tracker
1447                        {
1448                            if i == 0 {
1449                                // Use Display for the root enum shape
1450                                path_components.push(format!("{}", frame.shape));
1451                            }
1452                            path_components.push(format!("::{}", variant.name));
1453                            if let Some(idx) = *current_child
1454                                && let Some(field) = variant.data.fields.get(idx)
1455                            {
1456                                path_components.push(format!(".{}", field.name));
1457                            }
1458                        } else if i == 0 {
1459                            // just the enum display
1460                            path_components.push(format!("{}", frame.shape));
1461                        }
1462                    }
1463                    UserType::Union(_union_type) => {
1464                        path_components.push(format!("{}", frame.shape));
1465                    }
1466                    UserType::Opaque => {
1467                        path_components.push("<opaque>".to_string());
1468                    }
1469                },
1470                Type::Sequence(seq_type) => match seq_type {
1471                    facet_core::SequenceType::Array(_array_def) => {
1472                        // Try to show current element index
1473                        if let Tracker::Array {
1474                            current_child: Some(idx),
1475                            ..
1476                        } = &frame.tracker
1477                        {
1478                            path_components.push(format!("[{idx}]"));
1479                        }
1480                    }
1481                    // You can add more for Slice, Vec, etc., if applicable
1482                    _ => {
1483                        // just indicate "[]" for sequence
1484                        path_components.push("[]".to_string());
1485                    }
1486                },
1487                Type::Pointer(_) => {
1488                    // Indicate deref
1489                    path_components.push("*".to_string());
1490                }
1491                _ => {
1492                    // No structural path
1493                }
1494            }
1495        }
1496        // Merge the path_components into a single string
1497        for component in path_components {
1498            out.push_str(&component);
1499        }
1500        out
1501    }
1502
1503    /// Get the field for the parent frame
1504    pub fn parent_field(&self) -> Option<&Field> {
1505        self.frames()
1506            .iter()
1507            .rev()
1508            .nth(1)
1509            .and_then(|f| f.get_field())
1510    }
1511
1512    /// Gets the field for the current frame
1513    pub fn current_field(&self) -> Option<&Field> {
1514        self.frames().last().and_then(|f| f.get_field())
1515    }
1516}