t3rn_sdk_primitives/
storage.rs

1use crate::Vec;
2use arrayvec::ArrayVec;
3use codec::{Compact, Decode, Encode, EncodeLike, MaxEncodedLen, Output};
4
5// We had to make our own version of this since the one in frame_support is super coupled to the runtime crates
6// Test to prove feature parity in 3vm wasm-contracts.
7
8/// A bounded vector using ArrayVec as an underlying data structure.
9///
10#[derive(scale_info::TypeInfo, Debug, Clone)]
11pub struct BoundedVec<T: Encode + Decode, const CAP: usize>(pub ArrayVec<T, CAP>);
12
13impl<T, const CAP: usize> FromIterator<T> for BoundedVec<T, CAP>
14where
15    T: Encode + Decode,
16{
17    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
18        let inner = ArrayVec::from_iter(iter);
19        Self(inner)
20    }
21}
22
23impl<T, const CAP: usize> Default for BoundedVec<T, CAP>
24where
25    T: Encode + Decode,
26{
27    fn default() -> Self {
28        Self(ArrayVec::new())
29    }
30}
31
32impl<T, const CAP: usize> MaxEncodedLen for BoundedVec<T, CAP>
33where
34    T: MaxEncodedLen + Encode + Decode,
35{
36    fn max_encoded_len() -> usize {
37        Compact(CAP as u32)
38            .encoded_size()
39            .saturating_add(CAP.saturating_mul(T::max_encoded_len()))
40    }
41}
42
43impl<T, const CAP: usize> scale_info::prelude::ops::Deref for BoundedVec<T, CAP>
44where
45    T: Decode + Encode,
46{
47    type Target = [T];
48
49    fn deref(&self) -> &Self::Target {
50        &self.0
51    }
52}
53
54impl<T: Decode + Encode, const CAP: usize> Decode for BoundedVec<T, CAP> {
55    fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
56        let inner = Vec::<T>::decode(input)?;
57        if inner.len() > CAP {
58            return Err("BoundedVec exceeds its limit".into())
59        }
60        let inner = ArrayVec::from_iter(inner);
61        Ok(Self(inner))
62    }
63
64    fn skip<I: codec::Input>(input: &mut I) -> Result<(), codec::Error> {
65        Vec::<T>::skip(input)
66    }
67}
68
69impl<T: Decode + Encode, const CAP: usize> Encode for BoundedVec<T, CAP> {
70    fn size_hint(&self) -> usize {
71        self.0.iter().map(|x| x.size_hint()).sum()
72    }
73
74    fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
75        let bits = self.0.len();
76        Compact(bits as u32).encode_to(dest);
77        self.0.iter().for_each(|x| x.encode_to(dest));
78    }
79}
80
81// `BoundedVec`s encode to something which will always decode as a `Vec`.
82impl<T: Encode + Decode, const CAP: usize> EncodeLike<Vec<T>> for BoundedVec<T, CAP> {}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_boundec_vec_options() {
90        let x = BoundedVec::<_, 3>::from_iter(vec![Some(1_u8), Some(2_u8), Some(3_u8)]);
91        assert_eq!(x.encode(), vec![12, 1, 1, 1, 2, 1, 3]);
92    }
93}