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