1use facet_core::{GenericPtr, IterVTable, PtrConst, PtrMut, Shape, ShapeLayout};
2
3use super::Peek;
4use core::{fmt::Debug, marker::PhantomData};
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().thin().unwrap()) },
131 ListLikeDef::Slice(v) => {
132 match value.data() {
135 GenericPtr::Wide(wide_ptr) => {
136 let slice_as_units = unsafe { wide_ptr.get::<[()]>() };
139 slice_as_units.len()
140 }
141 GenericPtr::Thin(thin_ptr) => {
142 unsafe { (v.vtable.len)(thin_ptr) }
144 }
145 }
146 }
147 ListLikeDef::Array(v) => v.n,
148 };
149 Self { value, def, len }
150 }
151
152 #[inline]
154 pub fn len(&self) -> usize {
155 self.len
156 }
157
158 #[inline]
160 pub fn is_empty(&self) -> bool {
161 self.len() == 0
162 }
163
164 pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
168 if let (ListLikeDef::Slice(_), GenericPtr::Wide(wide_ptr)) = (&self.def, self.value.data())
170 {
171 if index >= self.len() {
172 return None;
173 }
174
175 let elem_layout = match self.def.t().layout {
177 ShapeLayout::Sized(layout) => layout,
178 ShapeLayout::Unsized => return None,
179 };
180
181 let data_ptr = wide_ptr.as_byte_ptr();
183
184 let elem_ptr = unsafe { data_ptr.add(index * elem_layout.size()) };
186
187 return Some(unsafe {
189 Peek::unchecked_new(GenericPtr::Thin(PtrConst::new(elem_ptr)), self.def.t())
190 });
191 }
192
193 let as_ptr = match self.def {
194 ListLikeDef::List(def) => {
195 let item = unsafe { (def.vtable.get)(self.value.data().thin().unwrap(), index)? };
197 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
198 }
199 ListLikeDef::Array(def) => def.vtable.as_ptr,
200 ListLikeDef::Slice(def) => def.vtable.as_ptr,
201 };
202
203 if index >= self.len() {
204 return None;
205 }
206
207 let base_ptr = unsafe { as_ptr(self.value.data().thin().unwrap()) };
209
210 let elem_layout = match self.def.t().layout {
212 ShapeLayout::Sized(layout) => layout,
213 ShapeLayout::Unsized => return None, };
215
216 let offset = index * elem_layout.size();
218
219 let item_ptr = unsafe { base_ptr.field(offset) };
221
222 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
223 }
224
225 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet> {
227 let (as_ptr_fn, iter_vtable) = match self.def {
228 ListLikeDef::List(def) => (def.vtable.as_ptr, Some(def.vtable.iter_vtable)),
229 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
230 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
231 };
232
233 let state = match (as_ptr_fn, iter_vtable) {
234 (Some(as_ptr_fn), _) => {
235 let data = if let (ListLikeDef::Slice(_), GenericPtr::Wide(wide_ptr)) =
237 (&self.def, self.value.data())
238 {
239 PtrConst::new(wide_ptr.as_byte_ptr())
241 } else {
242 unsafe { as_ptr_fn(self.value.data().thin().unwrap()) }
243 };
244
245 let layout = self
246 .def
247 .t()
248 .layout
249 .sized_layout()
250 .expect("can only iterate over sized list elements");
251 let stride = layout.size();
252
253 PeekListLikeIterState::Ptr { data, stride }
254 }
255 (None, Some(vtable)) => {
256 let iter =
257 unsafe { (vtable.init_with_value.unwrap())(self.value.data().thin().unwrap()) };
258 PeekListLikeIterState::Iter { iter, vtable }
259 }
260 (None, None) => unreachable!(),
261 };
262
263 PeekListLikeIter {
264 state,
265 index: 0,
266 len: self.len(),
267 def: self.def(),
268 _list: PhantomData,
269 }
270 }
271
272 #[inline]
274 pub fn def(&self) -> ListLikeDef {
275 self.def
276 }
277}