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 match &frame.shape.def {
26 Def::List(_) => {
27 frame.tracker = Tracker::List {
29 current_child: false,
30 };
31 return Ok(self);
32 }
33 Def::DynamicValue(_) => {
34 frame.tracker = Tracker::DynamicValue {
37 state: DynamicValueState::Array {
38 building_element: false,
39 },
40 };
41 return Ok(self);
42 }
43 _ => {
44 return Err(ReflectError::OperationFailed {
45 shape: frame.shape,
46 operation: "begin_list can only be called on List types or DynamicValue",
47 });
48 }
49 }
50 }
51 Tracker::List { .. } => {
52 if frame.is_init {
53 return Ok(self);
55 }
56 }
57 Tracker::DynamicValue { state } => {
58 if matches!(state, DynamicValueState::Array { .. }) {
60 return Ok(self);
61 }
62 if matches!(frame.ownership, FrameOwnership::ManagedElsewhere) && frame.is_init {
65 unsafe { frame.shape.call_drop_in_place(frame.data.assume_init()) };
66 }
67 frame.deinit();
68 }
69 Tracker::SmartPointerSlice { .. } => {
70 return Ok(self);
72 }
73 _ => {
74 return Err(ReflectError::UnexpectedTracker {
75 message: "begin_list called but tracker isn't something list-like",
76 current_tracker: frame.tracker.kind(),
77 });
78 }
79 };
80
81 match &frame.shape.def {
83 Def::List(list_def) => {
84 let init_fn = match list_def.init_in_place_with_capacity() {
86 Some(f) => f,
87 None => {
88 return Err(ReflectError::OperationFailed {
89 shape: frame.shape,
90 operation: "list type does not support initialization with capacity",
91 });
92 }
93 };
94
95 unsafe {
97 init_fn(frame.data, 0);
98 }
99
100 frame.tracker = Tracker::List {
102 current_child: false,
103 };
104 frame.is_init = true;
105 }
106 Def::DynamicValue(dyn_def) => {
107 unsafe {
109 (dyn_def.vtable.begin_array)(frame.data);
110 }
111
112 frame.tracker = Tracker::DynamicValue {
114 state: DynamicValueState::Array {
115 building_element: false,
116 },
117 };
118 frame.is_init = true;
119 }
120 _ => {
121 return Err(ReflectError::OperationFailed {
122 shape: frame.shape,
123 operation: "begin_list can only be called on List or DynamicValue types",
124 });
125 }
126 }
127
128 Ok(self)
129 }
130
131 pub fn begin_array(mut self) -> Result<Self, ReflectError> {
143 crate::trace!("begin_array()");
144 let frame = self.frames_mut().last_mut().unwrap();
145
146 let array_def = match &frame.shape.def {
148 Def::Array(array_def) => array_def,
149 _ => {
150 return Err(ReflectError::OperationFailed {
151 shape: frame.shape,
152 operation: "begin_array can only be called on Array types",
153 });
154 }
155 };
156
157 if array_def.n > 63 {
159 return Err(ReflectError::OperationFailed {
160 shape: frame.shape,
161 operation: "arrays larger than 63 elements are not yet supported",
162 });
163 }
164
165 match &frame.tracker {
166 Tracker::Scalar if !frame.is_init => {
167 frame.tracker = Tracker::Array {
169 iset: ISet::default(),
170 current_child: None,
171 };
172 }
173 Tracker::Array { .. } => {
174 }
176 _ => {
177 return Err(ReflectError::OperationFailed {
178 shape: frame.shape,
179 operation: "begin_array: unexpected tracker state",
180 });
181 }
182 }
183
184 Ok(self)
185 }
186
187 pub fn begin_list_item(mut self) -> Result<Self, ReflectError> {
190 crate::trace!("begin_list_item()");
191 let frame = self.frames_mut().last_mut().unwrap();
192
193 if let Tracker::SmartPointerSlice {
195 building_item,
196 vtable: _,
197 } = &frame.tracker
198 {
199 if *building_item {
200 return Err(ReflectError::OperationFailed {
201 shape: frame.shape,
202 operation: "already building an item, call end() first",
203 });
204 }
205
206 let element_shape = match &frame.shape.def {
208 Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
209 Some(pointee_shape) => match &pointee_shape.ty {
210 Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
211 _ => {
212 return Err(ReflectError::OperationFailed {
213 shape: frame.shape,
214 operation: "smart pointer pointee is not a slice",
215 });
216 }
217 },
218 None => {
219 return Err(ReflectError::OperationFailed {
220 shape: frame.shape,
221 operation: "smart pointer has no pointee",
222 });
223 }
224 },
225 _ => {
226 return Err(ReflectError::OperationFailed {
227 shape: frame.shape,
228 operation: "expected smart pointer definition",
229 });
230 }
231 };
232
233 crate::trace!("Pointee is a slice of {element_shape}");
235 let element_layout = match element_shape.layout.sized_layout() {
236 Ok(layout) => layout,
237 Err(_) => {
238 return Err(ReflectError::OperationFailed {
239 shape: element_shape,
240 operation: "cannot allocate unsized element",
241 });
242 }
243 };
244
245 let element_data = if element_layout.size() == 0 {
246 PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
248 } else {
249 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
250 let Some(element_ptr) = NonNull::new(element_ptr) else {
251 return Err(ReflectError::OperationFailed {
252 shape: frame.shape,
253 operation: "failed to allocate memory for list element",
254 });
255 };
256 PtrUninit::new(element_ptr.as_ptr())
257 };
258
259 crate::trace!("Pushing element frame, which we just allocated");
261 let element_frame = Frame::new(element_data, element_shape, FrameOwnership::Owned);
262 self.frames_mut().push(element_frame);
263
264 let parent_idx = self.frames().len() - 2;
267 if let Tracker::SmartPointerSlice { building_item, .. } =
268 &mut self.frames_mut()[parent_idx].tracker
269 {
270 crate::trace!("Marking element frame as building item");
271 *building_item = true;
272 }
273
274 return Ok(self);
275 }
276
277 if let Tracker::DynamicValue {
279 state: DynamicValueState::Array { building_element },
280 } = &frame.tracker
281 {
282 if *building_element {
283 return Err(ReflectError::OperationFailed {
284 shape: frame.shape,
285 operation: "already building an element, call end() first",
286 });
287 }
288
289 let element_shape = frame.shape;
292 let element_layout = match element_shape.layout.sized_layout() {
293 Ok(layout) => layout,
294 Err(_) => {
295 return Err(ReflectError::Unsized {
296 shape: element_shape,
297 operation: "begin_list_item: calculating element layout",
298 });
299 }
300 };
301
302 let element_data = if element_layout.size() == 0 {
303 PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
305 } else {
306 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
307 let Some(element_ptr) = NonNull::new(element_ptr) else {
308 return Err(ReflectError::OperationFailed {
309 shape: frame.shape,
310 operation: "failed to allocate memory for list element",
311 });
312 };
313 PtrUninit::new(element_ptr.as_ptr())
314 };
315
316 self.frames_mut().push(Frame::new(
318 element_data,
319 element_shape,
320 FrameOwnership::Owned,
321 ));
322
323 let parent_idx = self.frames().len() - 2;
325 if let Tracker::DynamicValue {
326 state: DynamicValueState::Array { building_element },
327 } = &mut self.frames_mut()[parent_idx].tracker
328 {
329 *building_element = true;
330 }
331
332 return Ok(self);
333 }
334
335 let list_def = match &frame.shape.def {
337 Def::List(list_def) => list_def,
338 _ => {
339 return Err(ReflectError::OperationFailed {
340 shape: frame.shape,
341 operation: "push can only be called on List or DynamicValue types",
342 });
343 }
344 };
345
346 match &mut frame.tracker {
348 Tracker::List { current_child } if frame.is_init => {
349 if *current_child {
350 return Err(ReflectError::OperationFailed {
351 shape: frame.shape,
352 operation: "already pushing an element, call pop() first",
353 });
354 }
355 *current_child = true;
356 }
357 _ => {
358 return Err(ReflectError::OperationFailed {
359 shape: frame.shape,
360 operation: "must call begin_list() before push()",
361 });
362 }
363 }
364
365 let element_shape = list_def.t();
367
368 let element_layout = match element_shape.layout.sized_layout() {
370 Ok(layout) => layout,
371 Err(_) => {
372 return Err(ReflectError::Unsized {
373 shape: element_shape,
374 operation: "begin_list_item: calculating element layout",
375 });
376 }
377 };
378 let element_data = if element_layout.size() == 0 {
379 PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
381 } else {
382 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
383 let Some(element_ptr) = NonNull::new(element_ptr) else {
384 return Err(ReflectError::OperationFailed {
385 shape: frame.shape,
386 operation: "failed to allocate memory for list element",
387 });
388 };
389 PtrUninit::new(element_ptr.as_ptr())
390 };
391
392 self.frames_mut().push(Frame::new(
394 element_data,
395 element_shape,
396 FrameOwnership::Owned,
397 ));
398
399 Ok(self)
400 }
401}