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().pop().unwrap();
16
17        // Check initialization before proceeding
18        if let Err(e) = frame.require_full_initialization() {
19            // Put the frame back so Drop can handle cleanup properly
20            self.frames_mut().push(frame);
21            return Err(e);
22        }
23
24        // Check invariants if present
25        // Safety: The value is fully initialized at this point (we just checked with require_full_initialization)
26        let value_ptr = unsafe { frame.data.assume_init().as_const() };
27        if let Some(result) = unsafe { frame.shape.call_invariants(value_ptr) } {
28            match result {
29                Ok(()) => {
30                    // Invariants passed
31                }
32                Err(msg) => {
33                    // Put the frame back so Drop can handle cleanup properly
34                    self.frames_mut().push(frame);
35                    // Leak the string to get a 'static lifetime for the error
36                    let static_msg: &'static str = Box::leak(msg.into_boxed_str());
37                    return Err(ReflectError::InvariantViolation {
38                        invariant: static_msg,
39                    });
40                }
41            }
42        }
43
44        // Mark as built to prevent Drop from cleaning up the value
45        self.state = PartialState::Built;
46
47        match frame
48            .shape
49            .layout
50            .sized_layout()
51            .map_err(|_layout_err| ReflectError::Unsized {
52                shape: frame.shape,
53                operation: "build (final check for sized layout)",
54            }) {
55            Ok(layout) => {
56                // Determine if we should deallocate based on ownership
57                let should_dealloc = !matches!(frame.ownership, FrameOwnership::ManagedElsewhere);
58
59                Ok(HeapValue {
60                    guard: Some(Guard {
61                        ptr: unsafe { NonNull::new_unchecked(frame.data.as_mut_byte_ptr()) },
62                        layout,
63                        should_dealloc,
64                    }),
65                    shape: frame.shape,
66                    phantom: PhantomData,
67                })
68            }
69            Err(e) => {
70                // Put the frame back for proper cleanup
71                self.frames_mut().push(frame);
72                Err(e)
73            }
74        }
75    }
76}