facet_reflect/peek/
list.rs

1use super::Peek;
2use core::{fmt::Debug, marker::PhantomData};
3use facet_core::{ListDef, PtrConst, PtrMut};
4
5/// Iterator over a `PeekList`
6pub struct PeekListIter<'mem, 'facet> {
7    state: PeekListIterState<'mem>,
8    index: usize,
9    len: usize,
10    def: ListDef,
11    _list: PhantomData<Peek<'mem, 'facet>>,
12}
13
14impl<'mem, 'facet> Iterator for PeekListIter<'mem, 'facet> {
15    type Item = Peek<'mem, 'facet>;
16
17    #[inline]
18    fn next(&mut self) -> Option<Self::Item> {
19        let item_ptr = match &self.state.kind {
20            PeekListIterStateKind::Ptr { data, stride } => {
21                if self.index >= self.len {
22                    return None;
23                }
24
25                unsafe { data.field(stride * self.index) }
26            }
27            PeekListIterStateKind::Iter { iter } => unsafe {
28                (self.def.iter_vtable().unwrap().next)(*iter)?
29            },
30        };
31
32        // Update the index. This is used pointer iteration and for
33        // calculating the iterator's size
34        self.index += 1;
35
36        Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
37    }
38
39    #[inline]
40    fn size_hint(&self) -> (usize, Option<usize>) {
41        let remaining = self.len.saturating_sub(self.index);
42        (remaining, Some(remaining))
43    }
44}
45
46impl ExactSizeIterator for PeekListIter<'_, '_> {}
47
48impl Drop for PeekListIter<'_, '_> {
49    #[inline]
50    fn drop(&mut self) {
51        match &self.state.kind {
52            PeekListIterStateKind::Iter { iter } => unsafe {
53                (self.def.iter_vtable().unwrap().dealloc)(*iter)
54            },
55            PeekListIterStateKind::Ptr { .. } => {
56                // Nothing to do
57            }
58        }
59    }
60}
61
62impl<'mem, 'facet> IntoIterator for &'mem PeekList<'mem, 'facet> {
63    type Item = Peek<'mem, 'facet>;
64    type IntoIter = PeekListIter<'mem, 'facet>;
65
66    #[inline]
67    fn into_iter(self) -> Self::IntoIter {
68        self.iter()
69    }
70}
71
72struct PeekListIterState<'mem> {
73    kind: PeekListIterStateKind,
74    _phantom: PhantomData<&'mem ()>,
75}
76
77enum PeekListIterStateKind {
78    Ptr { data: PtrConst, stride: usize },
79    Iter { iter: PtrMut },
80}
81
82/// Lets you read from a list (implements read-only [`facet_core::ListVTable`] proxies)
83#[derive(Clone, Copy)]
84pub struct PeekList<'mem, 'facet> {
85    pub(crate) value: Peek<'mem, 'facet>,
86    pub(crate) def: ListDef,
87}
88
89impl Debug for PeekList<'_, '_> {
90    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91        f.debug_struct("PeekList").finish_non_exhaustive()
92    }
93}
94
95impl<'mem, 'facet> PeekList<'mem, 'facet> {
96    /// Creates a new peek list
97    #[inline]
98    pub fn new(value: Peek<'mem, 'facet>, def: ListDef) -> Self {
99        Self { value, def }
100    }
101
102    /// Get the length of the list
103    #[inline]
104    pub fn len(&self) -> usize {
105        unsafe { (self.def.vtable.len)(self.value.data()) }
106    }
107
108    /// Returns true if the list is empty
109    #[inline]
110    pub fn is_empty(&self) -> bool {
111        self.len() == 0
112    }
113
114    /// Get an item from the list at the specified index
115    #[inline]
116    pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
117        let item = unsafe { (self.def.vtable.get)(self.value.data(), index, self.value.shape())? };
118
119        Some(unsafe { Peek::unchecked_new(item, self.def.t()) })
120    }
121
122    /// Returns an iterator over the list
123    pub fn iter(self) -> PeekListIter<'mem, 'facet> {
124        let state = if let Some(as_ptr_fn) = self.def.vtable.as_ptr {
125            let data = unsafe { as_ptr_fn(self.value.data()) };
126            let layout = self
127                .def
128                .t()
129                .layout
130                .sized_layout()
131                .expect("can only iterate over sized list elements");
132            let stride = layout.size();
133
134            PeekListIterState {
135                kind: PeekListIterStateKind::Ptr { data, stride },
136                _phantom: PhantomData,
137            }
138        } else {
139            let iter = unsafe {
140                (self.def.iter_vtable().unwrap().init_with_value.unwrap())(self.value.data())
141            };
142            PeekListIterState {
143                kind: PeekListIterStateKind::Iter { iter },
144                _phantom: PhantomData,
145            }
146        };
147
148        PeekListIter {
149            state,
150            index: 0,
151            len: self.len(),
152            def: self.def(),
153            _list: PhantomData,
154        }
155    }
156
157    /// Def getter
158    #[inline]
159    pub fn def(&self) -> ListDef {
160        self.def
161    }
162}