Skip to main content

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