facet_reflect/partial/partial_api/build.rs
1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Build
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
7 /// Builds the value, consuming the Partial.
8 pub fn build(mut self) -> Result<HeapValue<'facet, BORROW>, ReflectError> {
9 if self.frames().len() != 1 {
10 return Err(ReflectError::InvariantViolation {
11 invariant: "Partial::build() expects a single frame — call end() until that's the case",
12 });
13 }
14
15 let frame = self.frames_mut().last_mut().unwrap();
16
17 // Fill in defaults for any unset fields before checking initialization
18 crate::trace!(
19 "build(): calling fill_defaults for {}, tracker={:?}, is_init={}",
20 frame.allocated.shape(),
21 frame.tracker.kind(),
22 frame.is_init
23 );
24 frame.fill_defaults()?;
25 crate::trace!(
26 "build(): after fill_defaults, tracker={:?}, is_init={}",
27 frame.tracker.kind(),
28 frame.is_init
29 );
30
31 let frame = self.frames_mut().pop().unwrap();
32
33 // Check initialization before proceeding
34 crate::trace!(
35 "build(): calling require_full_initialization, tracker={:?}",
36 frame.tracker.kind()
37 );
38 let init_result = frame.require_full_initialization();
39 crate::trace!(
40 "build(): require_full_initialization returned {:?}",
41 init_result.is_ok()
42 );
43 if let Err(e) = init_result {
44 // Put the frame back so Drop can handle cleanup properly
45 self.frames_mut().push(frame);
46 return Err(e);
47 }
48
49 // Check invariants if present
50 // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
51 let value_ptr = unsafe { frame.data.assume_init().as_const() };
52 if let Some(result) = unsafe { frame.allocated.shape().call_invariants(value_ptr) } {
53 match result {
54 Ok(()) => {
55 // Invariants passed
56 }
57 Err(message) => {
58 // Put the frame back so Drop can handle cleanup properly
59 let shape = frame.allocated.shape();
60 self.frames_mut().push(frame);
61 return Err(ReflectError::UserInvariantFailed { message, shape });
62 }
63 }
64 }
65
66 // Mark as built to prevent Drop from cleaning up the value
67 self.state = PartialState::Built;
68
69 match frame
70 .allocated
71 .shape()
72 .layout
73 .sized_layout()
74 .map_err(|_layout_err| ReflectError::Unsized {
75 shape: frame.allocated.shape(),
76 operation: "build (final check for sized layout)",
77 }) {
78 Ok(layout) => {
79 // Determine if we should deallocate based on ownership
80 let should_dealloc = frame.ownership.needs_dealloc();
81
82 Ok(HeapValue {
83 guard: Some(Guard {
84 ptr: unsafe { NonNull::new_unchecked(frame.data.as_mut_byte_ptr()) },
85 layout,
86 should_dealloc,
87 }),
88 shape: frame.allocated.shape(),
89 phantom: PhantomData,
90 })
91 }
92 Err(e) => {
93 // Put the frame back for proper cleanup
94 self.frames_mut().push(frame);
95 Err(e)
96 }
97 }
98 }
99
100 /// Finishes deserialization in-place, validating the value without moving it.
101 ///
102 /// This is intended for use with [`from_raw`](Self::from_raw) where the value
103 /// is deserialized into caller-provided memory (e.g., a `MaybeUninit<T>` on the stack).
104 ///
105 /// On success, the caller can safely assume the memory contains a fully initialized,
106 /// valid value and call `MaybeUninit::assume_init()`.
107 ///
108 /// On failure, any partially initialized data is cleaned up (dropped), and the
109 /// memory should be considered uninitialized.
110 ///
111 /// # Panics
112 ///
113 /// Panics if called with more than one frame on the stack (i.e., if you haven't
114 /// called `end()` enough times to return to the root level).
115 ///
116 /// # Example
117 ///
118 /// ```ignore
119 /// use std::mem::MaybeUninit;
120 /// use facet_core::{Facet, PtrUninit};
121 /// use facet_reflect::Partial;
122 ///
123 /// let mut slot = MaybeUninit::<MyStruct>::uninit();
124 /// let ptr = PtrUninit::new(slot.as_mut_ptr().cast());
125 ///
126 /// let partial = unsafe { Partial::from_raw(ptr, MyStruct::SHAPE)? };
127 /// // ... deserialize into partial ...
128 /// partial.finish_in_place()?;
129 ///
130 /// // Now safe to assume initialized
131 /// let value = unsafe { slot.assume_init() };
132 /// ```
133 pub fn finish_in_place(mut self) -> Result<(), ReflectError> {
134 if self.frames().len() != 1 {
135 return Err(ReflectError::InvariantViolation {
136 invariant: "Partial::finish_in_place() expects a single frame — call end() until that's the case",
137 });
138 }
139
140 let frame = self.frames_mut().last_mut().unwrap();
141
142 // Fill in defaults for any unset fields before checking initialization
143 crate::trace!(
144 "finish_in_place(): calling fill_defaults for {}, tracker={:?}, is_init={}",
145 frame.allocated.shape(),
146 frame.tracker.kind(),
147 frame.is_init
148 );
149 frame.fill_defaults()?;
150 crate::trace!(
151 "finish_in_place(): after fill_defaults, tracker={:?}, is_init={}",
152 frame.tracker.kind(),
153 frame.is_init
154 );
155
156 let frame = self.frames_mut().pop().unwrap();
157
158 // Check initialization before proceeding
159 crate::trace!(
160 "finish_in_place(): calling require_full_initialization, tracker={:?}",
161 frame.tracker.kind()
162 );
163 let init_result = frame.require_full_initialization();
164 crate::trace!(
165 "finish_in_place(): require_full_initialization returned {:?}",
166 init_result.is_ok()
167 );
168 if let Err(e) = init_result {
169 // Put the frame back so Drop can handle cleanup properly
170 self.frames_mut().push(frame);
171 return Err(e);
172 }
173
174 // Check invariants if present
175 // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
176 let value_ptr = unsafe { frame.data.assume_init().as_const() };
177 if let Some(result) = unsafe { frame.allocated.shape().call_invariants(value_ptr) } {
178 match result {
179 Ok(()) => {
180 // Invariants passed
181 }
182 Err(message) => {
183 // Put the frame back so Drop can handle cleanup properly
184 let shape = frame.allocated.shape();
185 self.frames_mut().push(frame);
186 return Err(ReflectError::UserInvariantFailed { message, shape });
187 }
188 }
189 }
190
191 // Mark as built to prevent Drop from cleaning up the now-valid value.
192 // The caller owns the memory and will handle the value from here.
193 self.state = PartialState::Built;
194
195 // Frame is dropped here without deallocation (External ownership doesn't dealloc)
196 Ok(())
197 }
198}