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 {
20            PeekListIterState::Ptr { data, stride } => {
21                if self.index >= self.len {
22                    return None;
23                }
24
25                unsafe { data.field(stride * self.index) }
26            }
27            PeekListIterState::Iter { iter } => unsafe {
28                (self.def.vtable.iter_vtable.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 {
52            PeekListIterState::Iter { iter } => unsafe {
53                (self.def.vtable.iter_vtable.dealloc)(iter)
54            },
55            PeekListIterState::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
72enum PeekListIterState<'mem> {
73    Ptr { data: PtrConst<'mem>, stride: usize },
74    Iter { iter: PtrMut<'mem> },
75}
76
77/// Lets you read from a list (implements read-only [`facet_core::ListVTable`] proxies)
78#[derive(Clone, Copy)]
79pub struct PeekList<'mem, 'facet> {
80    pub(crate) value: Peek<'mem, 'facet>,
81    pub(crate) def: ListDef,
82}
83
84impl Debug for PeekList<'_, '_> {
85    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86        f.debug_struct("PeekList").finish_non_exhaustive()
87    }
88}
89
90impl<'mem, 'facet> PeekList<'mem, 'facet> {
91    /// Creates a new peek list
92    #[inline]
93    pub fn new(value: Peek<'mem, 'facet>, def: ListDef) -> Self {
94        Self { value, def }
95    }
96
97    /// Get the length of the list
98    #[inline]
99    pub fn len(&self) -> usize {
100        unsafe { (self.def.vtable.len)(self.value.data()) }
101    }
102
103    /// Returns true if the list is empty
104    #[inline]
105    pub fn is_empty(&self) -> bool {
106        self.len() == 0
107    }
108
109    /// Get an item from the list at the specified index
110    #[inline]
111    pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
112        let item = unsafe { (self.def.vtable.get)(self.value.data(), index)? };
113
114        Some(unsafe { Peek::unchecked_new(item, self.def.t()) })
115    }
116
117    /// Returns an iterator over the list
118    pub fn iter(self) -> PeekListIter<'mem, 'facet> {
119        let state = if let Some(as_ptr_fn) = self.def.vtable.as_ptr {
120            let data = unsafe { as_ptr_fn(self.value.data()) };
121            let layout = self
122                .def
123                .t()
124                .layout
125                .sized_layout()
126                .expect("can only iterate over sized list elements");
127            let stride = layout.size();
128
129            PeekListIterState::Ptr { data, stride }
130        } else {
131            let iter = unsafe {
132                (self.def.vtable.iter_vtable.init_with_value.unwrap())(self.value.data())
133            };
134            PeekListIterState::Iter { iter }
135        };
136
137        PeekListIter {
138            state,
139            index: 0,
140            len: self.len(),
141            def: self.def(),
142            _list: PhantomData,
143        }
144    }
145
146    /// Def getter
147    #[inline]
148    pub fn def(&self) -> ListDef {
149        self.def
150    }
151}