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