1use facet_core::{IterVTable, PtrConst, PtrMut, Shape, ShapeLayout};
2
3use super::Peek;
4use core::{fmt::Debug, marker::PhantomData, ptr::NonNull};
5
6#[derive(Clone, Copy)]
8pub enum ListLikeDef {
9 List(facet_core::ListDef),
13
14 Array(facet_core::ArrayDef),
18
19 Slice(facet_core::SliceDef),
23}
24
25impl ListLikeDef {
26 #[inline]
28 pub fn t(&self) -> &'static Shape {
29 match self {
30 ListLikeDef::List(v) => v.t(),
31 ListLikeDef::Array(v) => v.t(),
32 ListLikeDef::Slice(v) => v.t(),
33 }
34 }
35}
36
37pub struct PeekListLikeIter<'mem, 'facet> {
39 state: PeekListLikeIterState<'mem>,
40 index: usize,
41 len: usize,
42 def: ListLikeDef,
43 _list: PhantomData<Peek<'mem, 'facet>>,
44}
45
46impl<'mem, 'facet> Iterator for PeekListLikeIter<'mem, 'facet> {
47 type Item = Peek<'mem, 'facet>;
48
49 #[inline]
50 fn next(&mut self) -> Option<Self::Item> {
51 let item_ptr = match &self.state.kind {
52 PeekListLikeIterStateKind::Ptr { data, stride } => {
53 if self.index >= self.len {
54 return None;
55 }
56
57 unsafe { data.field(stride * self.index) }
58 }
59 PeekListLikeIterStateKind::Iter { iter, vtable } => unsafe { (vtable.next)(*iter)? },
60 };
61
62 self.index += 1;
65
66 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
67 }
68
69 #[inline]
70 fn size_hint(&self) -> (usize, Option<usize>) {
71 let remaining = self.len.saturating_sub(self.index);
72 (remaining, Some(remaining))
73 }
74}
75
76impl<'mem, 'facet> ExactSizeIterator for PeekListLikeIter<'mem, 'facet> {}
77
78impl<'mem, 'facet> IntoIterator for &'mem PeekListLike<'mem, 'facet> {
79 type Item = Peek<'mem, 'facet>;
80 type IntoIter = PeekListLikeIter<'mem, 'facet>;
81
82 #[inline]
83 fn into_iter(self) -> Self::IntoIter {
84 self.iter()
85 }
86}
87
88struct PeekListLikeIterState<'mem> {
89 kind: PeekListLikeIterStateKind,
90 _phantom: PhantomData<&'mem ()>,
91}
92
93enum PeekListLikeIterStateKind {
94 Ptr {
95 data: PtrConst,
96 stride: usize,
97 },
98 Iter {
99 iter: PtrMut,
100 vtable: &'static IterVTable<PtrConst>,
101 },
102}
103
104impl Drop for PeekListLikeIterState<'_> {
105 #[inline]
106 fn drop(&mut self) {
107 match &self.kind {
108 PeekListLikeIterStateKind::Iter { iter, vtable } => unsafe { (vtable.dealloc)(*iter) },
109 PeekListLikeIterStateKind::Ptr { .. } => {
110 }
112 }
113 }
114}
115
116#[derive(Clone, Copy)]
118pub struct PeekListLike<'mem, 'facet> {
119 pub(crate) value: Peek<'mem, 'facet>,
120 pub(crate) def: ListLikeDef,
121 len: usize,
122}
123
124impl<'mem, 'facet> Debug for PeekListLike<'mem, 'facet> {
125 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
126 f.debug_struct("PeekListLike").finish_non_exhaustive()
127 }
128}
129
130impl<'mem, 'facet> PeekListLike<'mem, 'facet> {
131 #[inline]
143 pub unsafe fn new(value: Peek<'mem, 'facet>, def: ListLikeDef) -> Self {
144 let len = match def {
145 ListLikeDef::List(v) => unsafe { (v.vtable.len)(value.data()) },
146 ListLikeDef::Slice(_) => {
147 let slice_as_units = unsafe { value.data.get::<[()]>() };
148 slice_as_units.len()
149 }
150 ListLikeDef::Array(v) => v.n,
151 };
152 Self { value, def, len }
153 }
154
155 #[inline]
157 pub fn len(&self) -> usize {
158 self.len
159 }
160
161 #[inline]
163 pub fn is_empty(&self) -> bool {
164 self.len() == 0
165 }
166
167 pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
171 if let ListLikeDef::Slice(_) = &self.def {
173 if index >= self.len() {
174 return None;
175 }
176
177 let elem_layout = match self.def.t().layout {
179 ShapeLayout::Sized(layout) => layout,
180 ShapeLayout::Unsized => return None,
181 };
182
183 let data_ptr = self.value.data().raw_ptr();
185
186 let elem_ptr = unsafe { data_ptr.add(index * elem_layout.size()) };
188
189 return Some(unsafe {
191 Peek::unchecked_new(
192 PtrConst::new(NonNull::new_unchecked(elem_ptr as *mut u8).as_ptr()),
193 self.def.t(),
194 )
195 });
196 }
197
198 let as_ptr = match self.def {
199 ListLikeDef::List(def) => {
200 let item =
202 unsafe { (def.vtable.get)(self.value.data(), index, self.value.shape())? };
203 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
204 }
205 ListLikeDef::Array(def) => def.vtable.as_ptr,
206 ListLikeDef::Slice(def) => def.vtable.as_ptr,
207 };
208
209 if index >= self.len() {
210 return None;
211 }
212
213 let base_ptr = unsafe { as_ptr(self.value.data()) };
215
216 let elem_layout = match self.def.t().layout {
218 ShapeLayout::Sized(layout) => layout,
219 ShapeLayout::Unsized => return None, };
221
222 let offset = index * elem_layout.size();
224
225 let item_ptr = unsafe { base_ptr.field(offset) };
227
228 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
229 }
230
231 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet> {
233 let (as_ptr_fn, iter_vtable) = match self.def {
234 ListLikeDef::List(def) => (def.vtable.as_ptr, def.iter_vtable()),
235 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
236 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
237 };
238
239 let state = match (as_ptr_fn, iter_vtable) {
240 (Some(as_ptr_fn), _) => {
241 let data = if let ListLikeDef::Slice(_) = &self.def {
243 PtrConst::new(unsafe {
245 NonNull::new_unchecked(self.value.data().raw_ptr() as *mut u8).as_ptr()
246 })
247 } else {
248 unsafe { as_ptr_fn(self.value.data()) }
249 };
250
251 let layout = self
252 .def
253 .t()
254 .layout
255 .sized_layout()
256 .expect("can only iterate over sized list elements");
257 let stride = layout.size();
258
259 PeekListLikeIterState {
260 kind: PeekListLikeIterStateKind::Ptr { data, stride },
261 _phantom: PhantomData,
262 }
263 }
264 (None, Some(vtable)) => {
265 let iter = unsafe { (vtable.init_with_value.unwrap())(self.value.data()) };
266 PeekListLikeIterState {
267 kind: PeekListLikeIterStateKind::Iter { iter, vtable },
268 _phantom: PhantomData,
269 }
270 }
271 (None, None) => unreachable!(),
272 };
273
274 PeekListLikeIter {
275 state,
276 index: 0,
277 len: self.len(),
278 def: self.def(),
279 _list: PhantomData,
280 }
281 }
282
283 #[inline]
285 pub fn def(&self) -> ListLikeDef {
286 self.def
287 }
288}