facet_reflect/partial/partial_api/
sets.rs

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