facet_reflect/partial/partial_api/
lists.rs1use super::*;
2use crate::AllocatedShape;
3
4impl<const BORROW: bool> Partial<'_, BORROW> {
8 pub fn begin_list(mut self) -> Result<Self, ReflectError> {
16 crate::trace!("begin_list()");
17 let frame = self.frames_mut().last_mut().unwrap();
18
19 match &frame.tracker {
20 Tracker::Scalar if !frame.is_init => {
21 }
23 Tracker::Scalar => {
24 match &frame.allocated.shape().def {
27 Def::List(_) => {
28 frame.tracker = Tracker::List {
30 current_child: false,
31 };
32 return Ok(self);
33 }
34 Def::DynamicValue(_) => {
35 frame.tracker = Tracker::DynamicValue {
38 state: DynamicValueState::Array {
39 building_element: false,
40 },
41 };
42 return Ok(self);
43 }
44 _ => {
45 return Err(ReflectError::OperationFailed {
46 shape: frame.allocated.shape(),
47 operation: "begin_list can only be called on List types or DynamicValue",
48 });
49 }
50 }
51 }
52 Tracker::List { .. } => {
53 if frame.is_init {
54 return Ok(self);
56 }
57 }
58 Tracker::DynamicValue { state } => {
59 if matches!(state, DynamicValueState::Array { .. }) {
61 return Ok(self);
62 }
63 frame.deinit_for_replace();
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.allocated.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.allocated.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.allocated.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.allocated.shape().def {
148 Def::Array(array_def) => array_def,
149 _ => {
150 return Err(ReflectError::OperationFailed {
151 shape: frame.allocated.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.allocated.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.allocated.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.allocated.shape(),
202 operation: "already building an item, call end() first",
203 });
204 }
205
206 let element_shape = match &frame.allocated.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.allocated.shape(),
214 operation: "smart pointer pointee is not a slice",
215 });
216 }
217 },
218 None => {
219 return Err(ReflectError::OperationFailed {
220 shape: frame.allocated.shape(),
221 operation: "smart pointer has no pointee",
222 });
223 }
224 },
225 _ => {
226 return Err(ReflectError::OperationFailed {
227 shape: frame.allocated.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.allocated.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(
262 element_data,
263 AllocatedShape::new(element_shape, element_layout.size()),
264 FrameOwnership::Owned,
265 );
266 self.frames_mut().push(element_frame);
267
268 let parent_idx = self.frames().len() - 2;
271 if let Tracker::SmartPointerSlice { building_item, .. } =
272 &mut self.frames_mut()[parent_idx].tracker
273 {
274 crate::trace!("Marking element frame as building item");
275 *building_item = true;
276 }
277
278 return Ok(self);
279 }
280
281 if let Tracker::DynamicValue {
283 state: DynamicValueState::Array { building_element },
284 } = &frame.tracker
285 {
286 if *building_element {
287 return Err(ReflectError::OperationFailed {
288 shape: frame.allocated.shape(),
289 operation: "already building an element, call end() first",
290 });
291 }
292
293 let element_shape = frame.allocated.shape();
296 let element_layout = match element_shape.layout.sized_layout() {
297 Ok(layout) => layout,
298 Err(_) => {
299 return Err(ReflectError::Unsized {
300 shape: element_shape,
301 operation: "begin_list_item: calculating element layout",
302 });
303 }
304 };
305
306 let element_data = if element_layout.size() == 0 {
307 PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
309 } else {
310 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
311 let Some(element_ptr) = NonNull::new(element_ptr) else {
312 return Err(ReflectError::OperationFailed {
313 shape: frame.allocated.shape(),
314 operation: "failed to allocate memory for list element",
315 });
316 };
317 PtrUninit::new(element_ptr.as_ptr())
318 };
319
320 self.frames_mut().push(Frame::new(
322 element_data,
323 AllocatedShape::new(element_shape, element_layout.size()),
324 FrameOwnership::Owned,
325 ));
326
327 let parent_idx = self.frames().len() - 2;
329 if let Tracker::DynamicValue {
330 state: DynamicValueState::Array { building_element },
331 } = &mut self.frames_mut()[parent_idx].tracker
332 {
333 *building_element = true;
334 }
335
336 return Ok(self);
337 }
338
339 let list_def = match &frame.allocated.shape().def {
341 Def::List(list_def) => list_def,
342 _ => {
343 return Err(ReflectError::OperationFailed {
344 shape: frame.allocated.shape(),
345 operation: "push can only be called on List or DynamicValue types",
346 });
347 }
348 };
349
350 match &mut frame.tracker {
352 Tracker::List { current_child } if frame.is_init => {
353 if *current_child {
354 return Err(ReflectError::OperationFailed {
355 shape: frame.allocated.shape(),
356 operation: "already pushing an element, call pop() first",
357 });
358 }
359 *current_child = true;
360 }
361 _ => {
362 return Err(ReflectError::OperationFailed {
363 shape: frame.allocated.shape(),
364 operation: "must call begin_list() before push()",
365 });
366 }
367 }
368
369 let element_shape = list_def.t();
371
372 let element_layout = match element_shape.layout.sized_layout() {
374 Ok(layout) => layout,
375 Err(_) => {
376 return Err(ReflectError::Unsized {
377 shape: element_shape,
378 operation: "begin_list_item: calculating element layout",
379 });
380 }
381 };
382 let element_data = if element_layout.size() == 0 {
383 PtrUninit::new(NonNull::<u8>::dangling().as_ptr())
385 } else {
386 let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
387 let Some(element_ptr) = NonNull::new(element_ptr) else {
388 return Err(ReflectError::OperationFailed {
389 shape: frame.allocated.shape(),
390 operation: "failed to allocate memory for list element",
391 });
392 };
393 PtrUninit::new(element_ptr.as_ptr())
394 };
395
396 self.frames_mut().push(Frame::new(
398 element_data,
399 AllocatedShape::new(element_shape, element_layout.size()),
400 FrameOwnership::Owned,
401 ));
402
403 Ok(self)
404 }
405}