facet_reflect/partial/partial_api/
sets.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Sets
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<const BORROW: bool> Partial<'_, BORROW> {
7    /// Initializes a set (HashSet, BTreeSet, etc.) if it hasn't been initialized before.
8    /// This is a prerequisite to `begin_set_item`/`set`/`end` or the shorthand `insert`.
9    ///
10    /// `begin_set` does not clear the set if it was previously initialized.
11    /// `begin_set` does not push a new frame to the stack, and thus does not
12    /// require `end` to be called afterwards.
13    pub fn begin_set(mut self) -> Result<Self, ReflectError> {
14        crate::trace!("begin_set()");
15        let frame = self.frames_mut().last_mut().unwrap();
16
17        match &frame.tracker {
18            Tracker::Scalar if !frame.is_init => {
19                // that's good, let's initialize it
20            }
21            Tracker::Scalar => {
22                // is_init is true - initialized (perhaps from a previous round?) but should be a set tracker, let's fix that:
23                frame.tracker = Tracker::Set {
24                    current_child: false,
25                };
26                return Ok(self);
27            }
28            Tracker::Set { .. } => {
29                if frame.is_init {
30                    // already initialized, nothing to do
31                    return Ok(self);
32                }
33            }
34            _ => {
35                return Err(ReflectError::UnexpectedTracker {
36                    message: "begin_set called but tracker isn't something set-like",
37                    current_tracker: frame.tracker.kind(),
38                });
39            }
40        };
41
42        // Check that we have a Set
43        let set_def = match &frame.shape.def {
44            Def::Set(set_def) => set_def,
45            _ => {
46                return Err(ReflectError::OperationFailed {
47                    shape: frame.shape,
48                    operation: "begin_set can only be called on Set types",
49                });
50            }
51        };
52
53        let init_fn = set_def.vtable.init_in_place_with_capacity;
54
55        // Initialize the set with default capacity (0)
56        unsafe {
57            init_fn(frame.data, 0);
58        }
59
60        // Update tracker to Set state and mark as initialized
61        frame.tracker = Tracker::Set {
62            current_child: false,
63        };
64        frame.is_init = true;
65
66        Ok(self)
67    }
68
69    /// Begins pushing an element to the set.
70    /// The element should be set using `set()` or similar methods, then `end()` to complete.
71    pub fn begin_set_item(mut self) -> Result<Self, ReflectError> {
72        crate::trace!("begin_set_item()");
73        let frame = self.frames_mut().last_mut().unwrap();
74
75        // Check that we have a Set that's been initialized
76        let set_def = match &frame.shape.def {
77            Def::Set(set_def) => set_def,
78            _ => {
79                return Err(ReflectError::OperationFailed {
80                    shape: frame.shape,
81                    operation: "begin_set_item can only be called on Set types",
82                });
83            }
84        };
85
86        // Verify the tracker is in Set state and initialized
87        match &mut frame.tracker {
88            Tracker::Set { current_child } if frame.is_init => {
89                if *current_child {
90                    return Err(ReflectError::OperationFailed {
91                        shape: frame.shape,
92                        operation: "already pushing an element, call end() first",
93                    });
94                }
95                *current_child = true;
96            }
97            _ => {
98                return Err(ReflectError::OperationFailed {
99                    shape: frame.shape,
100                    operation: "must call begin_set() before begin_set_item()",
101                });
102            }
103        }
104
105        // Get the element shape
106        let element_shape = set_def.t();
107
108        // Allocate space for the new element
109        let element_layout = match element_shape.layout.sized_layout() {
110            Ok(layout) => layout,
111            Err(_) => {
112                return Err(ReflectError::Unsized {
113                    shape: element_shape,
114                    operation: "begin_set_item: calculating element layout",
115                });
116            }
117        };
118        let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
119
120        let Some(element_ptr) = NonNull::new(element_ptr) else {
121            return Err(ReflectError::OperationFailed {
122                shape: frame.shape,
123                operation: "failed to allocate memory for set element",
124            });
125        };
126
127        // Push a new frame for the element
128        self.frames_mut().push(Frame::new(
129            PtrUninit::new(element_ptr.as_ptr()),
130            element_shape,
131            FrameOwnership::Owned,
132        ));
133
134        Ok(self)
135    }
136}