gel_db_protocol/
arrays.rs

1#![allow(private_bounds)]
2
3use crate::prelude::*;
4
5pub use std::marker::PhantomData;
6
7/// Inflated version of a zero-terminated array with zero-copy iterator access.
8#[derive(Copy, Clone, Default)]
9pub struct ZTArray<'a, T> {
10    _phantom: PhantomData<T>,
11    buf: &'a [u8],
12    len: usize,
13}
14
15impl<'a, T> ZTArray<'a, T> {
16    #[inline(always)]
17    pub const fn new(buf: &'a [u8], len: usize) -> Self {
18        Self {
19            buf,
20            len,
21            _phantom: PhantomData,
22        }
23    }
24
25    #[inline(always)]
26    pub const fn len(&self) -> usize {
27        self.len
28    }
29
30    #[inline(always)]
31    pub const fn is_empty(&self) -> bool {
32        self.len == 0
33    }
34}
35
36/// [`ZTArray`] [`Iterator`] for values of type `T`.
37pub struct ZTArrayIter<'a, T> {
38    _phantom: PhantomData<T>,
39    buf: &'a [u8],
40}
41
42impl<'a, T> std::fmt::Debug for ZTArray<'a, T>
43where
44    T: DataType,
45    T::DecodeLifetime<'a>: std::fmt::Debug,
46{
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.debug_list().entries(self).finish()
49    }
50}
51
52impl<'a> ZTArray<'a, u8> {
53    #[inline(always)]
54    pub fn into_slice(self) -> &'a [u8] {
55        self.buf
56    }
57}
58
59impl<'a, T: DataType> IntoIterator for ZTArray<'a, T> {
60    type Item = T::DecodeLifetime<'a>;
61    type IntoIter = ZTArrayIter<'a, T>;
62    fn into_iter(self) -> Self::IntoIter {
63        ZTArrayIter {
64            _phantom: PhantomData,
65            buf: self.buf,
66        }
67    }
68}
69
70impl<'a, T: DataType> IntoIterator for &ZTArray<'a, T> {
71    type Item = T::DecodeLifetime<'a>;
72    type IntoIter = ZTArrayIter<'a, T>;
73    fn into_iter(self) -> Self::IntoIter {
74        ZTArrayIter {
75            _phantom: PhantomData,
76            buf: self.buf,
77        }
78    }
79}
80
81impl<'a, T: DataType> Iterator for ZTArrayIter<'a, T> {
82    type Item = T::DecodeLifetime<'a>;
83    fn next(&mut self) -> Option<Self::Item> {
84        if self.buf[0] == 0 {
85            return None;
86        }
87        let value = T::decode(&mut self.buf).ok()?;
88        Some(value)
89    }
90}
91
92/// Inflated version of a length-specified array with zero-copy iterator access.
93#[derive(Copy, Clone, Default)]
94pub struct Array<'a, L, T> {
95    _phantom: PhantomData<(L, T)>,
96    buf: &'a [u8],
97    len: u32,
98}
99
100impl<'a, L, T> Array<'a, L, T> {
101    pub const fn new(buf: &'a [u8], len: u32) -> Self {
102        Self {
103            buf,
104            len,
105            _phantom: PhantomData,
106        }
107    }
108
109    #[inline(always)]
110    pub const fn len(&self) -> usize {
111        self.len as usize
112    }
113
114    #[inline(always)]
115    pub const fn is_empty(&self) -> bool {
116        self.len == 0
117    }
118}
119
120impl<'a, L> Array<'a, L, u8> {
121    #[inline(always)]
122    pub fn into_slice(self) -> &'a [u8] {
123        self.buf
124    }
125}
126
127impl<'a, L, T> std::fmt::Debug for Array<'a, L, T>
128where
129    for<'b> &'b Self: IntoIterator,
130    for<'b> <&'b Self as IntoIterator>::Item: std::fmt::Debug,
131{
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        f.debug_list().entries(self).finish()
134    }
135}
136
137/// [`Array`] [`Iterator`] for values of type `T`.
138pub struct ArrayIter<'a, T> {
139    _phantom: PhantomData<T>,
140    buf: &'a [u8],
141    len: u32,
142}
143
144impl<'a, L, T: DataType> IntoIterator for Array<'a, L, T> {
145    type Item = T::DecodeLifetime<'a>;
146    type IntoIter = ArrayIter<'a, T>;
147    fn into_iter(self) -> Self::IntoIter {
148        ArrayIter {
149            _phantom: PhantomData,
150            buf: self.buf,
151            len: self.len,
152        }
153    }
154}
155
156impl<'a, L, T: DataType> IntoIterator for &Array<'a, L, T> {
157    type Item = T::DecodeLifetime<'a>;
158    type IntoIter = ArrayIter<'a, T>;
159    fn into_iter(self) -> Self::IntoIter {
160        ArrayIter {
161            _phantom: PhantomData,
162            buf: self.buf,
163            len: self.len,
164        }
165    }
166}
167
168impl<'a, T: DataType> Iterator for ArrayIter<'a, T> {
169    type Item = T::DecodeLifetime<'a>;
170    fn next(&mut self) -> Option<Self::Item> {
171        if self.len == 0 {
172            return None;
173        }
174        self.len -= 1;
175        let value = T::decode(&mut self.buf).ok()?;
176        Some(value)
177    }
178}
179
180// Arrays of type [`u8`] are special-cased to return a slice of bytes.
181impl<T> AsRef<[u8]> for Array<'_, T, u8> {
182    fn as_ref(&self) -> &[u8] {
183        &self.buf[..self.len as _]
184    }
185}
186
187// Arrays of fixed-size elements can extract elements in O(1).
188impl<'a, L: TryInto<usize>, T: DataTypeFixedSize + DataType> Array<'a, L, T> {
189    pub fn get(&self, index: L) -> Option<T::DecodeLifetime<'a>> {
190        let Ok(index) = index.try_into() else {
191            return None;
192        };
193        let index: usize = index;
194        if index >= self.len as _ {
195            None
196        } else {
197            let mut segment = &self.buf[T::SIZE * index..T::SIZE * (index + 1)];
198            // As we've normally pre-scanned all items, this will not panic
199            Some(T::decode(&mut segment).unwrap())
200        }
201    }
202}