facet_reflect/partial/partial_api/
lists.rs1use super::*;
2
3impl<const BORROW: bool> Partial<'_, BORROW> {
7 pub fn begin_list(mut self) -> Result<Self, ReflectError> {
15 crate::trace!("begin_list()");
16 let frame = self.frames_mut().last_mut().unwrap();
17
18 match &frame.tracker {
19 Tracker::Scalar if !frame.is_init => {
20 }
22 Tracker::Scalar => {
23 if !matches!(frame.shape.def, Def::List(_)) {
26 return Err(ReflectError::OperationFailed {
27 shape: frame.shape,
28 operation: "begin_list can only be called on List types",
29 });
30 }
31 frame.tracker = Tracker::List {
32 current_child: false,
33 };
34 return Ok(self);
35 }
36 Tracker::List { .. } => {
37 if frame.is_init {
38 return Ok(self);
40 }
41 }
42 Tracker::DynamicValue { state } => {
43 if matches!(state, DynamicValueState::Array { .. }) {
45 return Ok(self);
46 }
47 frame.deinit();
49 }
50 Tracker::SmartPointerSlice { .. } => {
51 return Ok(self);
53 }
54 _ => {
55 return Err(ReflectError::UnexpectedTracker {
56 message: "begin_list called but tracker isn't something list-like",
57 current_tracker: frame.tracker.kind(),
58 });
59 }
60 };
61
62 match &frame.shape.def {
64 Def::List(list_def) => {
65 let init_fn = match list_def.init_in_place_with_capacity() {
67 Some(f) => f,
68 None => {
69 return Err(ReflectError::OperationFailed {
70 shape: frame.shape,
71 operation: "list type does not support initialization with capacity",
72 });
73 }
74 };
75
76 unsafe {
78 init_fn(frame.data, 0);
79 }
80
81 frame.tracker = Tracker::List {
83 current_child: false,
84 };
85 frame.is_init = true;
86 }
87 Def::DynamicValue(dyn_def) => {
88 unsafe {
90 (dyn_def.vtable.begin_array)(frame.data);
91 }
92
93 frame.tracker = Tracker::DynamicValue {
95 state: DynamicValueState::Array {
96 building_element: false,
97 },
98 };
99 frame.is_init = true;
100 }
101 _ => {
102 return Err(ReflectError::OperationFailed {
103 shape: frame.shape,
104 operation: "begin_list can only be called on List or DynamicValue types",
105 });
106 }
107 }
108
109 Ok(self)
110 }
111
112 pub fn begin_list_item(mut self) -> Result<Self, ReflectError> {
115 crate::trace!("begin_list_item()");
116 let frame = self.frames_mut().last_mut().unwrap();
117
118 if let Tracker::SmartPointerSlice {
120 building_item,
121 vtable: _,
122 } = &frame.tracker
123 {
124 if *building_item {
125 return Err(ReflectError::OperationFailed {
126 shape: frame.shape,
127 operation: "already building an item, call end() first",
128 });
129 }
130
131 let element_shape = match &frame.shape.def {
133 Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
134 Some(pointee_shape) => match &pointee_shape.ty {
135 Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
136 _ => {
137 return Err(ReflectError::OperationFailed {
138 shape: frame.shape,
139 operation: "smart pointer pointee is not a slice",
140 });
141 }
142 },
143 None => {
144 return Err(ReflectError::OperationFailed {
145 shape: frame.shape,
146 operation: "smart pointer has no pointee",
147 });
148 }
149 },
150 _ => {
151 return Err(ReflectError::OperationFailed {
152 shape: frame.shape,
153 operation: "expected smart pointer definition",
154 });
155 }
156 };
157
158 crate::trace!("Pointee is a slice of {element_shape}");
160 let element_layout = match element_shape.layout.sized_layout() {
161 Ok(layout) => layout,
162 Err(_) => {
163 return Err(ReflectError::OperationFailed {
164 shape: element_shape,
165 operation: "cannot allocate unsized element",
166 });
167 }
168 };
169
170 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
171 let Some(element_ptr) = NonNull::new(element_ptr) else {
172 return Err(ReflectError::OperationFailed {
173 shape: frame.shape,
174 operation: "failed to allocate memory for list element",
175 });
176 };
177
178 crate::trace!("Pushing element frame, which we just allocated");
180 let element_frame = Frame::new(
181 PtrUninit::new(element_ptr.as_ptr()),
182 element_shape,
183 FrameOwnership::Owned,
184 );
185 self.frames_mut().push(element_frame);
186
187 let parent_idx = self.frames().len() - 2;
190 if let Tracker::SmartPointerSlice { building_item, .. } =
191 &mut self.frames_mut()[parent_idx].tracker
192 {
193 crate::trace!("Marking element frame as building item");
194 *building_item = true;
195 }
196
197 return Ok(self);
198 }
199
200 if let Tracker::DynamicValue {
202 state: DynamicValueState::Array { building_element },
203 } = &frame.tracker
204 {
205 if *building_element {
206 return Err(ReflectError::OperationFailed {
207 shape: frame.shape,
208 operation: "already building an element, call end() first",
209 });
210 }
211
212 let element_shape = frame.shape;
215 let element_layout = match element_shape.layout.sized_layout() {
216 Ok(layout) => layout,
217 Err(_) => {
218 return Err(ReflectError::Unsized {
219 shape: element_shape,
220 operation: "begin_list_item: calculating element layout",
221 });
222 }
223 };
224
225 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
226 let Some(element_ptr) = NonNull::new(element_ptr) else {
227 return Err(ReflectError::OperationFailed {
228 shape: frame.shape,
229 operation: "failed to allocate memory for list element",
230 });
231 };
232
233 self.frames_mut().push(Frame::new(
235 PtrUninit::new(element_ptr.as_ptr()),
236 element_shape,
237 FrameOwnership::Owned,
238 ));
239
240 let parent_idx = self.frames().len() - 2;
242 if let Tracker::DynamicValue {
243 state: DynamicValueState::Array { building_element },
244 } = &mut self.frames_mut()[parent_idx].tracker
245 {
246 *building_element = true;
247 }
248
249 return Ok(self);
250 }
251
252 let list_def = match &frame.shape.def {
254 Def::List(list_def) => list_def,
255 _ => {
256 return Err(ReflectError::OperationFailed {
257 shape: frame.shape,
258 operation: "push can only be called on List or DynamicValue types",
259 });
260 }
261 };
262
263 match &mut frame.tracker {
265 Tracker::List { current_child } if frame.is_init => {
266 if *current_child {
267 return Err(ReflectError::OperationFailed {
268 shape: frame.shape,
269 operation: "already pushing an element, call pop() first",
270 });
271 }
272 *current_child = true;
273 }
274 _ => {
275 return Err(ReflectError::OperationFailed {
276 shape: frame.shape,
277 operation: "must call begin_list() before push()",
278 });
279 }
280 }
281
282 let element_shape = list_def.t();
284
285 let element_layout = match element_shape.layout.sized_layout() {
287 Ok(layout) => layout,
288 Err(_) => {
289 return Err(ReflectError::Unsized {
290 shape: element_shape,
291 operation: "begin_list_item: calculating element layout",
292 });
293 }
294 };
295 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
296
297 let Some(element_ptr) = NonNull::new(element_ptr) else {
298 return Err(ReflectError::OperationFailed {
299 shape: frame.shape,
300 operation: "failed to allocate memory for list element",
301 });
302 };
303
304 self.frames_mut().push(Frame::new(
306 PtrUninit::new(element_ptr.as_ptr()),
307 element_shape,
308 FrameOwnership::Owned,
309 ));
310
311 Ok(self)
312 }
313}