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 {
52 PeekListLikeIterState::Ptr { data, stride } => {
53 if self.index >= self.len {
54 return None;
55 }
56
57 unsafe { data.field(stride * self.index) }
58 }
59 PeekListLikeIterState::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
88enum PeekListLikeIterState<'mem> {
89 Ptr {
90 data: PtrConst<'mem>,
91 stride: usize,
92 },
93 Iter {
94 iter: PtrMut<'mem>,
95 vtable: IterVTable<PtrConst<'static>>,
96 },
97}
98
99impl Drop for PeekListLikeIterState<'_> {
100 #[inline]
101 fn drop(&mut self) {
102 match self {
103 Self::Iter { iter, vtable } => unsafe { (vtable.dealloc)(*iter) },
104 Self::Ptr { .. } => {
105 }
107 }
108 }
109}
110
111#[derive(Clone, Copy)]
113pub struct PeekListLike<'mem, 'facet> {
114 pub(crate) value: Peek<'mem, 'facet>,
115 pub(crate) def: ListLikeDef,
116 len: usize,
117}
118
119impl<'mem, 'facet> Debug for PeekListLike<'mem, 'facet> {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 f.debug_struct("PeekListLike").finish_non_exhaustive()
122 }
123}
124
125impl<'mem, 'facet> PeekListLike<'mem, 'facet> {
126 #[inline]
128 pub fn new(value: Peek<'mem, 'facet>, def: ListLikeDef) -> Self {
129 let len = match def {
130 ListLikeDef::List(v) => unsafe { (v.vtable.len)(value.data()) },
131 ListLikeDef::Slice(_) => {
132 let slice_as_units = unsafe { value.data.get::<[()]>() };
133 slice_as_units.len()
134 }
135 ListLikeDef::Array(v) => v.n,
136 };
137 Self { value, def, len }
138 }
139
140 #[inline]
142 pub fn len(&self) -> usize {
143 self.len
144 }
145
146 #[inline]
148 pub fn is_empty(&self) -> bool {
149 self.len() == 0
150 }
151
152 pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
156 if let ListLikeDef::Slice(_) = &self.def {
158 if index >= self.len() {
159 return None;
160 }
161
162 let elem_layout = match self.def.t().layout {
164 ShapeLayout::Sized(layout) => layout,
165 ShapeLayout::Unsized => return None,
166 };
167
168 let data_ptr = self.value.data().as_byte_ptr();
170
171 let elem_ptr = unsafe { data_ptr.add(index * elem_layout.size()) };
173
174 return Some(unsafe {
176 Peek::unchecked_new(
177 PtrConst::new(NonNull::new_unchecked(elem_ptr as *mut u8)),
178 self.def.t(),
179 )
180 });
181 }
182
183 let as_ptr = match self.def {
184 ListLikeDef::List(def) => {
185 let item = unsafe { (def.vtable.get)(self.value.data(), index)? };
187 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
188 }
189 ListLikeDef::Array(def) => def.vtable.as_ptr,
190 ListLikeDef::Slice(def) => def.vtable.as_ptr,
191 };
192
193 if index >= self.len() {
194 return None;
195 }
196
197 let base_ptr = unsafe { as_ptr(self.value.data()) };
199
200 let elem_layout = match self.def.t().layout {
202 ShapeLayout::Sized(layout) => layout,
203 ShapeLayout::Unsized => return None, };
205
206 let offset = index * elem_layout.size();
208
209 let item_ptr = unsafe { base_ptr.field(offset) };
211
212 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
213 }
214
215 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet> {
217 let (as_ptr_fn, iter_vtable) = match self.def {
218 ListLikeDef::List(def) => (def.vtable.as_ptr, Some(def.vtable.iter_vtable)),
219 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
220 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
221 };
222
223 let state = match (as_ptr_fn, iter_vtable) {
224 (Some(as_ptr_fn), _) => {
225 let data = if let ListLikeDef::Slice(_) = &self.def {
227 PtrConst::new(unsafe {
229 NonNull::new_unchecked(self.value.data().as_byte_ptr() as *mut u8)
230 })
231 } else {
232 unsafe { as_ptr_fn(self.value.data()) }
233 };
234
235 let layout = self
236 .def
237 .t()
238 .layout
239 .sized_layout()
240 .expect("can only iterate over sized list elements");
241 let stride = layout.size();
242
243 PeekListLikeIterState::Ptr { data, stride }
244 }
245 (None, Some(vtable)) => {
246 let iter = unsafe { (vtable.init_with_value.unwrap())(self.value.data()) };
247 PeekListLikeIterState::Iter { iter, vtable }
248 }
249 (None, None) => unreachable!(),
250 };
251
252 PeekListLikeIter {
253 state,
254 index: 0,
255 len: self.len(),
256 def: self.def(),
257 _list: PhantomData,
258 }
259 }
260
261 #[inline]
263 pub fn def(&self) -> ListLikeDef {
264 self.def
265 }
266}