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().thin().unwrap()) },
125 ListLikeDef::Slice(v) => unsafe { (v.vtable.len)(value.data().thin().unwrap()) },
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>> {
145 let as_ptr = match self.def {
146 ListLikeDef::List(def) => {
147 let item = unsafe { (def.vtable.get)(self.value.data().thin().unwrap(), index)? };
149 return Some(unsafe { Peek::unchecked_new(item, self.def.t()) });
150 }
151 ListLikeDef::Array(def) => def.vtable.as_ptr,
152 ListLikeDef::Slice(def) => def.vtable.as_ptr,
153 };
154
155 if index >= self.len() {
156 return None;
157 }
158
159 let base_ptr = unsafe { as_ptr(self.value.data().thin().unwrap()) };
161
162 let elem_layout = match self.def.t().layout {
164 ShapeLayout::Sized(layout) => layout,
165 ShapeLayout::Unsized => return None, };
167
168 let offset = index * elem_layout.size();
170
171 let item_ptr = unsafe { base_ptr.field(offset) };
173
174 Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
175 }
176
177 pub fn iter(self) -> PeekListLikeIter<'mem, 'facet, 'shape> {
179 let (as_ptr_fn, iter_vtable) = match self.def {
180 ListLikeDef::List(def) => (def.vtable.as_ptr, Some(def.vtable.iter_vtable)),
181 ListLikeDef::Array(def) => (Some(def.vtable.as_ptr), None),
182 ListLikeDef::Slice(def) => (Some(def.vtable.as_ptr), None),
183 };
184
185 let state = match (as_ptr_fn, iter_vtable) {
186 (Some(as_ptr_fn), _) => {
187 let data = unsafe { as_ptr_fn(self.value.data().thin().unwrap()) };
188 let layout = self
189 .def
190 .t()
191 .layout
192 .sized_layout()
193 .expect("can only iterate over sized list elements");
194 let stride = layout.size();
195
196 PeekListLikeIterState::Ptr { data, stride }
197 }
198 (None, Some(vtable)) => {
199 let iter =
200 unsafe { (vtable.init_with_value.unwrap())(self.value.data().thin().unwrap()) };
201 PeekListLikeIterState::Iter { iter, vtable }
202 }
203 (None, None) => unreachable!(),
204 };
205
206 PeekListLikeIter {
207 state,
208 index: 0,
209 len: self.len(),
210 def: self.def(),
211 _list: PhantomData,
212 }
213 }
214
215 pub fn def(&self) -> ListLikeDef<'shape> {
217 self.def
218 }
219}