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