facet_reflect/partial/partial_api/
maps.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Maps
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<const BORROW: bool> Partial<'_, BORROW> {
7    /// Begins a map initialization operation
8    ///
9    /// This initializes the map with default capacity and allows inserting key-value pairs
10    /// It does _not_ push a new frame onto the stack.
11    ///
12    /// For `Def::DynamicValue` types, this initializes as an object instead of a map.
13    pub fn begin_map(mut self) -> Result<Self, ReflectError> {
14        let frame = self.frames_mut().last_mut().unwrap();
15
16        // Check tracker state before initializing
17        match &frame.tracker {
18            Tracker::Scalar if !frame.is_init => {
19                // Good, will initialize below
20            }
21            Tracker::Scalar => {
22                // is_init is true - already initialized (from a previous round)
23                match frame.shape.def {
24                    Def::Map(_) => {
25                        // For Map, just update tracker - the map is already initialized
26                        frame.tracker = Tracker::Map {
27                            insert_state: MapInsertState::Idle,
28                        };
29                        return Ok(self);
30                    }
31                    Def::DynamicValue(_) => {
32                        // For DynamicValue, we need to reinitialize as an object.
33                        // The current value might be a different type (number, string, etc.),
34                        // so we must drop the old value before reinitializing.
35                        // For ManagedElsewhere frames, deinit() skips dropping, so drop explicitly.
36                        if matches!(frame.ownership, FrameOwnership::ManagedElsewhere) {
37                            unsafe { frame.shape.call_drop_in_place(frame.data.assume_init()) };
38                        }
39                        frame.deinit();
40                        // Fall through to initialization below
41                    }
42                    _ => {
43                        return Err(ReflectError::OperationFailed {
44                            shape: frame.shape,
45                            operation: "begin_map can only be called on Map or DynamicValue types",
46                        });
47                    }
48                }
49            }
50            Tracker::Map { .. } => {
51                if frame.is_init {
52                    // Already initialized, nothing to do
53                    return Ok(self);
54                }
55            }
56            Tracker::DynamicValue { state } => {
57                // Already initialized as a dynamic object
58                if matches!(state, DynamicValueState::Object { .. }) {
59                    return Ok(self);
60                }
61                // Otherwise (Scalar or Array state), we need to deinit before reinitializing.
62                // For ManagedElsewhere frames, deinit() skips dropping, so drop explicitly.
63                if matches!(frame.ownership, FrameOwnership::ManagedElsewhere) && frame.is_init {
64                    unsafe { frame.shape.call_drop_in_place(frame.data.assume_init()) };
65                }
66                frame.deinit();
67            }
68            _ => {
69                return Err(ReflectError::UnexpectedTracker {
70                    message: "begin_map called but tracker isn't Scalar, Map, or DynamicValue",
71                    current_tracker: frame.tracker.kind(),
72                });
73            }
74        }
75
76        // Check that we have a Map or DynamicValue
77        match &frame.shape.def {
78            Def::Map(map_def) => {
79                let init_fn = map_def.vtable.init_in_place_with_capacity;
80
81                // Initialize the map with default capacity (0)
82                unsafe {
83                    init_fn(frame.data, 0);
84                }
85
86                // Update tracker to Map state and mark as initialized
87                frame.tracker = Tracker::Map {
88                    insert_state: MapInsertState::Idle,
89                };
90                frame.is_init = true;
91            }
92            Def::DynamicValue(dyn_def) => {
93                // Initialize as a dynamic object
94                unsafe {
95                    (dyn_def.vtable.begin_object)(frame.data);
96                }
97
98                // Update tracker to DynamicValue object state and mark as initialized
99                frame.tracker = Tracker::DynamicValue {
100                    state: DynamicValueState::Object {
101                        insert_state: DynamicObjectInsertState::Idle,
102                    },
103                };
104                frame.is_init = true;
105            }
106            _ => {
107                return Err(ReflectError::OperationFailed {
108                    shape: frame.shape,
109                    operation: "begin_map can only be called on Map or DynamicValue types",
110                });
111            }
112        }
113
114        Ok(self)
115    }
116
117    /// Pushes a frame for the map key. After that, `set()` should be called
118    /// (or the key should be initialized somehow) and `end()` should be called
119    /// to pop the frame.
120    pub fn begin_key(mut self) -> Result<Self, ReflectError> {
121        let frame = self.frames_mut().last_mut().unwrap();
122
123        // Check that we have a Map in Idle state
124        let map_def = match (&frame.shape.def, &frame.tracker) {
125            (
126                Def::Map(map_def),
127                Tracker::Map {
128                    insert_state: MapInsertState::Idle,
129                },
130            ) if frame.is_init => map_def,
131            (
132                Def::Map(_),
133                Tracker::Map {
134                    insert_state: MapInsertState::PushingKey { .. },
135                },
136            ) => {
137                return Err(ReflectError::OperationFailed {
138                    shape: frame.shape,
139                    operation: "already pushing a key, call end() first",
140                });
141            }
142            (
143                Def::Map(_),
144                Tracker::Map {
145                    insert_state: MapInsertState::PushingValue { .. },
146                },
147            ) => {
148                return Err(ReflectError::OperationFailed {
149                    shape: frame.shape,
150                    operation: "must complete current operation before begin_key()",
151                });
152            }
153            _ => {
154                return Err(ReflectError::OperationFailed {
155                    shape: frame.shape,
156                    operation: "must call begin_map() before begin_key()",
157                });
158            }
159        };
160
161        // Get the key shape
162        let key_shape = map_def.k();
163
164        // Allocate space for the key
165        let key_layout = match key_shape.layout.sized_layout() {
166            Ok(layout) => layout,
167            Err(_) => {
168                return Err(ReflectError::Unsized {
169                    shape: key_shape,
170                    operation: "begin_key allocating key",
171                });
172            }
173        };
174        let key_ptr_raw: *mut u8 = unsafe { ::alloc::alloc::alloc(key_layout) };
175
176        let Some(key_ptr_raw) = NonNull::new(key_ptr_raw) else {
177            return Err(ReflectError::OperationFailed {
178                shape: frame.shape,
179                operation: "failed to allocate memory for map key",
180            });
181        };
182
183        let key_ptr = PtrUninit::new(key_ptr_raw.as_ptr());
184
185        // Store the key pointer in the insert state
186        match &mut frame.tracker {
187            Tracker::Map { insert_state, .. } => {
188                *insert_state = MapInsertState::PushingKey {
189                    key_ptr,
190                    key_initialized: false,
191                };
192            }
193            _ => unreachable!(),
194        }
195
196        // Push a new frame for the key
197        self.frames_mut().push(Frame::new(
198            PtrUninit::new(key_ptr_raw.as_ptr()),
199            key_shape,
200            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
201        ));
202
203        Ok(self)
204    }
205
206    /// Pushes a frame for the map value
207    /// Must be called after the key has been set and popped
208    pub fn begin_value(mut self) -> Result<Self, ReflectError> {
209        let frame = self.frames_mut().last_mut().unwrap();
210
211        // Check that we have a Map in PushingValue state with no value_ptr yet
212        let (map_def, key_ptr) = match (&frame.shape.def, &frame.tracker) {
213            (
214                Def::Map(map_def),
215                Tracker::Map {
216                    insert_state:
217                        MapInsertState::PushingValue {
218                            value_ptr: None,
219                            key_ptr,
220                            ..
221                        },
222                    ..
223                },
224            ) => (map_def, *key_ptr),
225            (
226                Def::Map(_),
227                Tracker::Map {
228                    insert_state:
229                        MapInsertState::PushingValue {
230                            value_ptr: Some(_), ..
231                        },
232                    ..
233                },
234            ) => {
235                return Err(ReflectError::OperationFailed {
236                    shape: frame.shape,
237                    operation: "already pushing a value, call end() first",
238                });
239            }
240            _ => {
241                return Err(ReflectError::OperationFailed {
242                    shape: frame.shape,
243                    operation: "must complete key before begin_value()",
244                });
245            }
246        };
247
248        // Get the value shape
249        let value_shape = map_def.v();
250
251        // Allocate space for the value
252        let value_layout = match value_shape.layout.sized_layout() {
253            Ok(layout) => layout,
254            Err(_) => {
255                return Err(ReflectError::Unsized {
256                    shape: value_shape,
257                    operation: "begin_value allocating value",
258                });
259            }
260        };
261        let value_ptr_raw: *mut u8 = unsafe { ::alloc::alloc::alloc(value_layout) };
262
263        let Some(value_ptr_raw) = NonNull::new(value_ptr_raw) else {
264            return Err(ReflectError::OperationFailed {
265                shape: frame.shape,
266                operation: "failed to allocate memory for map value",
267            });
268        };
269
270        let value_ptr = PtrUninit::new(value_ptr_raw.as_ptr());
271
272        // Store the value pointer in the insert state
273        match &mut frame.tracker {
274            Tracker::Map { insert_state, .. } => {
275                *insert_state = MapInsertState::PushingValue {
276                    key_ptr,
277                    value_ptr: Some(value_ptr),
278                    value_initialized: false,
279                };
280            }
281            _ => unreachable!(),
282        }
283
284        // Push a new frame for the value
285        self.frames_mut().push(Frame::new(
286            value_ptr,
287            value_shape,
288            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
289        ));
290
291        Ok(self)
292    }
293
294    /// Begins an object entry for a DynamicValue object.
295    ///
296    /// This is a simpler API than begin_key/begin_value for DynamicValue objects,
297    /// where keys are always strings. The key is stored and a frame is pushed for
298    /// the value. After setting the value and calling `end()`, the key-value pair
299    /// will be inserted into the object.
300    ///
301    /// For `Def::Map` types, use `begin_key()` / `begin_value()` instead.
302    pub fn begin_object_entry(mut self, key: &str) -> Result<Self, ReflectError> {
303        crate::trace!("begin_object_entry({key:?})");
304        let frame = self.frames_mut().last_mut().unwrap();
305
306        // Check that we have a DynamicValue in Object state with Idle insert_state
307        let dyn_def = match (&frame.shape.def, &frame.tracker) {
308            (
309                Def::DynamicValue(dyn_def),
310                Tracker::DynamicValue {
311                    state:
312                        DynamicValueState::Object {
313                            insert_state: DynamicObjectInsertState::Idle,
314                        },
315                },
316            ) if frame.is_init => {
317                // Good, proceed
318                dyn_def
319            }
320            (
321                Def::DynamicValue(_),
322                Tracker::DynamicValue {
323                    state:
324                        DynamicValueState::Object {
325                            insert_state: DynamicObjectInsertState::BuildingValue { .. },
326                        },
327                },
328            ) => {
329                return Err(ReflectError::OperationFailed {
330                    shape: frame.shape,
331                    operation: "already building a value, call end() first",
332                });
333            }
334            (Def::DynamicValue(_), _) => {
335                return Err(ReflectError::OperationFailed {
336                    shape: frame.shape,
337                    operation: "must call begin_map() before begin_object_entry()",
338                });
339            }
340            _ => {
341                return Err(ReflectError::OperationFailed {
342                    shape: frame.shape,
343                    operation: "begin_object_entry can only be called on DynamicValue types",
344                });
345            }
346        };
347
348        // For DynamicValue objects, the value shape is the same DynamicValue shape
349        let value_shape = frame.shape;
350
351        // Check if key already exists using object_get_mut (for "get or create" semantics)
352        // This is needed for formats like TOML with implicit tables: [a] followed by [a.b.c]
353        if let Some(get_mut_fn) = dyn_def.vtable.object_get_mut {
354            let object_ptr = unsafe { frame.data.assume_init() };
355            if let Some(existing_ptr) = unsafe { get_mut_fn(object_ptr, key) } {
356                // Key exists - push a frame pointing to existing value
357                // Leave insert_state as Idle (no insertion needed on end())
358                // Use ManagedElsewhere since parent object owns this value
359                let mut new_frame = Frame::new(
360                    existing_ptr.as_uninit(),
361                    value_shape,
362                    FrameOwnership::ManagedElsewhere,
363                );
364                new_frame.is_init = true;
365                // Set tracker to reflect it's an initialized DynamicValue
366                // For DynamicValue, we need to peek at the value to determine the state.
367                // However, we don't know yet what operations will be called (begin_map, begin_list, etc.)
368                // So we set Scalar tracker and let begin_map/begin_list handle the conversion.
369                // begin_list will convert Scalar->List if shape is Def::List, or handle DynamicValue directly.
370                new_frame.tracker = Tracker::Scalar;
371                self.frames_mut().push(new_frame);
372                return Ok(self);
373            }
374        }
375
376        // Key doesn't exist - allocate new value
377        let value_layout = match value_shape.layout.sized_layout() {
378            Ok(layout) => layout,
379            Err(_) => {
380                return Err(ReflectError::Unsized {
381                    shape: value_shape,
382                    operation: "begin_object_entry: calculating value layout",
383                });
384            }
385        };
386
387        let value_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(value_layout) };
388        let Some(value_ptr) = NonNull::new(value_ptr) else {
389            return Err(ReflectError::OperationFailed {
390                shape: frame.shape,
391                operation: "failed to allocate memory for object value",
392            });
393        };
394
395        // Update the insert state with the key
396        match &mut frame.tracker {
397            Tracker::DynamicValue {
398                state: DynamicValueState::Object { insert_state },
399            } => {
400                *insert_state = DynamicObjectInsertState::BuildingValue {
401                    key: String::from(key),
402                };
403            }
404            _ => unreachable!(),
405        }
406
407        // Push a new frame for the value
408        self.frames_mut().push(Frame::new(
409            PtrUninit::new(value_ptr.as_ptr()),
410            value_shape,
411            FrameOwnership::Owned,
412        ));
413
414        Ok(self)
415    }
416}