1use facet_core::{IterVTable, PtrConst, PtrMut, Shape, ShapeLayout};
2
3use super::Peek;
4use core::{fmt::Debug, marker::PhantomData};
5
6#[derive(Clone, Copy)]
8pub enum ListLikeDef<'shape> {
9 List(facet_core::ListDef<'shape>),
13
14 Array(facet_core::ArrayDef<'shape>),
18
19 Slice(facet_core::SliceDef<'shape>),
23}
24
25impl<'shape> ListLikeDef<'shape> {
26 pub fn t(&self) -> &'shape Shape<'shape> {
28 match self {
29 ListLikeDef::List(v) => v.t(),
30 ListLikeDef::Array(v) => v.t(),
31 ListLikeDef::Slice(v) => v.t(),
32 }
33 }
34}
35
36pub struct PeekListLikeIter<'mem, 'facet, 'shape> {
38 state: PeekListLikeIterState<'mem>,
39 index: usize,
40 len: usize,
41 def: ListLikeDef<'shape>,
42 _list: PhantomData<Peek<'mem, 'facet, 'shape>>,
43}
44
45impl<'mem, 'facet, 'shape> Iterator for PeekListLikeIter<'mem, 'facet, 'shape> {
46 type Item = Peek<'mem, 'facet, 'shape>;
47
48 fn next(&mut self) -> Option<Self::Item> {
49 let item_ptr = match self.state {
50 PeekListLikeIterState::Ptr { data, stride } => {
51 if self.index >= self.len {
52 return None;
53 }
54
55 unsafe { data.field(stride * self.index) }
56 }
57 PeekListLikeIterState::Iter { iter, vtable } => unsafe { (vtable.next)(iter)? },
58 };
59
60 self.index += 1;
63
64 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
65 }
66
67 fn size_hint(&self) -> (usize, Option<usize>) {
68 let remaining = self.len.saturating_sub(self.index);
69 (remaining, Some(remaining))
70 }
71}
72
73impl<'mem, 'facet, 'shape> ExactSizeIterator for PeekListLikeIter<'mem, 'facet, 'shape> {}
74
75impl<'mem, 'facet, 'shape> IntoIterator for &'mem PeekListLike<'mem, 'facet, 'shape> {
76 type Item = Peek<'mem, 'facet, 'shape>;
77 type IntoIter = PeekListLikeIter<'mem, 'facet, 'shape>;
78
79 fn into_iter(self) -> Self::IntoIter {
80 self.iter()
81 }
82}
83
84enum PeekListLikeIterState<'mem> {
85 Ptr {
86 data: PtrConst<'mem>,
87 stride: usize,
88 },
89 Iter {
90 iter: PtrMut<'mem>,
91 vtable: IterVTable<PtrConst<'static>>,
92 },
93}
94
95impl Drop for PeekListLikeIterState<'_> {
96 fn drop(&mut self) {
97 match self {
98 Self::Iter { iter, vtable } => unsafe { (vtable.dealloc)(*iter) },
99 Self::Ptr { .. } => {
100 }
102 }
103 }
104}
105
106#[derive(Clone, Copy)]
108pub struct PeekListLike<'mem, 'facet, 'shape> {
109 pub(crate) value: Peek<'mem, 'facet, 'shape>,
110 pub(crate) def: ListLikeDef<'shape>,
111 len: usize,
112}
113
114impl<'mem, 'facet, 'shape> Debug for PeekListLike<'mem, 'facet, 'shape> {
115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116 f.debug_struct("PeekListLike").finish_non_exhaustive()
117 }
118}
119
120impl<'mem, 'facet, 'shape> PeekListLike<'mem, 'facet, 'shape> {
121 pub fn new(value: Peek<'mem, 'facet, 'shape>, def: ListLikeDef<'shape>) -> Self {
123 let len = match def {
124 ListLikeDef::List(v) => unsafe { (v.vtable.len)(value.data()) },
125 ListLikeDef::Slice(v) => unsafe { (v.vtable.len)(value.data()) },
126 ListLikeDef::Array(v) => v.n,
127 };
128 Self { value, def, len }
129 }
130
131 pub fn len(&self) -> usize {
133 self.len
134 }
135
136 pub fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140
141 pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet, 'shape>> {
147 let as_ptr = match self.def {
148 ListLikeDef::List(def) => {
149 let item = unsafe { (def.vtable.get)(self.value.data(), index)? };
151 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
152 }
153 ListLikeDef::Array(def) => def.vtable.as_ptr,
154 ListLikeDef::Slice(def) => def.vtable.as_ptr,
155 };
156
157 if index >= self.len() {
158 return None;
159 }
160
161 let base_ptr = unsafe { as_ptr(self.value.data()) };
163
164 let elem_layout = match self.def.t().layout {
166 ShapeLayout::Sized(layout) => layout,
167 ShapeLayout::Unsized => return None, };
169
170 let offset = index * elem_layout.size();
172
173 let item_ptr = unsafe { base_ptr.field(offset) };
175
176 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
177 }
178
179 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet, 'shape> {
181 let (as_ptr_fn, iter_vtable) = match self.def {
182 ListLikeDef::List(def) => (def.vtable.as_ptr, Some(def.vtable.iter_vtable)),
183 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
184 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
185 };
186
187 let state = match (as_ptr_fn, iter_vtable) {
188 (Some(as_ptr_fn), _) => {
189 let data = unsafe { as_ptr_fn(self.value.data()) };
190 let layout = self
191 .def
192 .t()
193 .layout
194 .sized_layout()
195 .expect("can only iterate over sized list elements");
196 let stride = layout.size();
197
198 PeekListLikeIterState::Ptr { data, stride }
199 }
200 (None, Some(vtable)) => {
201 let iter = unsafe { (vtable.init_with_value.unwrap())(self.value.data()) };
202 PeekListLikeIterState::Iter { iter, vtable }
203 }
204 (None, None) => unreachable!(),
205 };
206
207 PeekListLikeIter {
208 state,
209 index: 0,
210 len: self.len(),
211 def: self.def(),
212 _list: PhantomData,
213 }
214 }
215
216 pub fn def(&self) -> ListLikeDef<'shape> {
218 self.def
219 }
220}