Skip to main content

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    value: Peek<'mem, 'facet>,
86    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    ///
98    /// # Safety
99    ///
100    /// The caller must ensure that `def` contains valid vtable function pointers that:
101    /// - Correctly implement the list operations for the actual type
102    /// - Do not cause undefined behavior when called
103    /// - Return pointers within valid memory bounds
104    /// - Match the element type specified in `def.t()`
105    ///
106    /// Violating these requirements can lead to memory safety issues.
107    #[inline]
108    pub const unsafe fn new(value: Peek<'mem, 'facet>, def: ListDef) -> Self {
109        Self { value, def }
110    }
111
112    /// Get the length of the list
113    #[inline]
114    pub fn len(&self) -> usize {
115        unsafe { (self.def.vtable.len)(self.value.data()) }
116    }
117
118    /// Returns true if the list is empty
119    #[inline]
120    pub fn is_empty(&self) -> bool {
121        self.len() == 0
122    }
123
124    /// Get an item from the list at the specified index
125    #[inline]
126    pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet>> {
127        let item = unsafe { (self.def.vtable.get)(self.value.data(), index, self.value.shape())? };
128
129        Some(unsafe { Peek::unchecked_new(item, self.def.t()) })
130    }
131
132    /// Returns an iterator over the list
133    pub fn iter(self) -> PeekListIter<'mem, 'facet> {
134        let state = if let Some(as_ptr_fn) = self.def.vtable.as_ptr {
135            let data = unsafe { as_ptr_fn(self.value.data()) };
136            let layout = self
137                .def
138                .t()
139                .layout
140                .sized_layout()
141                .expect("can only iterate over sized list elements");
142            let stride = layout.size();
143
144            PeekListIterState {
145                kind: PeekListIterStateKind::Ptr { data, stride },
146                _phantom: PhantomData,
147            }
148        } else {
149            let iter = unsafe {
150                (self.def.iter_vtable().unwrap().init_with_value.unwrap())(self.value.data())
151            };
152            PeekListIterState {
153                kind: PeekListIterStateKind::Iter { iter },
154                _phantom: PhantomData,
155            }
156        };
157
158        PeekListIter {
159            state,
160            index: 0,
161            len: self.len(),
162            def: self.def(),
163            _list: PhantomData,
164        }
165    }
166
167    /// Def getter
168    #[inline]
169    pub const fn def(&self) -> ListDef {
170        self.def
171    }
172}