facet_reflect/peek/
list_like.rs

1use facet_core::{PtrConst, Shape};
2
3use super::Peek;
4use core::fmt::Debug;
5
6/// Fields for types which act like lists
7#[derive(Clone, Copy)]
8pub enum ListLikeDef {
9    /// Ordered list of heterogenous values, variable size
10    ///
11    /// e.g. `Vec<T>`
12    List(facet_core::ListDef),
13
14    /// Fixed-size array of heterogenous values
15    ///
16    /// e.g. `[T; 32]`
17    Array(facet_core::ArrayDef),
18
19    /// Slice — a reference to a contiguous sequence of elements
20    ///
21    /// e.g. `&[T]`
22    Slice(facet_core::SliceDef),
23}
24
25impl ListLikeDef {
26    /// Returns the shape of the items in the list
27    pub fn t(&self) -> &'static 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
36/// Iterator over a `PeekListLike`
37pub struct PeekListLikeIter<'mem, 'facet_lifetime> {
38    list: PeekListLike<'mem, 'facet_lifetime>,
39    index: usize,
40    len: usize,
41}
42
43impl<'mem, 'facet_lifetime> Iterator for PeekListLikeIter<'mem, 'facet_lifetime> {
44    type Item = Peek<'mem, 'facet_lifetime>;
45
46    fn next(&mut self) -> Option<Self::Item> {
47        if self.index >= self.len {
48            return None;
49        }
50        let item = self.list.get(self.index);
51        self.index += 1;
52        item
53    }
54
55    fn size_hint(&self) -> (usize, Option<usize>) {
56        let remaining = self.len.saturating_sub(self.index);
57        (remaining, Some(remaining))
58    }
59}
60
61impl ExactSizeIterator for PeekListLikeIter<'_, '_> {}
62
63impl<'mem, 'facet_lifetime> IntoIterator for &'mem PeekListLike<'mem, 'facet_lifetime> {
64    type Item = Peek<'mem, 'facet_lifetime>;
65    type IntoIter = PeekListLikeIter<'mem, 'facet_lifetime>;
66
67    fn into_iter(self) -> Self::IntoIter {
68        self.iter()
69    }
70}
71
72/// Lets you read from a list, array or slice
73#[derive(Clone, Copy)]
74pub struct PeekListLike<'mem, 'facet_lifetime> {
75    pub(crate) value: Peek<'mem, 'facet_lifetime>,
76    pub(crate) def: ListLikeDef,
77    len: usize,
78    get_item_ptr: unsafe fn(array: PtrConst, index: usize) -> PtrConst,
79}
80
81impl Debug for PeekListLike<'_, '_> {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        f.debug_struct("PeekListLike").finish_non_exhaustive()
84    }
85}
86
87impl<'mem, 'facet_lifetime> PeekListLike<'mem, 'facet_lifetime> {
88    /// Creates a new peek list
89    pub fn new(value: Peek<'mem, 'facet_lifetime>, def: ListLikeDef) -> Self {
90        let (len, get_item_ptr) = match def {
91            ListLikeDef::List(v) => (
92                unsafe { (v.vtable.len)(value.data()) },
93                v.vtable.get_item_ptr,
94            ),
95            ListLikeDef::Slice(v) => (
96                unsafe { (v.vtable.len)(value.data()) },
97                v.vtable.get_item_ptr,
98            ),
99            ListLikeDef::Array(v) => (v.n, v.vtable.get_item_ptr),
100        };
101        Self {
102            value,
103            def,
104            len,
105            get_item_ptr,
106        }
107    }
108
109    /// Get the length of the list
110    pub fn len(&self) -> usize {
111        self.len
112    }
113
114    /// Returns true if the list is empty
115    pub fn is_empty(&self) -> bool {
116        self.len() == 0
117    }
118
119    /// Get an item from the list at the specified index
120    ///
121    /// # Panics
122    ///
123    /// Panics if the index is out of bounds
124    pub fn get(&self, index: usize) -> Option<Peek<'mem, 'facet_lifetime>> {
125        if index >= self.len() {
126            return None;
127        }
128
129        let item_ptr = unsafe { (self.get_item_ptr)(self.value.data(), index) };
130        Some(unsafe { Peek::unchecked_new(item_ptr, self.def.t()) })
131    }
132
133    /// Returns an iterator over the list
134    pub fn iter(self) -> PeekListLikeIter<'mem, 'facet_lifetime> {
135        PeekListLikeIter {
136            list: self,
137            index: 0,
138            len: self.len(),
139        }
140    }
141
142    /// Def getter
143    pub fn def(&self) -> ListLikeDef {
144        self.def
145    }
146}