facet_reflect/wip/pop.rs
1use crate::trace;
2use facet_core::{
3 Def, EnumType, PtrConst, PtrMut, PtrUninit, Repr, ScalarAffinity, SequenceType, StructType,
4 Type, UserType, Variant,
5};
6#[allow(unused_imports)]
7use owo_colors::OwoColorize;
8
9use crate::{FrameMode, ReflectError};
10
11use super::{Frame, Wip};
12
13impl Wip<'_> {
14 /// Pops the current frame — goes back up one level
15 pub fn pop(mut self) -> Result<Self, ReflectError> {
16 let frame = match self.pop_inner()? {
17 Some(frame) => frame,
18 None => {
19 return Err(ReflectError::InvariantViolation {
20 invariant: "No frame to pop — it was time to call build()",
21 });
22 }
23 };
24
25 self.track(frame);
26 Ok(self)
27 }
28
29 fn pop_inner(&mut self) -> Result<Option<Frame>, ReflectError> {
30 let mut frame = match self.frames.pop() {
31 Some(f) => f,
32 None => return Ok(None),
33 };
34 #[cfg(feature = "log")]
35 let frame_shape = frame.shape;
36
37 let init = frame.is_fully_initialized();
38 trace!(
39 "[{}] {} popped, {} initialized",
40 self.frames.len(),
41 frame_shape.blue(),
42 if init {
43 "✅ fully".style(owo_colors::Style::new().green())
44 } else {
45 "🚧 partially".style(owo_colors::Style::new().red())
46 }
47 );
48 if init {
49 // If this frame is fully initialized, mark it as such in all tracking states
50
51 // 1. Mark this frame as fully initialized (if it isn't already)
52 unsafe {
53 frame.mark_fully_initialized();
54 }
55
56 // 2. Mark the parent's field as initialized (if this is a field)
57 #[cfg(feature = "log")]
58 let num_frames = self.frames.len();
59 if let Some(parent) = self.frames.last_mut() {
60 if let Some(index) = frame.field_index_in_parent {
61 trace!(
62 "[{}] Marking field #{} in parent {} as initialized",
63 num_frames,
64 index.to_string().yellow(),
65 parent.shape.blue()
66 );
67 parent.istate.fields.set(index);
68 }
69 }
70
71 // 3. If this is a container type like an array, make sure its internal state reflects that it's complete
72 match frame.shape.def {
73 Def::Array(array_def) => {
74 // For arrays, they're only fully initialized if all elements are populated
75 let current_index = frame.istate.list_index.unwrap_or(0);
76 trace!(
77 "[{}] Array {} has {}/{} elements populated",
78 self.frames.len(),
79 frame_shape.blue(),
80 current_index.to_string().yellow(),
81 array_def.n.to_string().green()
82 );
83
84 if current_index == array_def.n {
85 trace!(
86 "[{}] Array {} fully populated with {} elements, marking as initialized",
87 self.frames.len(),
88 frame_shape.blue(),
89 array_def.n.to_string().green()
90 );
91 // Mark the array itself as initialized (field 0)
92 frame.istate.fields.set(0);
93 }
94 }
95 // Add other container types here if needed
96 _ => {}
97 }
98 }
99
100 // Handle special frame modes
101 match frame.istate.mode {
102 // Handle list element frames
103 FrameMode::ListElement => {
104 if frame.is_fully_initialized() {
105 // This was a list or tuple element, so we need to push it to the parent
106 #[cfg(feature = "log")]
107 let frame_len = self.frames.len();
108
109 // Get parent frame
110 let parent_frame = self.frames.last_mut().unwrap();
111 let parent_shape = parent_frame.shape;
112
113 match parent_shape.def {
114 // Handle List/Array
115 Def::List(list_def) => {
116 let list_vtable = list_def.vtable;
117 trace!(
118 "[{}] Pushing element to list {}",
119 frame_len,
120 parent_shape.blue()
121 );
122 unsafe {
123 (list_vtable.push)(
124 PtrMut::new(parent_frame.data.as_mut_byte_ptr()),
125 PtrMut::new(frame.data.as_mut_byte_ptr()),
126 );
127 self.mark_moved_out_of(&mut frame);
128 }
129 }
130 Def::Scalar(s) if matches!(s.affinity, ScalarAffinity::Empty(_)) => {
131 trace!(
132 "[{}] Handling scalar empty unit type {}",
133 frame_len,
134 parent_shape.blue()
135 );
136 // Mark the parent scalar unit as fully initialized
137 unsafe {
138 parent_frame.mark_fully_initialized();
139 self.mark_moved_out_of(&mut frame);
140 }
141 }
142 _ => match parent_shape.ty {
143 // Handle Empty Unit Types (including empty tuple structs and tuples)
144 Type::User(UserType::Struct(sd))
145 if sd.kind == facet_core::StructKind::Tuple
146 && sd.fields.is_empty() =>
147 {
148 trace!(
149 "[{}] Handling empty tuple struct unit type {}",
150 frame_len,
151 parent_shape.blue()
152 );
153 // Mark the parent unit struct as fully initialized
154 unsafe {
155 parent_frame.mark_fully_initialized();
156 }
157 // Element frame is implicitly moved/consumed, but nothing to dealloc if it was also unit
158 unsafe { self.mark_moved_out_of(&mut frame) };
159 }
160
161 // Handle tuples (Type::Sequence(SequenceType::Tuple))
162 Type::Sequence(SequenceType::Tuple(tt)) => {
163 // Get the field index from list_index saved during push
164 let previous_index = parent_frame.istate.list_index.unwrap_or(1);
165 let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
166
167 if field_index >= tt.fields.len() {
168 panic!(
169 "Field index {} out of bounds for tuple {} with {} fields",
170 field_index,
171 parent_shape,
172 tt.fields.len()
173 );
174 }
175
176 let field = &tt.fields[field_index];
177 trace!(
178 "[{}] Setting tuple field {} ({}) of {}",
179 frame_len,
180 field_index.to_string().yellow(),
181 field.name.bright_blue(),
182 parent_shape.blue()
183 );
184
185 unsafe {
186 // Copy the element data to the tuple field
187 let field_ptr = parent_frame.data.field_uninit_at(field.offset);
188 field_ptr
189 .copy_from(
190 PtrConst::new(frame.data.as_byte_ptr()),
191 field.shape(),
192 )
193 .map_err(|_| ReflectError::Unsized {
194 shape: field.shape(),
195 })?; // Use ? to propagate potential unsized error
196
197 // Mark the specific field as initialized using its index
198 parent_frame.istate.fields.set(field_index);
199
200 // Mark the element as moved
201 self.mark_moved_out_of(&mut frame);
202 }
203 }
204
205 // Handle Tuple Structs
206 Type::User(UserType::Struct(sd))
207 if sd.kind == facet_core::StructKind::Tuple =>
208 {
209 // Get the field index from list_index saved during push
210 let previous_index = parent_frame.istate.list_index.unwrap_or(1);
211 let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
212
213 if field_index >= sd.fields.len() {
214 panic!(
215 "Field index {} out of bounds for tuple struct {} with {} fields",
216 field_index,
217 parent_shape,
218 sd.fields.len()
219 );
220 }
221
222 let field = &sd.fields[field_index];
223 trace!(
224 "[{}] Setting tuple struct field {} ({}) of {}",
225 frame_len,
226 field_index.to_string().yellow(),
227 field.name.bright_blue(),
228 parent_shape.blue()
229 );
230
231 unsafe {
232 // Copy the element data to the tuple field
233 let field_ptr = parent_frame.data.field_uninit_at(field.offset);
234 field_ptr
235 .copy_from(
236 PtrConst::new(frame.data.as_byte_ptr()),
237 field.shape(),
238 )
239 .map_err(|_| ReflectError::Unsized {
240 shape: field.shape(),
241 })?; // Use ? to propagate potential unsized error
242
243 // Mark the specific field as initialized using its index
244 parent_frame.istate.fields.set(field_index);
245
246 // Mark the element as moved
247 self.mark_moved_out_of(&mut frame);
248 }
249 }
250
251 // Handle Tuple Enum Variants
252 Type::User(UserType::Enum(_)) => {
253 // Ensure a variant is selected and it's a tuple variant
254 let variant =
255 parent_frame.istate.variant.as_ref().unwrap_or_else(|| {
256 panic!(
257 "Popping element for enum {} but no variant was selected",
258 parent_shape
259 )
260 });
261
262 if variant.data.kind != facet_core::StructKind::Tuple {
263 panic!(
264 "Popping element for enum {}, but selected variant '{}' is not a tuple variant",
265 parent_shape, variant.name
266 );
267 }
268
269 // Get the field index from list_index saved during push
270 let previous_index = parent_frame.istate.list_index.unwrap_or(1);
271 let field_index = previous_index - 1; // -1 because we incremented *after* using the index in push
272
273 if field_index >= variant.data.fields.len() {
274 panic!(
275 "Field index {} out of bounds for tuple enum variant '{}' of {} with {} fields",
276 field_index,
277 variant.name,
278 parent_shape,
279 variant.data.fields.len()
280 );
281 }
282
283 let field = &variant.data.fields[field_index];
284 trace!(
285 "[{}] Setting tuple enum variant field {} ({}) of variant '{}' in {}",
286 frame_len,
287 field_index.to_string().yellow(),
288 field.name.bright_blue(),
289 variant.name.yellow(),
290 parent_shape.blue()
291 );
292
293 unsafe {
294 // Copy the element data to the tuple field within the enum's data payload
295 let field_ptr = parent_frame.data.field_uninit_at(field.offset);
296 field_ptr
297 .copy_from(
298 PtrConst::new(frame.data.as_byte_ptr()),
299 field.shape(),
300 )
301 .map_err(|_| ReflectError::Unsized {
302 shape: field.shape(),
303 })?; // Use ? to propagate potential unsized error
304
305 // Mark the specific field as initialized using its index
306 parent_frame.istate.fields.set(field_index);
307
308 // Mark the element as moved
309 self.mark_moved_out_of(&mut frame);
310 }
311 }
312
313 // Handle Arrays
314 _ if matches!(parent_shape.def, Def::Array(_)) => {
315 // Get the element index from list_index saved during push
316 let previous_index = parent_frame.istate.list_index.unwrap_or(1);
317 let element_index = previous_index - 1; // -1 because we incremented *after* using the index in push
318
319 let array_def = match parent_shape.def {
320 Def::Array(array_def) => array_def,
321 _ => unreachable!("Already checked this is an array"),
322 };
323
324 if element_index >= array_def.n {
325 panic!(
326 "Element index {} out of bounds for array {} with {} elements",
327 element_index, parent_shape, array_def.n
328 );
329 }
330
331 trace!(
332 "[{}] Setting array element {} of {}",
333 frame_len,
334 element_index.to_string().yellow(),
335 parent_shape.blue()
336 );
337
338 unsafe {
339 // Get raw pointer to the array data
340 let array_ptr = (array_def.vtable.as_mut_ptr)(PtrMut::new(
341 parent_frame.data.as_mut_byte_ptr(),
342 ));
343
344 // Calculate the element size and offset
345 let element_size = array_def
346 .t
347 .layout
348 .sized_layout()
349 .map_err(|_| ReflectError::Unsized { shape: array_def.t })?
350 .size();
351
352 // Calculate pointer to the right element in the array
353 let element_offset = element_size * element_index;
354 let element_ptr = PtrUninit::new(
355 array_ptr.as_byte_ptr().add(element_offset) as *mut u8,
356 );
357
358 // Copy the element data to the array
359 element_ptr
360 .copy_from(
361 PtrConst::new(frame.data.as_byte_ptr()),
362 frame.shape,
363 )
364 .map_err(|_| ReflectError::Unsized {
365 shape: frame.shape,
366 })?; // Use ? to propagate potential unsized error
367
368 // Check if the array is fully populated and mark it specially if it is
369 if previous_index == array_def.n {
370 trace!(
371 "[{}] Array {} fully populated with {} elements, marking as fully initialized",
372 frame_len,
373 parent_shape.blue(),
374 array_def.n.to_string().green()
375 );
376 // Mark the array itself as fully initialized
377 parent_frame.mark_fully_initialized();
378
379 // For nested arrays, also mark the parent field as initialized
380 if let Some(parent_field_index) =
381 parent_frame.field_index_in_parent
382 {
383 // Find the grandparent (skip to before the parent frame) if it exists
384 if self.frames.len() >= 3 {
385 let grandparent_index = self.frames.len() - 2;
386 if let Some(grandparent_frame) =
387 self.frames.get_mut(grandparent_index)
388 {
389 trace!(
390 "[{}] Marking field {} in grandparent {} as initialized",
391 frame_len,
392 parent_field_index.to_string().yellow(),
393 grandparent_frame.shape.blue()
394 );
395 grandparent_frame
396 .istate
397 .fields
398 .set(parent_field_index);
399 }
400 }
401 }
402 }
403
404 // Mark the element as moved
405 self.mark_moved_out_of(&mut frame);
406 }
407 }
408
409 // Unexpected parent type
410 _ => {
411 panic!(
412 "FrameMode::ListElement pop expected parent to be List, Tuple, Tuple Struct, Tuple Enum Variant, or Array, but got {}",
413 parent_shape
414 );
415 }
416 },
417 }
418 } else {
419 // Frame not fully initialized, just deallocate if needed (handled by Frame drop later)
420 trace!(
421 "Popping uninitialized ListElement frame ({}), potential leak if allocated resources are not managed",
422 frame.shape.yellow()
423 );
424 }
425 }
426
427 // Handle map value frames
428 FrameMode::MapValue {
429 index: key_frame_index,
430 } if frame.is_fully_initialized() => {
431 // This was a map value, so we need to insert the key-value pair into the map
432
433 // Now let's remove the key frame from the frames array
434 let mut key_frame = self.frames.remove(key_frame_index);
435
436 // Make sure the key is fully initialized
437 if !key_frame.istate.fields.is_any_set() {
438 panic!("key is not initialized when popping value frame");
439 }
440
441 // Get parent map frame
442 #[cfg(feature = "log")]
443 let frame_len = self.frames.len();
444 let parent_frame = self.frames.last_mut().unwrap();
445 let parent_shape = parent_frame.shape;
446
447 // Make sure the parent is a map
448 match parent_shape.def {
449 Def::Map(_) => {
450 // Get the map vtable from the MapDef
451 if let Def::Map(map_def) = parent_shape.def {
452 trace!(
453 "[{}] Inserting key-value pair into map {}",
454 frame_len,
455 parent_shape.blue()
456 );
457 unsafe {
458 // Call the map's insert function with the key and value
459 (map_def.vtable.insert_fn)(
460 parent_frame.data.assume_init(),
461 key_frame.data.assume_init(),
462 PtrMut::new(frame.data.as_mut_byte_ptr()),
463 );
464 self.mark_moved_out_of(&mut key_frame);
465 self.mark_moved_out_of(&mut frame);
466 }
467 } else {
468 panic!("parent frame is not a map type");
469 }
470 }
471 _ => {
472 panic!("Expected map or hash map, got {}", frame.shape);
473 }
474 }
475 }
476
477 // Handle option frames
478 FrameMode::OptionSome => {
479 if frame.is_fully_initialized() {
480 trace!("Popping OptionSome (fully init'd)");
481
482 // Get parent frame
483 #[cfg(feature = "log")]
484 let frames_len = self.frames.len();
485 let parent_frame = self.frames.last_mut().unwrap();
486 let parent_shape = parent_frame.shape;
487
488 // Make sure the parent is an option
489 match parent_shape.def {
490 Def::Option(option_def) => {
491 trace!(
492 "[{}] Setting Some value in option {}",
493 frames_len,
494 parent_shape.blue()
495 );
496 unsafe {
497 // Call the option's init_some function
498 (option_def.vtable.init_some_fn)(
499 parent_frame.data,
500 PtrConst::new(frame.data.as_byte_ptr()),
501 );
502 trace!(
503 "Marking parent frame as fully initialized — its shape is {}",
504 parent_frame.shape
505 );
506 let variant = match parent_frame.shape.ty {
507 Type::User(UserType::Enum(EnumType { variants, .. })) => {
508 variants[1]
509 }
510 _ => Variant::builder()
511 .name("Some")
512 .discriminant(1)
513 .data(
514 StructType::builder()
515 .tuple()
516 .repr(Repr::default())
517 .build(),
518 )
519 .build(),
520 };
521 parent_frame.istate.variant = Some(variant); // the `Some` variant
522 parent_frame.mark_fully_initialized();
523 trace!(
524 "After marking: shape={} at {:p}, flags={:?}, mode={:?}, fully_initialized={}",
525 parent_frame.shape.blue(),
526 parent_frame.data.as_byte_ptr(),
527 parent_frame.istate.flags.bright_magenta(),
528 parent_frame.istate.mode.yellow(),
529 if parent_frame.is_fully_initialized() {
530 "✅"
531 } else {
532 "❌"
533 }
534 );
535
536 self.mark_moved_out_of(&mut frame);
537 }
538 }
539 _ => {
540 panic!(
541 "Expected parent frame to be an option type, got {}",
542 frame.shape
543 );
544 }
545 }
546 } else {
547 trace!("Popping OptionSome (not fully init'd)");
548 }
549 }
550
551 // Map keys are just tracked, they don't need special handling when popped
552 // FIXME: that's not true, we need to deallocate them at least??
553 FrameMode::MapKey => {}
554
555 // Field frame
556 FrameMode::Field => {}
557
558 // Uninitialized special frames
559 _ => {}
560 }
561
562 Ok(Some(frame))
563 }
564}