mproto/
list.rs

1use crate::{BaseLen, Compatible, Decode, DecodeCursor, DecodeError, DecodeResult, Encode, EncodeCursor, Owned};
2
3#[cfg(any(feature = "std", feature = "alloc"))]
4use crate::Lazy;
5
6#[cfg(any(feature = "std", feature = "alloc"))]
7impl<T: Owned + Compatible<T>> Owned for Vec<T> {
8    type Lazy<'a> = ListLazy<'a, T>;
9
10    fn lazy_to_owned(lazy: Self::Lazy<'_>) -> DecodeResult<Self> {
11        lazy.try_into()
12    }
13}
14
15#[cfg(any(feature = "std", feature = "alloc"))]
16impl<'a, T: Owned + Compatible<T>> Lazy<'a> for ListLazy<'a, T> {
17    type Owned = Vec<T>;
18}
19
20#[cfg(any(feature = "std", feature = "alloc"))]
21impl<'a, T, U> core::convert::TryFrom<ListLazy<'a, T>> for Vec<U>
22where
23    T: Owned,
24    U: Decode<'a> + Compatible<T>,
25{
26    type Error = DecodeError;
27
28    fn try_from(other: ListLazy<'a, T>) -> Result<Self, Self::Error> {
29        let cursor = DecodeCursor::at_offset(other.buffer, other.offset);
30        Decode::decode(&cursor)
31    }
32}
33
34impl<T: BaseLen> BaseLen for [T] {
35    const BASE_LEN: usize = 4 + 4;
36}
37
38impl<T: Encode> Encode for [T] {
39    fn scratch_len(&self) -> usize {
40        self.len() * T::BASE_LEN + self.iter().fold(0, |sum, item| sum + item.scratch_len())
41    }
42
43    fn encode(&self, cursor: &mut EncodeCursor) {
44        cursor
45            .base(4)
46            .copy_from_slice(&(self.len() as u32).to_le_bytes());
47
48        cursor.inner_in_scratch(self.len() * T::BASE_LEN, |cursor| {
49            for item in self {
50                item.encode(cursor);
51            }
52        });
53    }
54}
55
56#[cfg(any(feature = "std", feature = "alloc"))]
57impl<T, U: Compatible<T>> Compatible<Vec<T>> for Vec<U> {}
58#[cfg(any(feature = "std", feature = "alloc"))]
59impl<T, U: Compatible<T>> Compatible<Vec<T>> for [U] {}
60#[cfg(any(feature = "std", feature = "alloc"))]
61impl<T, U: Compatible<T>> Compatible<[T]> for Vec<U> {}
62
63impl<'a> Decode<'a> for &'a [u8] {
64    fn decode(cursor: &DecodeCursor<'a>) -> DecodeResult<Self> {
65        let len = u32::from_le_bytes(cursor.base(4).try_into().map_err(|_| DecodeError)?) as usize;
66
67        Ok(cursor.scratch(len))
68    }
69}
70
71#[cfg(any(feature = "std", feature = "alloc"))]
72impl<T: BaseLen> BaseLen for Vec<T> {
73    const BASE_LEN: usize = 4 + 4;
74}
75
76#[cfg(any(feature = "std", feature = "alloc"))]
77impl<T: Encode> Encode for Vec<T> {
78    fn scratch_len(&self) -> usize {
79        self.len() * T::BASE_LEN + self.iter().fold(0, |sum, item| sum + item.scratch_len())
80    }
81
82    fn encode(&self, cursor: &mut EncodeCursor) {
83        cursor
84            .base(4)
85            .copy_from_slice(&(self.len() as u32).to_le_bytes());
86
87        cursor.inner_in_scratch(self.len() * T::BASE_LEN, |cursor| {
88            for item in self {
89                item.encode(cursor);
90            }
91        });
92    }
93}
94
95#[cfg(any(feature = "std", feature = "alloc"))]
96impl<'a, T: Decode<'a>> Decode<'a> for Vec<T> {
97    fn decode(cursor: &DecodeCursor<'a>) -> DecodeResult<Self> {
98        let len = u32::from_le_bytes(cursor.base(4).try_into().map_err(|_| DecodeError)?) as usize;
99
100        cursor.inner_in_scratch(|cursor| {
101            let mut vec = Vec::with_capacity(len);
102            for _ in 0..len {
103                vec.push(T::decode(cursor)?);
104            }
105            Ok(vec)
106        })
107    }
108}
109
110#[cfg(any(feature = "std", feature = "alloc"))]
111impl<'a, T, U> PartialEq<ListLazy<'a, T>> for Vec<U>
112where
113    T: Owned,
114    U: PartialEq<T::Lazy<'a>>,
115{
116    fn eq(&self, other: &ListLazy<'a, T>) -> bool {
117        for (i, item) in self.iter().enumerate() {
118            if *item != other.get(i).unwrap() {
119                return false;
120            }
121        }
122
123        true
124    }
125}
126
127pub struct ListGen<I: ExactSizeIterator>(pub I);
128
129impl<I: ExactSizeIterator> BaseLen for ListGen<I> {
130    const BASE_LEN: usize = 4 + 4;
131}
132
133impl<I: Clone + ExactSizeIterator> Encode for ListGen<I>
134where
135    I::Item: Encode,
136{
137    fn scratch_len(&self) -> usize {
138        self.0.len() * I::Item::BASE_LEN
139            + self.0.clone().fold(0, |sum, item| sum + item.scratch_len())
140    }
141
142    fn encode(&self, cursor: &mut EncodeCursor) {
143        cursor
144            .base(4)
145            .copy_from_slice(&(self.0.len() as u32).to_le_bytes());
146
147        cursor.inner_in_scratch(self.0.len() * I::Item::BASE_LEN, |cursor| {
148            for item in self.0.clone() {
149                item.encode(cursor);
150            }
151        });
152    }
153}
154
155#[cfg(any(feature = "std", feature = "alloc"))]
156impl<T: Owned, U: Compatible<T>, I: Clone + ExactSizeIterator<Item = U>> Compatible<Vec<T>>
157    for ListGen<I>
158{
159}
160
161pub struct ListLazy<'a, T> {
162    buffer: &'a [u8],
163    offset: usize,
164    item_ty: core::marker::PhantomData<T>,
165}
166
167impl<T: Owned, U: Compatible<T>> Compatible<[U]> for ListLazy<'_, T> {}
168impl<T: Owned, U: Compatible<T>> Compatible<ListLazy<'_, T>> for [U] {}
169
170#[cfg(any(feature = "std", feature = "alloc"))]
171impl<T: Owned, U: Compatible<T>> Compatible<Vec<U>> for ListLazy<'_, T> {}
172#[cfg(any(feature = "std", feature = "alloc"))]
173impl<T: Owned, U: Compatible<T>> Compatible<ListLazy<'_, T>> for Vec<U> {}
174
175impl<'a, T: Owned> BaseLen for ListLazy<'a, T> {
176    const BASE_LEN: usize = 4 + 4;
177}
178
179impl<'a, T: Owned> Encode for ListLazy<'a, T> {
180    fn scratch_len(&self) -> usize {
181        self.len() * T::BASE_LEN + self.iter().fold(0, |sum, item| sum + item.scratch_len())
182    }
183
184    fn encode(&self, cursor: &mut EncodeCursor) {
185        cursor
186            .base(4)
187            .copy_from_slice(&(self.len() as u32).to_le_bytes());
188
189        cursor.inner_in_scratch(self.len() * T::BASE_LEN, |cursor| {
190            for item in self {
191                item.encode(cursor);
192            }
193        });
194    }
195}
196
197impl<'a, T: Owned> ListLazy<'a, T> {
198    pub fn len(&self) -> usize {
199        u32::from_le_bytes(
200            self.buffer[self.offset..self.offset + 4]
201                .try_into()
202                .unwrap(),
203        ) as usize
204    }
205
206    pub fn get(&self, index: usize) -> DecodeResult<T::Lazy<'a>> {
207        if index >= self.len() {
208            return Err(DecodeError);
209        }
210
211        let list_scratch_offset = u32::from_le_bytes(
212            self.buffer[self.offset + 4..self.offset + 8]
213                .try_into()
214                .map_err(|_| DecodeError)?,
215        ) as usize;
216
217        Decode::decode(&DecodeCursor::at_offset(
218            self.buffer,
219            list_scratch_offset + (index * T::BASE_LEN),
220        ))
221    }
222
223    pub fn iter<'s>(&'s self) -> ListLazyIter<'s, 'a, T> {
224        let len = self.len();
225        ListLazyIter {
226            list_lazy: self,
227            len,
228            cursor: 0,
229        }
230    }
231}
232
233impl<'a, T: Owned> Decode<'a> for ListLazy<'a, T> {
234    fn decode(cursor: &DecodeCursor<'a>) -> DecodeResult<Self> {
235        let offset = cursor.offset();
236        cursor.advance(Self::BASE_LEN);
237        Ok(ListLazy {
238            buffer: cursor.buffer(),
239            offset,
240            item_ty: core::marker::PhantomData,
241        })
242    }
243}
244
245impl<'s, 'a, T: Owned> IntoIterator for &'s ListLazy<'a, T> {
246    type Item = T::Lazy<'a>;
247    type IntoIter = ListLazyIter<'s, 'a, T>;
248
249    fn into_iter(self) -> Self::IntoIter {
250        let len = self.len();
251        ListLazyIter {
252            list_lazy: self,
253            len,
254            cursor: 0,
255        }
256    }
257}
258
259pub struct ListLazyIter<'s, 'a, T> {
260    list_lazy: &'s ListLazy<'a, T>,
261    len: usize,
262    cursor: usize,
263}
264
265impl<'s, 'a, T: Owned> Iterator for ListLazyIter<'s, 'a, T> {
266    type Item = T::Lazy<'a>;
267
268    fn next(&mut self) -> Option<Self::Item> {
269        let i = self.cursor;
270        self.cursor += 1;
271
272        if i < self.len {
273            Some(self.list_lazy.get(i).unwrap())
274        } else {
275            None
276        }
277    }
278}
279
280impl<'a, T, const N: usize> core::convert::TryInto<[T::Lazy<'a>; N]> for ListLazy<'a, T>
281where
282    T: Owned + Clone,
283    for<'b> T::Lazy<'b>: Sized,
284{
285    type Error = ();
286
287    fn try_into(self) -> Result<[T::Lazy<'a>; N], Self::Error> {
288        use core::mem::MaybeUninit;
289
290        if self.len() != N {
291            return Err(());
292        }
293
294        let mut out: [MaybeUninit<T::Lazy<'_>>; N] =
295            [const { MaybeUninit::<T::Lazy<'_>>::uninit() }; N];
296        for (out, item) in out.iter_mut().zip(self.iter()) {
297            out.write(item);
298        }
299
300        // TODO when stable
301        // SAFETY: we just initialized all items in `out` in the above for-loop.
302        //Ok(unsafe { MaybeUninit::array_assume_init(out) })
303        // SAFETY:
304        // - we just initialized all items in `out` in the above for-loop.
305        // - MaybeUninit<T> and T are guaranteed to have the same layout.
306        // - MaybeUninit<T> does not drop, so there are no double-frees.
307        Ok(unsafe { core::mem::transmute_copy(&out) })
308    }
309}
310
311impl<'a> From<ListLazy<'a, u8>> for &'a [u8] {
312    fn from(other: ListLazy<'a, u8>) -> Self {
313        let list_scratch_offset = u32::from_le_bytes(
314            other.buffer[other.offset + 4..other.offset + 8]
315                .try_into()
316                .unwrap(),
317        ) as usize;
318        &other.buffer[list_scratch_offset..list_scratch_offset + other.len()]
319    }
320}
321
322impl<T: Owned> Copy for ListLazy<'_, T> {}
323impl<T: Owned> Clone for ListLazy<'_, T> {
324    fn clone(&self) -> Self {
325        Self {
326            buffer: self.buffer,
327            offset: self.offset,
328            item_ty: core::marker::PhantomData,
329        }
330    }
331}
332impl<T> core::fmt::Debug for ListLazy<'_, T>
333where
334    T: Owned,
335    for<'a> T::Lazy<'a>: core::fmt::Debug,
336{
337    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
338        write!(f, "[")?;
339        for i in 0..self.len() {
340            if i > 0 {
341                write!(f, ", ")?;
342            }
343            write!(f, "{:?}", self.get(i))?;
344        }
345        write!(f, "]")?;
346        Ok(())
347    }
348}
349
350impl<T> PartialEq for ListLazy<'_, T>
351where
352    T: Owned,
353    for<'a> T::Lazy<'a>: PartialEq,
354{
355    /// Panics if decoding an item from either `ListLazy` fails.
356    fn eq(&self, other: &Self) -> bool {
357        if self.len() != other.len() {
358            return false;
359        }
360        for (item, other_item) in self.iter().zip(other.iter()) {
361            if !item.eq(&other_item) {
362                return false;
363            }
364        }
365        true
366    }
367}
368
369impl<T> Eq for ListLazy<'_, T>
370where
371    T: Owned,
372    for<'a> T::Lazy<'a>: Eq,
373{
374}