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}