1use core::{fmt::Debug, marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
2use facet_core::{FieldError, PtrMut, PtrUninit, Shape, ShapeLayout};
3
4use crate::{Guard, HeapValue, ReflectError, ReflectErrorKind, peek::ListLikeDef};
5
6use super::Poke;
7
8pub struct PokeListLike<'mem, 'facet> {
10 value: Poke<'mem, 'facet>,
11 def: ListLikeDef,
12 len: usize,
13}
14
15impl<'mem, 'facet> Debug for PokeListLike<'mem, 'facet> {
16 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 f.debug_struct("PokeListLike").finish_non_exhaustive()
18 }
19}
20
21pub struct PokeListLikeIter<'mem, 'facet> {
27 data: PtrMut,
28 stride: usize,
29 index: usize,
30 len: usize,
31 elem_shape: &'static Shape,
32 _list: PhantomData<Poke<'mem, 'facet>>,
33}
34
35impl<'mem, 'facet> Iterator for PokeListLikeIter<'mem, 'facet> {
36 type Item = Poke<'mem, 'facet>;
37
38 #[inline]
39 fn next(&mut self) -> Option<Self::Item> {
40 if self.index >= self.len {
41 return None;
42 }
43 let item_ptr = unsafe { self.data.field(self.stride * self.index) };
44 self.index += 1;
45 Some(unsafe { Poke::from_raw_parts(item_ptr, self.elem_shape) })
46 }
47
48 #[inline]
49 fn size_hint(&self) -> (usize, Option<usize>) {
50 let remaining = self.len.saturating_sub(self.index);
51 (remaining, Some(remaining))
52 }
53}
54
55impl<'mem, 'facet> ExactSizeIterator for PokeListLikeIter<'mem, 'facet> {}
56
57impl<'mem, 'facet> PokeListLike<'mem, 'facet> {
58 #[inline]
68 pub unsafe fn new(value: Poke<'mem, 'facet>, def: ListLikeDef) -> Self {
69 let len = match def {
70 ListLikeDef::List(v) => unsafe { (v.vtable.len)(value.data()) },
71 ListLikeDef::Slice(_) => {
72 let slice_as_units = unsafe { value.data().get::<[()]>() };
73 slice_as_units.len()
74 }
75 ListLikeDef::Array(v) => v.n,
76 };
77 Self { value, def, len }
78 }
79
80 fn err(&self, kind: ReflectErrorKind) -> ReflectError {
81 self.value.err(kind)
82 }
83
84 #[inline]
86 pub const fn len(&self) -> usize {
87 self.len
88 }
89
90 #[inline]
92 pub const fn is_empty(&self) -> bool {
93 self.len == 0
94 }
95
96 #[inline]
98 pub const fn def(&self) -> ListLikeDef {
99 self.def
100 }
101
102 #[inline]
104 pub fn get(&self, index: usize) -> Option<crate::Peek<'_, 'facet>> {
105 self.as_peek_list_like().get(index)
106 }
107
108 pub fn get_mut(&mut self, index: usize) -> Option<Poke<'_, 'facet>> {
110 if index >= self.len {
111 return None;
112 }
113
114 let item_ptr = match self.def {
115 ListLikeDef::List(def) => {
116 let get_mut_fn = def.vtable.get_mut?;
117 unsafe { get_mut_fn(self.value.data_mut(), index, self.value.shape())? }
118 }
119 ListLikeDef::Array(def) => {
120 let elem_layout = match self.def.t().layout {
121 ShapeLayout::Sized(layout) => layout,
122 ShapeLayout::Unsized => return None,
123 };
124 let base = unsafe { (def.vtable.as_mut_ptr)(self.value.data_mut()) };
125 unsafe { base.field(index * elem_layout.size()) }
126 }
127 ListLikeDef::Slice(def) => {
128 let elem_layout = match self.def.t().layout {
129 ShapeLayout::Sized(layout) => layout,
130 ShapeLayout::Unsized => return None,
131 };
132 let base = unsafe { (def.vtable.as_mut_ptr)(self.value.data_mut()) };
133 unsafe { base.field(index * elem_layout.size()) }
134 }
135 };
136
137 Some(unsafe { Poke::from_raw_parts(item_ptr, self.def.t()) })
138 }
139
140 pub fn iter_mut(self) -> Result<PokeListLikeIter<'mem, 'facet>, ReflectError> {
151 let elem_shape = self.def.t();
152 let stride = match elem_shape.layout {
153 ShapeLayout::Sized(layout) => layout.size(),
154 ShapeLayout::Unsized => {
155 return Err(self.err(ReflectErrorKind::OperationFailed {
156 shape: self.value.shape,
157 operation: "iter_mut requires sized element type",
158 }));
159 }
160 };
161
162 let data = match self.def {
163 ListLikeDef::List(def) => match def.vtable.as_mut_ptr {
164 Some(as_mut_ptr_fn) => unsafe { as_mut_ptr_fn(self.value.data) },
165 None => {
166 return Err(self.err(ReflectErrorKind::OperationFailed {
167 shape: self.value.shape,
168 operation:
169 "iter_mut requires a contiguous `as_mut_ptr` vtable entry; use `get_mut` per index",
170 }));
171 }
172 },
173 ListLikeDef::Array(def) => unsafe { (def.vtable.as_mut_ptr)(self.value.data) },
174 ListLikeDef::Slice(def) => unsafe { (def.vtable.as_mut_ptr)(self.value.data) },
175 };
176
177 Ok(PokeListLikeIter {
178 data,
179 stride,
180 index: 0,
181 len: self.len,
182 elem_shape,
183 _list: PhantomData,
184 })
185 }
186
187 pub fn push<T: facet_core::Facet<'facet>>(&mut self, value: T) -> Result<(), ReflectError> {
193 if self.def.t() != T::SHAPE {
194 return Err(self.err(ReflectErrorKind::WrongShape {
195 expected: self.def.t(),
196 actual: T::SHAPE,
197 }));
198 }
199 let push_fn = self.push_fn()?;
200 let mut value = ManuallyDrop::new(value);
201 unsafe {
202 let item_ptr = PtrMut::new(&mut value as *mut ManuallyDrop<T> as *mut u8);
203 push_fn(self.value.data_mut(), item_ptr);
204 }
205 self.len += 1;
206 Ok(())
207 }
208
209 pub fn push_from_heap<const BORROW: bool>(
214 &mut self,
215 value: HeapValue<'facet, BORROW>,
216 ) -> Result<(), ReflectError> {
217 if self.def.t() != value.shape() {
218 return Err(self.err(ReflectErrorKind::WrongShape {
219 expected: self.def.t(),
220 actual: value.shape(),
221 }));
222 }
223 let push_fn = self.push_fn()?;
224 let mut value = value;
225 let guard = value
226 .guard
227 .take()
228 .expect("HeapValue guard was already taken");
229 unsafe {
230 let item_ptr = PtrMut::new(guard.ptr.as_ptr());
231 push_fn(self.value.data_mut(), item_ptr);
232 }
233 drop(guard);
234 self.len += 1;
235 Ok(())
236 }
237
238 pub fn pop(&mut self) -> Result<Option<HeapValue<'facet, true>>, ReflectError> {
243 let list_def = match self.def {
244 ListLikeDef::List(def) => def,
245 _ => {
246 return Err(self.err(ReflectErrorKind::OperationFailed {
247 shape: self.value.shape(),
248 operation: "pop: only list-backed list-likes support pop",
249 }));
250 }
251 };
252 let pop_fn = list_def.pop().ok_or_else(|| {
253 self.err(ReflectErrorKind::OperationFailed {
254 shape: self.value.shape(),
255 operation: "pop: list type does not support pop",
256 })
257 })?;
258 let elem_shape = self.def.t();
259 let layout = elem_shape.layout.sized_layout().map_err(|_| {
260 self.err(ReflectErrorKind::Unsized {
261 shape: elem_shape,
262 operation: "pop",
263 })
264 })?;
265 let ptr = if layout.size() == 0 {
266 NonNull::<u8>::dangling()
267 } else {
268 let raw = unsafe { alloc::alloc::alloc(layout) };
269 match NonNull::new(raw) {
270 Some(p) => p,
271 None => alloc::alloc::handle_alloc_error(layout),
272 }
273 };
274 let out = PtrUninit::new(ptr.as_ptr());
275 let popped = unsafe { pop_fn(self.value.data_mut(), out) };
276 if !popped {
277 if layout.size() != 0 {
278 unsafe { alloc::alloc::dealloc(ptr.as_ptr(), layout) };
279 }
280 return Ok(None);
281 }
282 self.len -= 1;
283 Ok(Some(HeapValue {
284 guard: Some(Guard {
285 ptr,
286 layout,
287 should_dealloc: layout.size() != 0,
288 }),
289 shape: elem_shape,
290 phantom: PhantomData,
291 }))
292 }
293
294 pub fn swap(&mut self, a: usize, b: usize) -> Result<(), ReflectError> {
302 let len = self.len;
303 if a >= len || b >= len {
304 let out_of_bounds = if a >= len { a } else { b };
305 return Err(self.err(ReflectErrorKind::FieldError {
306 shape: self.value.shape(),
307 field_error: FieldError::IndexOutOfBounds {
308 index: out_of_bounds,
309 bound: len,
310 },
311 }));
312 }
313 if a == b {
314 return Ok(());
315 }
316
317 match self.def {
318 ListLikeDef::List(def) => {
319 let swap_fn = def.vtable.swap.ok_or_else(|| {
320 self.err(ReflectErrorKind::OperationFailed {
321 shape: self.value.shape(),
322 operation: "swap: list type does not support swap",
323 })
324 })?;
325 let ok = unsafe { swap_fn(self.value.data_mut(), a, b, self.value.shape()) };
326 if !ok {
327 return Err(self.err(ReflectErrorKind::OperationFailed {
328 shape: self.value.shape(),
329 operation: "swap: vtable refused the operation",
330 }));
331 }
332 Ok(())
333 }
334 ListLikeDef::Array(def) => {
335 let elem_size = match self.def.t().layout {
336 ShapeLayout::Sized(l) => l.size(),
337 ShapeLayout::Unsized => {
338 return Err(self.err(ReflectErrorKind::Unsized {
339 shape: self.def.t(),
340 operation: "swap",
341 }));
342 }
343 };
344 unsafe {
345 let base = (def.vtable.as_mut_ptr)(self.value.data_mut());
346 let pa = base.field(a * elem_size);
347 let pb = base.field(b * elem_size);
348 core::ptr::swap_nonoverlapping(
349 pa.as_mut_byte_ptr(),
350 pb.as_mut_byte_ptr(),
351 elem_size,
352 );
353 }
354 Ok(())
355 }
356 ListLikeDef::Slice(def) => {
357 let elem_size = match self.def.t().layout {
358 ShapeLayout::Sized(l) => l.size(),
359 ShapeLayout::Unsized => {
360 return Err(self.err(ReflectErrorKind::Unsized {
361 shape: self.def.t(),
362 operation: "swap",
363 }));
364 }
365 };
366 unsafe {
367 let base = (def.vtable.as_mut_ptr)(self.value.data_mut());
368 let pa = base.field(a * elem_size);
369 let pb = base.field(b * elem_size);
370 core::ptr::swap_nonoverlapping(
371 pa.as_mut_byte_ptr(),
372 pb.as_mut_byte_ptr(),
373 elem_size,
374 );
375 }
376 Ok(())
377 }
378 }
379 }
380
381 #[inline]
384 fn push_fn(&self) -> Result<facet_core::ListPushFn, ReflectError> {
385 match self.def {
386 ListLikeDef::List(def) => def.push().ok_or_else(|| {
387 self.err(ReflectErrorKind::OperationFailed {
388 shape: self.value.shape(),
389 operation: "push: list type does not support push",
390 })
391 }),
392 _ => Err(self.err(ReflectErrorKind::OperationFailed {
393 shape: self.value.shape(),
394 operation: "push: only list-backed list-likes support push",
395 })),
396 }
397 }
398
399 #[inline]
401 pub fn into_inner(self) -> Poke<'mem, 'facet> {
402 self.value
403 }
404
405 #[inline]
407 pub fn as_peek_list_like(&self) -> crate::PeekListLike<'_, 'facet> {
408 unsafe { crate::PeekListLike::new(self.value.as_peek(), self.def) }
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use alloc::vec::Vec;
415
416 use super::*;
417
418 #[test]
419 fn poke_list_like_vec_len_and_get_mut() {
420 let mut v: Vec<i32> = alloc::vec![1, 2, 3];
421 let poke = Poke::new(&mut v);
422 let mut ll = poke.into_list_like().unwrap();
423 assert_eq!(ll.len(), 3);
424
425 {
426 let mut item = ll.get_mut(1).unwrap();
427 item.set(200i32).unwrap();
428 }
429 assert_eq!(v, alloc::vec![1, 200, 3]);
430 }
431
432 #[test]
433 fn poke_list_like_array_get_mut() {
434 let mut arr: [i32; 3] = [10, 20, 30];
435 let poke = Poke::new(&mut arr);
436 let mut ll = poke.into_list_like().unwrap();
437 assert_eq!(ll.len(), 3);
438
439 {
440 let mut item = ll.get_mut(0).unwrap();
441 item.set(99i32).unwrap();
442 }
443 assert_eq!(arr, [99, 20, 30]);
444 }
445
446 #[test]
447 fn poke_list_like_iter_mut() {
448 let mut v: Vec<i32> = alloc::vec![1, 2, 3];
449 let poke = Poke::new(&mut v);
450 let ll = poke.into_list_like().unwrap();
451 for mut item in ll.iter_mut().unwrap() {
452 let cur = *item.get::<i32>().unwrap();
453 item.set(cur * 10).unwrap();
454 }
455 assert_eq!(v, alloc::vec![10, 20, 30]);
456 }
457
458 #[test]
459 fn poke_list_like_vec_push_pop() {
460 let mut v: Vec<i32> = alloc::vec![];
461 {
462 let poke = Poke::new(&mut v);
463 let mut ll = poke.into_list_like().unwrap();
464 ll.push(10i32).unwrap();
465 ll.push(20i32).unwrap();
466 assert_eq!(ll.len(), 2);
467 let popped = ll.pop().unwrap().unwrap();
468 assert_eq!(popped.materialize::<i32>().unwrap(), 20);
469 assert_eq!(ll.len(), 1);
470 }
471 assert_eq!(v, alloc::vec![10]);
472 }
473
474 #[test]
475 fn poke_list_like_array_push_fails() {
476 let mut arr: [i32; 3] = [1, 2, 3];
477 let poke = Poke::new(&mut arr);
478 let mut ll = poke.into_list_like().unwrap();
479 let res = ll.push(4i32);
480 assert!(matches!(
481 res,
482 Err(ref err) if matches!(err.kind, ReflectErrorKind::OperationFailed { .. })
483 ));
484 }
485
486 #[test]
487 fn poke_list_like_array_pop_fails() {
488 let mut arr: [i32; 3] = [1, 2, 3];
489 let poke = Poke::new(&mut arr);
490 let mut ll = poke.into_list_like().unwrap();
491 let res = ll.pop();
492 assert!(matches!(
493 res,
494 Err(ref err) if matches!(err.kind, ReflectErrorKind::OperationFailed { .. })
495 ));
496 }
497
498 #[test]
499 fn poke_list_like_vec_swap() {
500 let mut v: Vec<i32> = alloc::vec![1, 2, 3];
501 let poke = Poke::new(&mut v);
502 let mut ll = poke.into_list_like().unwrap();
503 ll.swap(0, 2).unwrap();
504 assert_eq!(v, alloc::vec![3, 2, 1]);
505 }
506
507 #[test]
508 fn poke_list_like_array_swap() {
509 let mut arr: [i32; 3] = [10, 20, 30];
510 let poke = Poke::new(&mut arr);
511 let mut ll = poke.into_list_like().unwrap();
512 ll.swap(0, 2).unwrap();
513 assert_eq!(arr, [30, 20, 10]);
514 }
515
516 #[test]
517 fn poke_list_like_swap_out_of_bounds_fails() {
518 let mut v: Vec<i32> = alloc::vec![1, 2, 3];
519 let poke = Poke::new(&mut v);
520 let mut ll = poke.into_list_like().unwrap();
521 let res = ll.swap(5, 0);
522 assert!(matches!(
523 res,
524 Err(ref err) if matches!(err.kind, ReflectErrorKind::FieldError { .. })
525 ));
526 }
527}