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