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_layout = current_shape.layout.sized_layout().map_err(|_| {
477 ReflectError::Unsized {
478 shape: current_shape,
479 operation: "SmartPointerSlice conversion requires sized Arc",
480 }
481 })?;
482 let arc_size = arc_layout.size();
483 unsafe {
484 core::ptr::copy_nonoverlapping(
485 arc_ptr.as_byte_ptr(),
486 field_location.as_mut_byte_ptr(),
487 arc_size,
488 );
489 }
490
491 // Free the staging allocation from convert_fn (the Arc was copied to field_location)
492 unsafe {
493 ::alloc::alloc::dealloc(arc_ptr.as_byte_ptr() as *mut u8, arc_layout);
494 }
495
496 // Update the frame to point to the correct field location and mark as initialized
497 frames[top_idx].data = field_location;
498 frames[top_idx].tracker = Tracker::Scalar;
499 frames[top_idx].is_init = true;
500
501 // Return WITHOUT popping - the field frame will be popped by the next end() call
502 return Ok(self);
503 }
504 FrameOwnership::Owned => {
505 // Arc<[T]> is the root type or owned independently
506 // The frame already has the allocation, we just need to update it with the Arc
507
508 // The frame's data pointer is currently the builder, but we allocated
509 // the Arc memory in the convert_fn. Update to point to the Arc.
510 frames[top_idx].data = PtrUninit::new(arc_ptr.as_byte_ptr() as *mut u8);
511 frames[top_idx].tracker = Tracker::Scalar;
512 frames[top_idx].is_init = true;
513 // Keep Owned ownership so Guard will properly deallocate
514
515 // Return WITHOUT popping - the frame stays and will be built/dropped normally
516 return Ok(self);
517 }
518 FrameOwnership::ManagedElsewhere => {
519 return Err(ReflectError::InvariantViolation {
520 invariant: "SmartPointerSlice cannot have ManagedElsewhere ownership after conversion",
521 });
522 }
523 }
524 }
525 }
526
527 if self.frames().len() <= 1 {
528 // Never pop the last/root frame - this indicates a broken state machine
529 // No need to poison - returning Err consumes self, Drop will handle cleanup
530 return Err(ReflectError::InvariantViolation {
531 invariant: "Partial::end() called with only one frame on the stack",
532 });
533 }
534
535 // In deferred mode, cannot pop below the start depth
536 if let Some(start_depth) = self.start_depth()
537 && self.frames().len() <= start_depth
538 {
539 // No need to poison - returning Err consumes self, Drop will handle cleanup
540 return Err(ReflectError::InvariantViolation {
541 invariant: "Partial::end() called but would pop below deferred start depth",
542 });
543 }
544
545 // Require that the top frame is fully initialized before popping.
546 // Skip this check in deferred mode - validation happens in finish_deferred().
547 // EXCEPT for collection items (map, list, set, option) which must be fully
548 // initialized before insertion/completion.
549 let requires_full_init = if !self.is_deferred() {
550 true
551 } else {
552 // In deferred mode, first check if this frame will be stored (tracked field).
553 // If so, skip full init check - the frame will be stored for later completion.
554 let is_tracked_frame = if let FrameMode::Deferred {
555 stack,
556 start_depth,
557 current_path,
558 ..
559 } = &self.mode
560 {
561 // Path depth should match the relative frame depth for a tracked field.
562 // frames.len() - start_depth should equal path.len() for tracked fields.
563 let relative_depth = stack.len() - *start_depth;
564 !current_path.is_empty() && current_path.len() == relative_depth
565 } else {
566 false
567 };
568
569 if is_tracked_frame {
570 // This frame will be stored in deferred mode - don't require full init
571 false
572 } else {
573 // Check if parent is a collection that requires fully initialized items
574 if self.frames().len() >= 2 {
575 let frame_len = self.frames().len();
576 let parent_frame = &self.frames()[frame_len - 2];
577 matches!(
578 parent_frame.tracker,
579 Tracker::Map { .. }
580 | Tracker::List { .. }
581 | Tracker::Set { .. }
582 | Tracker::Option { .. }
583 | Tracker::Result { .. }
584 | Tracker::DynamicValue {
585 state: DynamicValueState::Array { .. }
586 }
587 )
588 } else {
589 false
590 }
591 }
592 };
593
594 if requires_full_init {
595 // Fill defaults before checking full initialization
596 // This is important for structs in deferred mode that are children of collections
597 // (lists, maps, etc.) - they must be fully initialized before being inserted,
598 // but defaults should be applied first.
599 if self.is_deferred()
600 && let Some(frame) = self.frames_mut().last_mut()
601 {
602 crate::trace!(
603 "end(): Filling defaults before full init check for {}, tracker={:?}",
604 frame.shape,
605 frame.tracker.kind()
606 );
607 frame.fill_defaults()?;
608 }
609
610 let frame = self.frames().last().unwrap();
611 crate::trace!(
612 "end(): Checking full init for {}, tracker={:?}, is_init={}",
613 frame.shape,
614 frame.tracker.kind(),
615 frame.is_init
616 );
617 let result = frame.require_full_initialization();
618 crate::trace!(
619 "end(): require_full_initialization result: {:?}",
620 result.is_ok()
621 );
622 result?
623 }
624
625 // Pop the frame and save its data pointer for SmartPointer handling
626 let mut popped_frame = self.frames_mut().pop().unwrap();
627
628 // In deferred mode, store the frame for potential re-entry and skip
629 // the normal parent-updating logic. The frame will be finalized later
630 // in finish_deferred().
631 //
632 // We only store if the path depth matches the frame depth, meaning we're
633 // ending a tracked struct/enum field, not something like begin_some()
634 // or a field inside a collection item.
635 if let FrameMode::Deferred {
636 stack,
637 start_depth,
638 current_path,
639 stored_frames,
640 ..
641 } = &mut self.mode
642 {
643 // Path depth should match the relative frame depth for a tracked field.
644 // After popping: frames.len() - start_depth + 1 should equal path.len()
645 // for fields entered via begin_field (not begin_some/begin_inner).
646 let relative_depth = stack.len() - *start_depth + 1;
647 let is_tracked_field = !current_path.is_empty() && current_path.len() == relative_depth;
648
649 if is_tracked_field {
650 trace!(
651 "end(): Storing frame for deferred path {:?}, shape {}",
652 current_path, popped_frame.shape
653 );
654
655 // Store the frame at the current path
656 let path = current_path.clone();
657 stored_frames.insert(path, popped_frame);
658
659 // Pop from current_path
660 current_path.pop();
661
662 // Clear parent's current_child tracking
663 if let Some(parent_frame) = stack.last_mut() {
664 parent_frame.tracker.clear_current_child();
665 }
666
667 return Ok(self);
668 }
669 }
670
671 // check if this needs deserialization from a different shape
672 if popped_frame.using_custom_deserialization {
673 // Check for field-level proxy first, then fall back to shape-level proxy
674 let deserialize_with: Option<facet_core::ProxyConvertInFn> = self
675 .parent_field()
676 .and_then(|f| f.proxy().map(|p| p.convert_in));
677
678 // Fall back to shape-level proxy stored in the frame
679 let deserialize_with =
680 deserialize_with.or_else(|| popped_frame.shape_level_proxy.map(|p| p.convert_in));
681
682 if let Some(deserialize_with) = deserialize_with {
683 let parent_frame = self.frames_mut().last_mut().unwrap();
684
685 trace!(
686 "Detected custom conversion needed from {} to {}",
687 popped_frame.shape, parent_frame.shape
688 );
689
690 unsafe {
691 let res = {
692 let inner_value_ptr = popped_frame.data.assume_init().as_const();
693 (deserialize_with)(inner_value_ptr, parent_frame.data)
694 };
695 let popped_frame_shape = popped_frame.shape;
696
697 // Note: We do NOT call deinit() here because deserialize_with uses
698 // ptr::read to take ownership of the source value. Calling deinit()
699 // would cause a double-free. We mark is_init as false to satisfy
700 // dealloc()'s assertion, then deallocate the memory.
701 popped_frame.is_init = false;
702 popped_frame.dealloc();
703 let rptr = res.map_err(|message| ReflectError::CustomDeserializationError {
704 message,
705 src_shape: popped_frame_shape,
706 dst_shape: parent_frame.shape,
707 })?;
708 if rptr.as_uninit() != parent_frame.data {
709 return Err(ReflectError::CustomDeserializationError {
710 message: "deserialize_with did not return the expected pointer".into(),
711 src_shape: popped_frame_shape,
712 dst_shape: parent_frame.shape,
713 });
714 }
715 parent_frame.mark_as_init();
716 }
717 return Ok(self);
718 }
719 }
720
721 // Update parent frame's tracking when popping from a child
722 // Capture deferred state before borrowing frames mutably
723 let is_deferred = self.is_deferred();
724 let parent_frame = self.frames_mut().last_mut().unwrap();
725
726 crate::trace!(
727 "end(): Popped {} (tracker {:?}), Parent {} (tracker {:?})",
728 popped_frame.shape,
729 popped_frame.tracker.kind(),
730 parent_frame.shape,
731 parent_frame.tracker.kind()
732 );
733
734 // Check if we need to do a conversion - this happens when:
735 // 1. The parent frame has a builder_shape or inner type that matches the popped frame's shape
736 // 2. The parent frame has try_from
737 // 3. The parent frame is not yet initialized
738 // 4. The parent frame's tracker is Scalar (not Option, SmartPointer, etc.)
739 // This ensures we only do conversion when begin_inner was used, not begin_some
740 let needs_conversion = !parent_frame.is_init
741 && matches!(parent_frame.tracker, Tracker::Scalar)
742 && ((parent_frame.shape.builder_shape.is_some()
743 && parent_frame.shape.builder_shape.unwrap() == popped_frame.shape)
744 || (parent_frame.shape.inner.is_some()
745 && parent_frame.shape.inner.unwrap() == popped_frame.shape))
746 && match parent_frame.shape.vtable {
747 facet_core::VTableErased::Direct(vt) => vt.try_from.is_some(),
748 facet_core::VTableErased::Indirect(vt) => vt.try_from.is_some(),
749 };
750
751 if needs_conversion {
752 trace!(
753 "Detected implicit conversion needed from {} to {}",
754 popped_frame.shape, parent_frame.shape
755 );
756
757 // The conversion requires the source frame to be fully initialized
758 // (we're about to call assume_init() and pass to try_from)
759 if let Err(e) = popped_frame.require_full_initialization() {
760 // Deallocate the memory since the frame wasn't fully initialized
761 if let FrameOwnership::Owned = popped_frame.ownership
762 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
763 && layout.size() > 0
764 {
765 trace!(
766 "Deallocating uninitialized conversion frame memory: size={}, align={}",
767 layout.size(),
768 layout.align()
769 );
770 unsafe {
771 ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
772 }
773 }
774 return Err(e);
775 }
776
777 // Perform the conversion
778 let inner_ptr = unsafe { popped_frame.data.assume_init().as_const() };
779 let inner_shape = popped_frame.shape;
780
781 trace!("Converting from {} to {}", inner_shape, parent_frame.shape);
782
783 // Handle Direct and Indirect vtables differently due to different return types
784 let result = match parent_frame.shape.vtable {
785 facet_core::VTableErased::Direct(vt) => {
786 if let Some(try_from_fn) = vt.try_from {
787 unsafe {
788 try_from_fn(
789 parent_frame.data.as_mut_byte_ptr() as *mut (),
790 inner_shape,
791 inner_ptr,
792 )
793 }
794 } else {
795 return Err(ReflectError::OperationFailed {
796 shape: parent_frame.shape,
797 operation: "try_from not available for this type",
798 });
799 }
800 }
801 facet_core::VTableErased::Indirect(vt) => {
802 if let Some(try_from_fn) = vt.try_from {
803 let ox_mut = facet_core::OxMut::new(
804 unsafe { parent_frame.data.assume_init() },
805 parent_frame.shape,
806 );
807 match unsafe { try_from_fn(ox_mut.into(), inner_shape, inner_ptr) } {
808 Some(result) => result,
809 None => {
810 return Err(ReflectError::OperationFailed {
811 shape: parent_frame.shape,
812 operation: "try_from not available for inner type",
813 });
814 }
815 }
816 } else {
817 return Err(ReflectError::OperationFailed {
818 shape: parent_frame.shape,
819 operation: "try_from not available for this type",
820 });
821 }
822 }
823 };
824
825 if let Err(e) = result {
826 trace!("Conversion failed: {e:?}");
827
828 // Deallocate the inner value's memory since conversion failed
829 if let FrameOwnership::Owned = popped_frame.ownership
830 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
831 && layout.size() > 0
832 {
833 trace!(
834 "Deallocating conversion frame memory after failure: size={}, align={}",
835 layout.size(),
836 layout.align()
837 );
838 unsafe {
839 ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
840 }
841 }
842
843 return Err(ReflectError::TryFromError {
844 src_shape: inner_shape,
845 dst_shape: parent_frame.shape,
846 inner: facet_core::TryFromError::Generic(e),
847 });
848 }
849
850 trace!("Conversion succeeded, marking parent as initialized");
851 parent_frame.is_init = true;
852
853 // Deallocate the inner value's memory since try_from consumed it
854 if let FrameOwnership::Owned = popped_frame.ownership
855 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
856 && layout.size() > 0
857 {
858 trace!(
859 "Deallocating conversion frame memory: size={}, align={}",
860 layout.size(),
861 layout.align()
862 );
863 unsafe {
864 ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
865 }
866 }
867
868 return Ok(self);
869 }
870
871 // For Field-owned frames, reclaim responsibility in parent's tracker
872 // Only mark as initialized if the child frame was actually initialized.
873 // This prevents double-free when begin_inner/begin_some drops a value via
874 // prepare_for_reinitialization but then fails, leaving the child uninitialized.
875 //
876 // We use require_full_initialization() rather than just is_init because:
877 // - Scalar frames use is_init as the source of truth
878 // - Struct/Array/Enum frames use their iset/data as the source of truth
879 // (is_init may never be set to true for these tracker types)
880 if let FrameOwnership::Field { field_idx } = popped_frame.ownership {
881 // In deferred mode, fill defaults on the child frame before checking initialization.
882 // This handles cases like struct fields inside enum variants inside map values -
883 // the struct's optional fields need defaults filled before we can mark the field
884 // as initialized in the parent enum.
885 if is_deferred {
886 popped_frame.fill_defaults()?;
887 }
888 let child_is_initialized = popped_frame.require_full_initialization().is_ok();
889 match &mut parent_frame.tracker {
890 Tracker::Struct {
891 iset,
892 current_child,
893 } => {
894 if child_is_initialized {
895 iset.set(field_idx); // Parent reclaims responsibility only if child was init
896 }
897 *current_child = None;
898 }
899 Tracker::Array {
900 iset,
901 current_child,
902 } => {
903 if child_is_initialized {
904 iset.set(field_idx); // Parent reclaims responsibility only if child was init
905 }
906 *current_child = None;
907 }
908 Tracker::Enum {
909 data,
910 current_child,
911 ..
912 } => {
913 if child_is_initialized {
914 data.set(field_idx); // Parent reclaims responsibility only if child was init
915 }
916 *current_child = None;
917 }
918 _ => {}
919 }
920 return Ok(self);
921 }
922
923 match &mut parent_frame.tracker {
924 Tracker::SmartPointer => {
925 // We just popped the inner value frame, so now we need to create the smart pointer
926 if let Def::Pointer(smart_ptr_def) = parent_frame.shape.def {
927 // The inner value must be fully initialized before we can create the smart pointer
928 if let Err(e) = popped_frame.require_full_initialization() {
929 // Inner value wasn't initialized, deallocate and return error
930 popped_frame.deinit();
931 popped_frame.dealloc();
932 return Err(e);
933 }
934
935 let Some(new_into_fn) = smart_ptr_def.vtable.new_into_fn else {
936 popped_frame.deinit();
937 popped_frame.dealloc();
938 return Err(ReflectError::OperationFailed {
939 shape: parent_frame.shape,
940 operation: "SmartPointer missing new_into_fn",
941 });
942 };
943
944 // The child frame contained the inner value
945 let inner_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
946
947 // Use new_into_fn to create the Box
948 unsafe {
949 new_into_fn(parent_frame.data, inner_ptr);
950 }
951
952 // We just moved out of it
953 popped_frame.tracker = Tracker::Scalar;
954 popped_frame.is_init = false;
955
956 // Deallocate the inner value's memory since new_into_fn moved it
957 popped_frame.dealloc();
958
959 parent_frame.is_init = true;
960 }
961 }
962 Tracker::List { current_child } if parent_frame.is_init => {
963 if *current_child {
964 // We just popped an element frame, now push it to the list
965 if let Def::List(list_def) = parent_frame.shape.def {
966 let Some(push_fn) = list_def.push() else {
967 return Err(ReflectError::OperationFailed {
968 shape: parent_frame.shape,
969 operation: "List missing push function",
970 });
971 };
972
973 // The child frame contained the element value
974 let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
975
976 // Use push to add element to the list
977 unsafe {
978 push_fn(
979 PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
980 element_ptr,
981 );
982 }
983
984 // Push moved out of popped_frame
985 popped_frame.tracker = Tracker::Scalar;
986 popped_frame.is_init = false;
987 popped_frame.dealloc();
988
989 *current_child = false;
990 }
991 }
992 }
993 Tracker::Map { insert_state } if parent_frame.is_init => {
994 match insert_state {
995 MapInsertState::PushingKey { key_ptr, .. } => {
996 // We just popped the key frame - mark key as initialized and transition
997 // to PushingValue state
998 *insert_state = MapInsertState::PushingValue {
999 key_ptr: *key_ptr,
1000 value_ptr: None,
1001 value_initialized: false,
1002 };
1003 }
1004 MapInsertState::PushingValue {
1005 key_ptr, value_ptr, ..
1006 } => {
1007 // We just popped the value frame, now insert the pair
1008 if let (Some(value_ptr), Def::Map(map_def)) =
1009 (value_ptr, parent_frame.shape.def)
1010 {
1011 let insert = map_def.vtable.insert;
1012
1013 // Use insert to add key-value pair to the map
1014 unsafe {
1015 insert(
1016 PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1017 PtrMut::new(key_ptr.as_mut_byte_ptr()),
1018 PtrMut::new(value_ptr.as_mut_byte_ptr()),
1019 );
1020 }
1021
1022 // Note: We don't deallocate the key and value memory here.
1023 // The insert function has semantically moved the values into the map,
1024 // but we still need to deallocate the temporary buffers.
1025 // However, since we don't have frames for them anymore (they were popped),
1026 // we need to handle deallocation here.
1027 if let Ok(key_shape) = map_def.k().layout.sized_layout()
1028 && key_shape.size() > 0
1029 {
1030 unsafe {
1031 ::alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_shape);
1032 }
1033 }
1034 if let Ok(value_shape) = map_def.v().layout.sized_layout()
1035 && value_shape.size() > 0
1036 {
1037 unsafe {
1038 ::alloc::alloc::dealloc(
1039 value_ptr.as_mut_byte_ptr(),
1040 value_shape,
1041 );
1042 }
1043 }
1044
1045 // Reset to idle state
1046 *insert_state = MapInsertState::Idle;
1047 }
1048 }
1049 MapInsertState::Idle => {
1050 // Nothing to do
1051 }
1052 }
1053 }
1054 Tracker::Set { current_child } if parent_frame.is_init => {
1055 if *current_child {
1056 // We just popped an element frame, now insert it into the set
1057 if let Def::Set(set_def) = parent_frame.shape.def {
1058 let insert = set_def.vtable.insert;
1059
1060 // The child frame contained the element value
1061 let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
1062
1063 // Use insert to add element to the set
1064 unsafe {
1065 insert(
1066 PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
1067 element_ptr,
1068 );
1069 }
1070
1071 // Insert moved out of popped_frame
1072 popped_frame.tracker = Tracker::Scalar;
1073 popped_frame.is_init = false;
1074 popped_frame.dealloc();
1075
1076 *current_child = false;
1077 }
1078 }
1079 }
1080 Tracker::Option { building_inner } => {
1081 crate::trace!(
1082 "end(): matched Tracker::Option, building_inner={}",
1083 *building_inner
1084 );
1085 // We just popped the inner value frame for an Option's Some variant
1086 if *building_inner {
1087 if let Def::Option(option_def) = parent_frame.shape.def {
1088 // Use the Option vtable to initialize Some(inner_value)
1089 let init_some_fn = option_def.vtable.init_some;
1090
1091 // The popped frame contains the inner value
1092 let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
1093
1094 // Initialize the Option as Some(inner_value)
1095 unsafe {
1096 init_some_fn(parent_frame.data, inner_value_ptr);
1097 }
1098
1099 // Deallocate the inner value's memory since init_some_fn moved it
1100 if let FrameOwnership::Owned = popped_frame.ownership
1101 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1102 && layout.size() > 0
1103 {
1104 unsafe {
1105 ::alloc::alloc::dealloc(
1106 popped_frame.data.as_mut_byte_ptr(),
1107 layout,
1108 );
1109 }
1110 }
1111
1112 // Mark that we're no longer building the inner value
1113 *building_inner = false;
1114 crate::trace!("end(): set building_inner to false");
1115 // Mark the Option as initialized
1116 parent_frame.is_init = true;
1117 crate::trace!("end(): set parent_frame.is_init to true");
1118 } else {
1119 return Err(ReflectError::OperationFailed {
1120 shape: parent_frame.shape,
1121 operation: "Option frame without Option definition",
1122 });
1123 }
1124 } else {
1125 // building_inner is false - the Option was already initialized but
1126 // begin_some was called again. The popped frame was not used to
1127 // initialize the Option, so we need to clean it up.
1128 popped_frame.deinit();
1129 if let FrameOwnership::Owned = popped_frame.ownership
1130 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1131 && layout.size() > 0
1132 {
1133 unsafe {
1134 ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
1135 }
1136 }
1137 }
1138 }
1139 Tracker::Result {
1140 is_ok,
1141 building_inner,
1142 } => {
1143 crate::trace!(
1144 "end(): matched Tracker::Result, is_ok={}, building_inner={}",
1145 *is_ok,
1146 *building_inner
1147 );
1148 // We just popped the inner value frame for a Result's Ok or Err variant
1149 if *building_inner {
1150 if let Def::Result(result_def) = parent_frame.shape.def {
1151 // The popped frame contains the inner value
1152 let inner_value_ptr = unsafe { popped_frame.data.assume_init().as_const() };
1153
1154 // Initialize the Result as Ok(inner_value) or Err(inner_value)
1155 if *is_ok {
1156 let init_ok_fn = result_def.vtable.init_ok;
1157 unsafe {
1158 init_ok_fn(parent_frame.data, inner_value_ptr);
1159 }
1160 } else {
1161 let init_err_fn = result_def.vtable.init_err;
1162 unsafe {
1163 init_err_fn(parent_frame.data, inner_value_ptr);
1164 }
1165 }
1166
1167 // Deallocate the inner value's memory since init_ok/err_fn moved it
1168 if let FrameOwnership::Owned = popped_frame.ownership
1169 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1170 && layout.size() > 0
1171 {
1172 unsafe {
1173 ::alloc::alloc::dealloc(
1174 popped_frame.data.as_mut_byte_ptr(),
1175 layout,
1176 );
1177 }
1178 }
1179
1180 // Mark that we're no longer building the inner value
1181 *building_inner = false;
1182 crate::trace!("end(): set building_inner to false");
1183 // Mark the Result as initialized
1184 parent_frame.is_init = true;
1185 crate::trace!("end(): set parent_frame.is_init to true");
1186 } else {
1187 return Err(ReflectError::OperationFailed {
1188 shape: parent_frame.shape,
1189 operation: "Result frame without Result definition",
1190 });
1191 }
1192 } else {
1193 // building_inner is false - the Result was already initialized but
1194 // begin_ok/begin_err was called again. The popped frame was not used to
1195 // initialize the Result, so we need to clean it up.
1196 popped_frame.deinit();
1197 if let FrameOwnership::Owned = popped_frame.ownership
1198 && let Ok(layout) = popped_frame.shape.layout.sized_layout()
1199 && layout.size() > 0
1200 {
1201 unsafe {
1202 ::alloc::alloc::dealloc(popped_frame.data.as_mut_byte_ptr(), layout);
1203 }
1204 }
1205 }
1206 }
1207 Tracker::Scalar => {
1208 // the main case here is: the popped frame was a `String` and the
1209 // parent frame is an `Arc<str>`, `Box<str>` etc.
1210 match &parent_frame.shape.def {
1211 Def::Pointer(smart_ptr_def) => {
1212 let pointee =
1213 smart_ptr_def
1214 .pointee()
1215 .ok_or(ReflectError::InvariantViolation {
1216 invariant: "pointer type doesn't have a pointee",
1217 })?;
1218
1219 if !pointee.is_shape(str::SHAPE) {
1220 return Err(ReflectError::InvariantViolation {
1221 invariant: "only T=str is supported when building SmartPointer<T> and T is unsized",
1222 });
1223 }
1224
1225 if !popped_frame.shape.is_shape(String::SHAPE) {
1226 return Err(ReflectError::InvariantViolation {
1227 invariant: "the popped frame should be String when building a SmartPointer<T>",
1228 });
1229 }
1230
1231 popped_frame.require_full_initialization()?;
1232
1233 // if the just-popped frame was a SmartPointerStr, we have some conversion to do:
1234 // Special-case: SmartPointer<str> (Box<str>, Arc<str>, Rc<str>) via SmartPointerStr tracker
1235 // Here, popped_frame actually contains a value for String that should be moved into the smart pointer.
1236 // We convert the String into Box<str>, Arc<str>, or Rc<str> as appropriate and write it to the parent frame.
1237 use ::alloc::{rc::Rc, string::String, sync::Arc};
1238 let parent_shape = parent_frame.shape;
1239
1240 let Some(known) = smart_ptr_def.known else {
1241 return Err(ReflectError::OperationFailed {
1242 shape: parent_shape,
1243 operation: "SmartPointerStr for unknown smart pointer kind",
1244 });
1245 };
1246
1247 parent_frame.deinit();
1248
1249 // Interpret the memory as a String, then convert and write.
1250 let string_ptr = popped_frame.data.as_mut_byte_ptr() as *mut String;
1251 let string_value = unsafe { core::ptr::read(string_ptr) };
1252
1253 match known {
1254 KnownPointer::Box => {
1255 let boxed: Box<str> = string_value.into_boxed_str();
1256 unsafe {
1257 core::ptr::write(
1258 parent_frame.data.as_mut_byte_ptr() as *mut Box<str>,
1259 boxed,
1260 );
1261 }
1262 }
1263 KnownPointer::Arc => {
1264 let arc: Arc<str> = Arc::from(string_value.into_boxed_str());
1265 unsafe {
1266 core::ptr::write(
1267 parent_frame.data.as_mut_byte_ptr() as *mut Arc<str>,
1268 arc,
1269 );
1270 }
1271 }
1272 KnownPointer::Rc => {
1273 let rc: Rc<str> = Rc::from(string_value.into_boxed_str());
1274 unsafe {
1275 core::ptr::write(
1276 parent_frame.data.as_mut_byte_ptr() as *mut Rc<str>,
1277 rc,
1278 );
1279 }
1280 }
1281 _ => {
1282 return Err(ReflectError::OperationFailed {
1283 shape: parent_shape,
1284 operation: "Don't know how to build this pointer type",
1285 });
1286 }
1287 }
1288
1289 parent_frame.is_init = true;
1290
1291 popped_frame.tracker = Tracker::Scalar;
1292 popped_frame.is_init = false;
1293 popped_frame.dealloc();
1294 }
1295 _ => {
1296 // This can happen if begin_inner() was called on a type that
1297 // has shape.inner but isn't a SmartPointer (e.g., Option).
1298 // In this case, we can't complete the conversion, so return error.
1299 return Err(ReflectError::OperationFailed {
1300 shape: parent_frame.shape,
1301 operation: "end() called but parent has Uninit/Init tracker and isn't a SmartPointer",
1302 });
1303 }
1304 }
1305 }
1306 Tracker::SmartPointerSlice {
1307 vtable,
1308 building_item,
1309 } => {
1310 if *building_item {
1311 // We just popped an element frame, now push it to the slice builder
1312 let element_ptr = PtrMut::new(popped_frame.data.as_mut_byte_ptr());
1313
1314 // Use the slice builder's push_fn to add the element
1315 crate::trace!("Pushing element to slice builder");
1316 unsafe {
1317 let parent_ptr = parent_frame.data.assume_init();
1318 (vtable.push_fn)(parent_ptr, element_ptr);
1319 }
1320
1321 popped_frame.tracker = Tracker::Scalar;
1322 popped_frame.is_init = false;
1323 popped_frame.dealloc();
1324
1325 if let Tracker::SmartPointerSlice {
1326 building_item: bi, ..
1327 } = &mut parent_frame.tracker
1328 {
1329 *bi = false;
1330 }
1331 }
1332 }
1333 Tracker::DynamicValue {
1334 state: DynamicValueState::Array { building_element },
1335 } => {
1336 if *building_element {
1337 // Check that the element is initialized before pushing
1338 if !popped_frame.is_init {
1339 // Element was never set - clean up and return error
1340 let shape = parent_frame.shape;
1341 popped_frame.dealloc();
1342 *building_element = false;
1343 // No need to poison - returning Err consumes self, Drop will handle cleanup
1344 return Err(ReflectError::OperationFailed {
1345 shape,
1346 operation: "end() called but array element was never initialized",
1347 });
1348 }
1349
1350 // We just popped an element frame, now push it to the dynamic array
1351 if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
1352 // Get mutable pointers - both array and element need PtrMut
1353 let array_ptr = unsafe { parent_frame.data.assume_init() };
1354 let element_ptr = unsafe { popped_frame.data.assume_init() };
1355
1356 // Use push_array_element to add element to the array
1357 unsafe {
1358 (dyn_def.vtable.push_array_element)(array_ptr, element_ptr);
1359 }
1360
1361 // Push moved out of popped_frame
1362 popped_frame.tracker = Tracker::Scalar;
1363 popped_frame.is_init = false;
1364 popped_frame.dealloc();
1365
1366 *building_element = false;
1367 }
1368 }
1369 }
1370 Tracker::DynamicValue {
1371 state: DynamicValueState::Object { insert_state },
1372 } => {
1373 if let DynamicObjectInsertState::BuildingValue { key } = insert_state {
1374 // Check that the value is initialized before inserting
1375 if !popped_frame.is_init {
1376 // Value was never set - clean up and return error
1377 let shape = parent_frame.shape;
1378 popped_frame.dealloc();
1379 *insert_state = DynamicObjectInsertState::Idle;
1380 // No need to poison - returning Err consumes self, Drop will handle cleanup
1381 return Err(ReflectError::OperationFailed {
1382 shape,
1383 operation: "end() called but object entry value was never initialized",
1384 });
1385 }
1386
1387 // We just popped a value frame, now insert it into the dynamic object
1388 if let Def::DynamicValue(dyn_def) = parent_frame.shape.def {
1389 // Get mutable pointers - both object and value need PtrMut
1390 let object_ptr = unsafe { parent_frame.data.assume_init() };
1391 let value_ptr = unsafe { popped_frame.data.assume_init() };
1392
1393 // Use insert_object_entry to add the key-value pair
1394 unsafe {
1395 (dyn_def.vtable.insert_object_entry)(object_ptr, key, value_ptr);
1396 }
1397
1398 // Insert moved out of popped_frame
1399 popped_frame.tracker = Tracker::Scalar;
1400 popped_frame.is_init = false;
1401 popped_frame.dealloc();
1402
1403 // Reset insert state to Idle
1404 *insert_state = DynamicObjectInsertState::Idle;
1405 }
1406 }
1407 }
1408 _ => {}
1409 }
1410
1411 Ok(self)
1412 }
1413
1414 /// Returns a human-readable path representing the current traversal in the builder,
1415 /// e.g., `RootStruct.fieldName[index].subfield`.
1416 pub fn path(&self) -> String {
1417 let mut out = String::new();
1418
1419 let mut path_components = Vec::new();
1420 // The stack of enum/struct/sequence names currently in context.
1421 // Start from root and build upwards.
1422 for (i, frame) in self.frames().iter().enumerate() {
1423 match frame.shape.ty {
1424 Type::User(user_type) => match user_type {
1425 UserType::Struct(struct_type) => {
1426 // Try to get currently active field index
1427 let mut field_str = None;
1428 if let Tracker::Struct {
1429 current_child: Some(idx),
1430 ..
1431 } = &frame.tracker
1432 && let Some(field) = struct_type.fields.get(*idx)
1433 {
1434 field_str = Some(field.name);
1435 }
1436 if i == 0 {
1437 // Use Display for the root struct shape
1438 path_components.push(format!("{}", frame.shape));
1439 }
1440 if let Some(field_name) = field_str {
1441 path_components.push(format!(".{field_name}"));
1442 }
1443 }
1444 UserType::Enum(_enum_type) => {
1445 // Try to get currently active variant and field
1446 if let Tracker::Enum {
1447 variant,
1448 current_child,
1449 ..
1450 } = &frame.tracker
1451 {
1452 if i == 0 {
1453 // Use Display for the root enum shape
1454 path_components.push(format!("{}", frame.shape));
1455 }
1456 path_components.push(format!("::{}", variant.name));
1457 if let Some(idx) = *current_child
1458 && let Some(field) = variant.data.fields.get(idx)
1459 {
1460 path_components.push(format!(".{}", field.name));
1461 }
1462 } else if i == 0 {
1463 // just the enum display
1464 path_components.push(format!("{}", frame.shape));
1465 }
1466 }
1467 UserType::Union(_union_type) => {
1468 path_components.push(format!("{}", frame.shape));
1469 }
1470 UserType::Opaque => {
1471 path_components.push("<opaque>".to_string());
1472 }
1473 },
1474 Type::Sequence(seq_type) => match seq_type {
1475 facet_core::SequenceType::Array(_array_def) => {
1476 // Try to show current element index
1477 if let Tracker::Array {
1478 current_child: Some(idx),
1479 ..
1480 } = &frame.tracker
1481 {
1482 path_components.push(format!("[{idx}]"));
1483 }
1484 }
1485 // You can add more for Slice, Vec, etc., if applicable
1486 _ => {
1487 // just indicate "[]" for sequence
1488 path_components.push("[]".to_string());
1489 }
1490 },
1491 Type::Pointer(_) => {
1492 // Indicate deref
1493 path_components.push("*".to_string());
1494 }
1495 _ => {
1496 // No structural path
1497 }
1498 }
1499 }
1500 // Merge the path_components into a single string
1501 for component in path_components {
1502 out.push_str(&component);
1503 }
1504 out
1505 }
1506
1507 /// Get the field for the parent frame
1508 pub fn parent_field(&self) -> Option<&Field> {
1509 self.frames()
1510 .iter()
1511 .rev()
1512 .nth(1)
1513 .and_then(|f| f.get_field())
1514 }
1515
1516 /// Gets the field for the current frame
1517 pub fn current_field(&self) -> Option<&Field> {
1518 self.frames().last().and_then(|f| f.get_field())
1519 }
1520}