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]
133 pub fn new(value: Peek<'mem, 'facet>, def: ListLikeDef) -> Self {
134 let len = match def {
135 ListLikeDef::List(v) => unsafe { (v.vtable.len)(value.data()) },
136 ListLikeDef::Slice(_) => {
137 let slice_as_units = unsafe { value.data.get::<[()]>() };
138 slice_as_units.len()
139 }
140 ListLikeDef::Array(v) => v.n,
141 };
142 Self { value, def, len }
143 }
144
145 #[inline]
147 pub fn len(&self) -> usize {
148 self.len
149 }
150
151 #[inline]
153 pub fn is_empty(&self) -> bool {
154 self.len() == 0
155 }
156
157 pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
161 if let ListLikeDef::Slice(_) = &self.def {
163 if index >= self.len() {
164 return None;
165 }
166
167 let elem_layout = match self.def.t().layout {
169 ShapeLayout::Sized(layout) => layout,
170 ShapeLayout::Unsized => return None,
171 };
172
173 let data_ptr = self.value.data().raw_ptr();
175
176 let elem_ptr = unsafe { data_ptr.add(index * elem_layout.size()) };
178
179 return Some(unsafe {
181 Peek::unchecked_new(
182 PtrConst::new(NonNull::new_unchecked(elem_ptr as *mut u8).as_ptr()),
183 self.def.t(),
184 )
185 });
186 }
187
188 let as_ptr = match self.def {
189 ListLikeDef::List(def) => {
190 let item =
192 unsafe { (def.vtable.get)(self.value.data(), index, self.value.shape())? };
193 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
194 }
195 ListLikeDef::Array(def) => def.vtable.as_ptr,
196 ListLikeDef::Slice(def) => def.vtable.as_ptr,
197 };
198
199 if index >= self.len() {
200 return None;
201 }
202
203 let base_ptr = unsafe { as_ptr(self.value.data()) };
205
206 let elem_layout = match self.def.t().layout {
208 ShapeLayout::Sized(layout) => layout,
209 ShapeLayout::Unsized => return None, };
211
212 let offset = index * elem_layout.size();
214
215 let item_ptr = unsafe { base_ptr.field(offset) };
217
218 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
219 }
220
221 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet> {
223 let (as_ptr_fn, iter_vtable) = match self.def {
224 ListLikeDef::List(def) => (def.vtable.as_ptr, def.iter_vtable()),
225 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
226 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
227 };
228
229 let state = match (as_ptr_fn, iter_vtable) {
230 (Some(as_ptr_fn), _) => {
231 let data = if let ListLikeDef::Slice(_) = &self.def {
233 PtrConst::new(unsafe {
235 NonNull::new_unchecked(self.value.data().raw_ptr() as *mut u8).as_ptr()
236 })
237 } else {
238 unsafe { as_ptr_fn(self.value.data()) }
239 };
240
241 let layout = self
242 .def
243 .t()
244 .layout
245 .sized_layout()
246 .expect("can only iterate over sized list elements");
247 let stride = layout.size();
248
249 PeekListLikeIterState {
250 kind: PeekListLikeIterStateKind::Ptr { data, stride },
251 _phantom: PhantomData,
252 }
253 }
254 (None, Some(vtable)) => {
255 let iter = unsafe { (vtable.init_with_value.unwrap())(self.value.data()) };
256 PeekListLikeIterState {
257 kind: PeekListLikeIterStateKind::Iter { iter, vtable },
258 _phantom: PhantomData,
259 }
260 }
261 (None, None) => unreachable!(),
262 };
263
264 PeekListLikeIter {
265 state,
266 index: 0,
267 len: self.len(),
268 def: self.def(),
269 _list: PhantomData,
270 }
271 }
272
273 #[inline]
275 pub fn def(&self) -> ListLikeDef {
276 self.def
277 }
278}