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