facet_reflect/partial/partial_api/
option.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Option / inner
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<const BORROW: bool> Partial<'_, BORROW> {
7    /// Begin building the Some variant of an Option
8    pub fn begin_some(mut self) -> Result<Self, ReflectError> {
9        // Verify we're working with an Option and get the def
10        let option_def = {
11            let frame = self.frames().last().unwrap();
12            match frame.shape.def {
13                Def::Option(def) => def,
14                _ => {
15                    return Err(ReflectError::WasNotA {
16                        expected: "Option",
17                        actual: frame.shape,
18                    });
19                }
20            }
21        };
22
23        // Check if we need to handle re-initialization.
24        // For Options, also check if tracker is Option{building_inner:false} which means
25        // a previous begin_some/end cycle completed.
26        let needs_reinit = {
27            let frame = self.frames().last().unwrap();
28            frame.is_init
29                || matches!(
30                    frame.tracker,
31                    Tracker::Option {
32                        building_inner: false
33                    }
34                )
35        };
36
37        if needs_reinit {
38            self.prepare_for_reinitialization();
39        }
40
41        // In deferred mode, push "Some" onto the path to distinguish
42        // Option<T> (path ends before "Some") from the inner T (path includes "Some").
43        // This treats Option like an enum with Some/None variants for path tracking.
44        if let FrameMode::Deferred {
45            stack,
46            start_depth,
47            current_path,
48            stored_frames,
49            ..
50        } = &mut self.mode
51        {
52            let relative_depth = stack.len() - *start_depth;
53            let should_track = current_path.len() == relative_depth;
54
55            if should_track {
56                current_path.push("Some");
57
58                // Check if we have a stored frame for this path (re-entry case)
59                if let Some(stored_frame) = stored_frames.remove(current_path) {
60                    trace!("begin_some: Restoring stored frame for path {current_path:?}");
61
62                    // Update tracker to indicate we're building the inner value
63                    let frame = stack.last_mut().unwrap();
64                    frame.tracker = Tracker::Option {
65                        building_inner: true,
66                    };
67
68                    stack.push(stored_frame);
69                    return Ok(self);
70                }
71            }
72        }
73
74        // Set tracker to indicate we're building the inner value
75        let frame = self.frames_mut().last_mut().unwrap();
76        frame.tracker = Tracker::Option {
77            building_inner: true,
78        };
79
80        // Get the inner type shape
81        let inner_shape = option_def.t;
82
83        // Allocate memory for the inner value
84        let inner_layout =
85            inner_shape
86                .layout
87                .sized_layout()
88                .map_err(|_| ReflectError::Unsized {
89                    shape: inner_shape,
90                    operation: "begin_some, allocating Option inner value",
91                })?;
92
93        let inner_data = if inner_layout.size() == 0 {
94            // For ZST, use a non-null but unallocated pointer
95            PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
96        } else {
97            // Allocate memory for the inner value
98            let ptr = unsafe { ::alloc::alloc::alloc(inner_layout) };
99            let Some(ptr) = NonNull::new(ptr) else {
100                ::alloc::alloc::handle_alloc_error(inner_layout);
101            };
102            PtrUninit::new(ptr.as_ptr())
103        };
104
105        // Create a new frame for the inner value
106        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
107        self.frames_mut().push(inner_frame);
108
109        Ok(self)
110    }
111
112    /// Begin building the inner value of a wrapper type
113    pub fn begin_inner(mut self) -> Result<Self, ReflectError> {
114        // Get the inner shape and check for try_from
115        // Priority: builder_shape (for immutable collections) > inner (for variance/transparent wrappers)
116        let (inner_shape, has_try_from, parent_shape, is_option) = {
117            let frame = self.frames().last().unwrap();
118            // Check builder_shape first (immutable collections like Bytes, Arc<[T]>)
119            if let Some(builder_shape) = frame.shape.builder_shape {
120                let has_try_from = frame.shape.vtable.has_try_from();
121                let is_option = matches!(frame.shape.def, Def::Option(_));
122                (Some(builder_shape), has_try_from, frame.shape, is_option)
123            } else if let Some(inner_shape) = frame.shape.inner {
124                let has_try_from = frame.shape.vtable.has_try_from();
125                let is_option = matches!(frame.shape.def, Def::Option(_));
126                (Some(inner_shape), has_try_from, frame.shape, is_option)
127            } else {
128                (None, false, frame.shape, false)
129            }
130        };
131
132        // Handle re-initialization if needed
133        self.prepare_for_reinitialization();
134
135        if let Some(inner_shape) = inner_shape {
136            if has_try_from {
137                // For Option types, use begin_some behavior to properly track building_inner
138                // This ensures end() knows how to handle the popped frame
139                if is_option {
140                    return self.begin_some();
141                }
142
143                // Create a conversion frame with the inner shape
144                // For non-Option types with try_from, we leave the parent tracker unchanged
145                // and the conversion will happen in end()
146
147                // Allocate memory for the inner value (conversion source)
148                let inner_layout =
149                    inner_shape
150                        .layout
151                        .sized_layout()
152                        .map_err(|_| ReflectError::Unsized {
153                            shape: inner_shape,
154                            operation: "begin_inner, getting inner layout",
155                        })?;
156
157                let inner_data = if inner_layout.size() == 0 {
158                    // For ZST, use a non-null but unallocated pointer
159                    PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
160                } else {
161                    // Allocate memory for the inner value
162                    let ptr = unsafe { ::alloc::alloc::alloc(inner_layout) };
163                    let Some(ptr) = NonNull::new(ptr) else {
164                        ::alloc::alloc::handle_alloc_error(inner_layout);
165                    };
166                    PtrUninit::new(ptr.as_ptr())
167                };
168
169                // For conversion frames, we create a frame directly with the inner shape
170                // This allows setting values of the inner type which will be converted
171                // The automatic conversion detection in end() will handle the conversion
172                trace!(
173                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
174                );
175                self.frames_mut()
176                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
177
178                Ok(self)
179            } else {
180                // For wrapper types without try_from, navigate to the first field
181                // This is a common pattern for newtype wrappers
182                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
183                self.begin_nth_field(0)
184            }
185        } else {
186            Err(ReflectError::OperationFailed {
187                shape: parent_shape,
188                operation: "type does not have an inner value",
189            })
190        }
191    }
192
193    /// Begin bulding the source shape for custom deserialization, calling end() for this frame will
194    /// call the deserialize_with function provided by the field and set the field using the result.
195    pub fn begin_custom_deserialization(mut self) -> Result<Self, ReflectError> {
196        let current_frame = self.frames().last().unwrap();
197        let target_shape = current_frame.shape;
198        trace!("begin_custom_deserialization: target_shape={target_shape}");
199        if let Some(field) = self.parent_field() {
200            trace!("begin_custom_deserialization: field name={}", field.name);
201            if let Some(proxy_def) = field.proxy() {
202                // Get the source shape from the proxy definition
203                let source_shape = proxy_def.shape;
204                let source_data = source_shape.allocate().map_err(|_| ReflectError::Unsized {
205                    shape: target_shape,
206                    operation: "Not a Sized type",
207                })?;
208
209                trace!(
210                    "begin_custom_deserialization: Creating frame for deserialization type {source_shape}"
211                );
212                let mut new_frame = Frame::new(source_data, source_shape, FrameOwnership::Owned);
213                new_frame.using_custom_deserialization = true;
214                self.frames_mut().push(new_frame);
215
216                Ok(self)
217            } else {
218                Err(ReflectError::OperationFailed {
219                    shape: target_shape,
220                    operation: "field does not have a proxy definition",
221                })
222            }
223        } else {
224            Err(ReflectError::OperationFailed {
225                shape: target_shape,
226                operation: "not currently processing a field",
227            })
228        }
229    }
230
231    /// Begin building the source shape for custom deserialization using container-level proxy.
232    ///
233    /// Unlike `begin_custom_deserialization` which uses field-level proxy info, this method
234    /// uses the shape's own proxy definition (from `#[facet(proxy = ...)]` at container level).
235    ///
236    /// Returns `Ok((self, true))` if the shape has a container-level proxy and we've begun
237    /// custom deserialization, `Ok((self, false))` if not (self is returned unchanged).
238    pub fn begin_custom_deserialization_from_shape(mut self) -> Result<(Self, bool), ReflectError> {
239        let current_frame = self.frames().last().unwrap();
240        let target_shape = current_frame.shape;
241        trace!("begin_custom_deserialization_from_shape: target_shape={target_shape}");
242
243        let Some(proxy_def) = target_shape.proxy else {
244            return Ok((self, false));
245        };
246
247        let source_shape = proxy_def.shape;
248        let source_data = source_shape.allocate().map_err(|_| ReflectError::Unsized {
249            shape: target_shape,
250            operation: "Not a Sized type",
251        })?;
252
253        trace!(
254            "begin_custom_deserialization_from_shape: Creating frame for deserialization type {source_shape}"
255        );
256        let mut new_frame = Frame::new(source_data, source_shape, FrameOwnership::Owned);
257        new_frame.using_custom_deserialization = true;
258        // Store the target shape's proxy in the frame so end() can use it for conversion
259        new_frame.shape_level_proxy = Some(proxy_def);
260        self.frames_mut().push(new_frame);
261
262        Ok((self, true))
263    }
264}