facet_reflect/partial/partial_api/
ptr.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Smart pointers
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<const BORROW: bool> Partial<'_, BORROW> {
7    /// Pushes a frame to initialize the inner value of a smart pointer (`Box<T>`, `Arc<T>`, etc.)
8    pub fn begin_smart_ptr(mut self) -> Result<Self, ReflectError> {
9        crate::trace!("begin_smart_ptr()");
10
11        // Check that we have a SmartPointer and get necessary data
12        let (smart_ptr_def, pointee_shape) = {
13            let frame = self.frames().last().unwrap();
14
15            match &frame.shape.def {
16                Def::Pointer(smart_ptr_def) if smart_ptr_def.constructible_from_pointee() => {
17                    let pointee_shape = match smart_ptr_def.pointee() {
18                        Some(shape) => shape,
19                        None => {
20                            return Err(ReflectError::OperationFailed {
21                                shape: frame.shape,
22                                operation: "Smart pointer must have a pointee shape",
23                            });
24                        }
25                    };
26                    (*smart_ptr_def, pointee_shape)
27                }
28                _ => {
29                    return Err(ReflectError::OperationFailed {
30                        shape: frame.shape,
31                        operation: "push_smart_ptr can only be called on compatible types",
32                    });
33                }
34            }
35        };
36
37        // Handle re-initialization if the smart pointer is already initialized
38        self.prepare_for_reinitialization();
39
40        let frame = self.frames_mut().last_mut().unwrap();
41
42        if pointee_shape.layout.sized_layout().is_ok() {
43            // pointee is sized, we can allocate it — for `Arc<T>` we'll be allocating a `T` and
44            // holding onto it. We'll build a new Arc with it when ending the smart pointer frame.
45
46            frame.tracker = Tracker::SmartPointer;
47
48            let inner_layout = match pointee_shape.layout.sized_layout() {
49                Ok(layout) => layout,
50                Err(_) => {
51                    return Err(ReflectError::Unsized {
52                        shape: pointee_shape,
53                        operation: "begin_smart_ptr, calculating inner value layout",
54                    });
55                }
56            };
57            let inner_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(inner_layout) };
58            let Some(inner_ptr) = NonNull::new(inner_ptr) else {
59                return Err(ReflectError::OperationFailed {
60                    shape: frame.shape,
61                    operation: "failed to allocate memory for smart pointer inner value",
62                });
63            };
64
65            // Push a new frame for the inner value
66            self.frames_mut().push(Frame::new(
67                PtrUninit::new(inner_ptr.as_ptr()),
68                pointee_shape,
69                FrameOwnership::Owned,
70            ));
71        } else {
72            // pointee is unsized, we only support a handful of cases there
73            if pointee_shape == str::SHAPE {
74                crate::trace!("Pointee is str");
75
76                // Allocate space for a String
77                let string_layout = String::SHAPE
78                    .layout
79                    .sized_layout()
80                    .expect("String must have a sized layout");
81                let string_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(string_layout) };
82                let Some(string_ptr) = NonNull::new(string_ptr) else {
83                    return Err(ReflectError::OperationFailed {
84                        shape: frame.shape,
85                        operation: "failed to allocate memory for string",
86                    });
87                };
88                let frame = Frame::new(
89                    PtrUninit::new(string_ptr.as_ptr()),
90                    String::SHAPE,
91                    FrameOwnership::Owned,
92                );
93                // Frame::new already sets tracker = Scalar and is_init = false
94                self.frames_mut().push(frame);
95            } else if let Type::Sequence(SequenceType::Slice(_st)) = pointee_shape.ty {
96                crate::trace!("Pointee is [{}]", _st.t);
97
98                // Get the slice builder vtable
99                let slice_builder_vtable = smart_ptr_def.vtable.slice_builder_vtable.ok_or(
100                    ReflectError::OperationFailed {
101                        shape: frame.shape,
102                        operation: "smart pointer does not support slice building",
103                    },
104                )?;
105
106                // Create a new builder
107                let builder_ptr = (slice_builder_vtable.new_fn)();
108
109                // Deallocate the original Arc allocation before replacing with slice builder
110                if let FrameOwnership::Owned = frame.ownership
111                    && let Ok(layout) = frame.shape.layout.sized_layout()
112                    && layout.size() > 0
113                {
114                    unsafe { ::alloc::alloc::dealloc(frame.data.as_mut_byte_ptr(), layout) };
115                }
116
117                // Update the current frame to use the slice builder
118                frame.data = builder_ptr.as_uninit();
119                frame.tracker = Tracker::SmartPointerSlice {
120                    vtable: slice_builder_vtable,
121                    building_item: false,
122                };
123                // Keep the original ownership (e.g., Field) so parent tracking works correctly.
124                // The slice builder memory itself is managed by the vtable's convert_fn/free_fn.
125            } else {
126                return Err(ReflectError::OperationFailed {
127                    shape: frame.shape,
128                    operation: "push_smart_ptr can only be called on pointers to supported pointee types",
129                });
130            }
131        }
132
133        Ok(self)
134    }
135}