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        let (inner_shape, has_try_from, parent_shape, is_option) = {
116            let frame = self.frames().last().unwrap();
117            if let Some(inner_shape) = frame.shape.inner {
118                let has_try_from = frame.shape.vtable.has_try_from();
119                let is_option = matches!(frame.shape.def, Def::Option(_));
120                (Some(inner_shape), has_try_from, frame.shape, is_option)
121            } else {
122                (None, false, frame.shape, false)
123            }
124        };
125
126        // Handle re-initialization if needed
127        self.prepare_for_reinitialization();
128
129        if let Some(inner_shape) = inner_shape {
130            if has_try_from {
131                // For Option types, use begin_some behavior to properly track building_inner
132                // This ensures end() knows how to handle the popped frame
133                if is_option {
134                    return self.begin_some();
135                }
136
137                // Create a conversion frame with the inner shape
138                // For non-Option types with try_from, we leave the parent tracker unchanged
139                // and the conversion will happen in end()
140
141                // Allocate memory for the inner value (conversion source)
142                let inner_layout =
143                    inner_shape
144                        .layout
145                        .sized_layout()
146                        .map_err(|_| ReflectError::Unsized {
147                            shape: inner_shape,
148                            operation: "begin_inner, getting inner layout",
149                        })?;
150
151                let inner_data = if inner_layout.size() == 0 {
152                    // For ZST, use a non-null but unallocated pointer
153                    PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
154                } else {
155                    // Allocate memory for the inner value
156                    let ptr = unsafe { ::alloc::alloc::alloc(inner_layout) };
157                    let Some(ptr) = NonNull::new(ptr) else {
158                        ::alloc::alloc::handle_alloc_error(inner_layout);
159                    };
160                    PtrUninit::new(ptr.as_ptr())
161                };
162
163                // For conversion frames, we create a frame directly with the inner shape
164                // This allows setting values of the inner type which will be converted
165                // The automatic conversion detection in end() will handle the conversion
166                trace!(
167                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
168                );
169                self.frames_mut()
170                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
171
172                Ok(self)
173            } else {
174                // For wrapper types without try_from, navigate to the first field
175                // This is a common pattern for newtype wrappers
176                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
177                self.begin_nth_field(0)
178            }
179        } else {
180            Err(ReflectError::OperationFailed {
181                shape: parent_shape,
182                operation: "type does not have an inner value",
183            })
184        }
185    }
186
187    /// Begin bulding the source shape for custom deserialization, calling end() for this frame will
188    /// call the deserialize_with function provided by the field and set the field using the result.
189    pub fn begin_custom_deserialization(mut self) -> Result<Self, ReflectError> {
190        let current_frame = self.frames().last().unwrap();
191        let target_shape = current_frame.shape;
192        trace!("begin_custom_deserialization: target_shape={target_shape}");
193        if let Some(field) = self.parent_field() {
194            trace!("begin_custom_deserialization: field name={}", field.name);
195            if let Some(proxy_def) = field.proxy() {
196                // Get the source shape from the proxy definition
197                let source_shape = proxy_def.shape;
198                let source_data = source_shape.allocate().map_err(|_| ReflectError::Unsized {
199                    shape: target_shape,
200                    operation: "Not a Sized type",
201                })?;
202
203                trace!(
204                    "begin_custom_deserialization: Creating frame for deserialization type {source_shape}"
205                );
206                let mut new_frame = Frame::new(source_data, source_shape, FrameOwnership::Owned);
207                new_frame.using_custom_deserialization = true;
208                self.frames_mut().push(new_frame);
209
210                Ok(self)
211            } else {
212                Err(ReflectError::OperationFailed {
213                    shape: target_shape,
214                    operation: "field does not have a proxy definition",
215                })
216            }
217        } else {
218            Err(ReflectError::OperationFailed {
219                shape: target_shape,
220                operation: "not currently processing a field",
221            })
222        }
223    }
224
225    /// Begin building the source shape for custom deserialization using container-level proxy.
226    ///
227    /// Unlike `begin_custom_deserialization` which uses field-level proxy info, this method
228    /// uses the shape's own proxy definition (from `#[facet(proxy = ...)]` at container level).
229    ///
230    /// Returns `Ok((self, true))` if the shape has a container-level proxy and we've begun
231    /// custom deserialization, `Ok((self, false))` if not (self is returned unchanged).
232    pub fn begin_custom_deserialization_from_shape(mut self) -> Result<(Self, bool), ReflectError> {
233        let current_frame = self.frames().last().unwrap();
234        let target_shape = current_frame.shape;
235        trace!("begin_custom_deserialization_from_shape: target_shape={target_shape}");
236
237        let Some(proxy_def) = target_shape.proxy else {
238            return Ok((self, false));
239        };
240
241        let source_shape = proxy_def.shape;
242        let source_data = source_shape.allocate().map_err(|_| ReflectError::Unsized {
243            shape: target_shape,
244            operation: "Not a Sized type",
245        })?;
246
247        trace!(
248            "begin_custom_deserialization_from_shape: Creating frame for deserialization type {source_shape}"
249        );
250        let mut new_frame = Frame::new(source_data, source_shape, FrameOwnership::Owned);
251        new_frame.using_custom_deserialization = true;
252        // Store the target shape's proxy in the frame so end() can use it for conversion
253        new_frame.shape_level_proxy = Some(proxy_def);
254        self.frames_mut().push(new_frame);
255
256        Ok((self, true))
257    }
258}