mina_p2p_messages/
array.rs

1use binprot::{BinProtRead, BinProtWrite, Nat0};
2use malloc_size_of_derive::MallocSizeOf;
3use rsexp::OfSexp;
4use serde::{Deserialize, Serialize};
5use std::ops::Deref;
6
7/// Mina array bounded to specific length. Note that the length is only checked
8/// when performing binprot operations.
9#[derive(
10    Clone,
11    Debug,
12    PartialEq,
13    Eq,
14    PartialOrd,
15    Ord,
16    Serialize,
17    Deserialize,
18    derive_more::From,
19    derive_more::Into,
20    MallocSizeOf,
21)]
22pub struct ArrayN<T, const N: u64>(Vec<T>);
23
24impl<T, const N: u64> AsRef<[T]> for ArrayN<T, N> {
25    fn as_ref(&self) -> &[T] {
26        self.0.as_ref()
27    }
28}
29
30impl<T, const N: u64> Deref for ArrayN<T, N> {
31    type Target = [T];
32
33    fn deref(&self) -> &Self::Target {
34        self.0.as_ref()
35    }
36}
37
38impl<T, const N: u64> IntoIterator for ArrayN<T, N> {
39    type Item = T;
40
41    type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
42
43    fn into_iter(self) -> Self::IntoIter {
44        self.0.into_iter()
45    }
46}
47
48impl<'a, T, const N: u64> IntoIterator for &'a ArrayN<T, N> {
49    type Item = &'a T;
50
51    type IntoIter = <&'a Vec<T> as IntoIterator>::IntoIter;
52
53    fn into_iter(self) -> Self::IntoIter {
54        self.0.iter()
55    }
56}
57
58impl<T, const N: u64> FromIterator<T> for ArrayN<T, N> {
59    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
60        ArrayN::<_, N>(Vec::from_iter(iter))
61    }
62}
63
64impl<T, const N: u64> ArrayN<T, N> {
65    pub fn to_inner(self) -> Vec<T> {
66        self.0
67    }
68
69    pub fn inner(&self) -> &Vec<T> {
70        &self.0
71    }
72
73    pub fn inner_mut(&mut self) -> &mut Vec<T> {
74        &mut self.0
75    }
76
77    pub fn iter(&self) -> std::slice::Iter<'_, T> {
78        self.0.iter()
79    }
80}
81
82impl<T: OfSexp, const N: u64> OfSexp for ArrayN<T, N> {
83    fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
84    where
85        Self: Sized,
86    {
87        let limit = N as usize;
88        let elts = s.extract_list("ArrayN")?;
89
90        if elts.len() > limit {
91            return Err(rsexp::IntoSexpError::ListLengthMismatch {
92                type_: "ArrayN",
93                expected_len: limit,
94                list_len: elts.len(),
95            });
96        }
97
98        let mut converted = Vec::with_capacity(elts.len());
99        for elt in elts.iter() {
100            converted.push(rsexp::OfSexp::of_sexp(elt)?);
101        }
102
103        Ok(ArrayN(converted))
104    }
105}
106
107impl<T: rsexp::SexpOf, const N: u64> rsexp::SexpOf for ArrayN<T, N> {
108    fn sexp_of(&self) -> rsexp::Sexp {
109        let elements: Vec<rsexp::Sexp> = self.0.iter().map(|item| item.sexp_of()).collect();
110
111        rsexp::Sexp::List(elements)
112    }
113}
114
115impl<T, const N: u64> BinProtRead for ArrayN<T, N>
116where
117    T: BinProtRead,
118{
119    fn binprot_read<R: std::io::prelude::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error> {
120        let Nat0(len) = Nat0::binprot_read(r)?;
121        if len > N {
122            return Err(MinaArrayNTooLong::<N>::new(len).into());
123        }
124        let mut v: Vec<T> = Vec::with_capacity(len as usize);
125        for _i in 0..len {
126            let item = T::binprot_read(r)?;
127            v.push(item)
128        }
129        Ok(ArrayN(v))
130    }
131}
132
133impl<T, const N: u64> BinProtWrite for ArrayN<T, N>
134where
135    T: BinProtWrite,
136{
137    fn binprot_write<W: std::io::prelude::Write>(&self, w: &mut W) -> std::io::Result<()> {
138        let len = self.0.len() as u64;
139        if len > N {
140            return Err(MinaArrayNTooLong::<N>::new(len).into());
141        }
142        Nat0(len).binprot_write(w)?;
143        for v in self.0.iter() {
144            v.binprot_write(w)?
145        }
146        Ok(())
147    }
148}
149
150#[derive(Debug, thiserror::Error)]
151#[error("String length `{0}` is greater than maximum `{N}`")]
152pub struct MinaArrayNTooLong<const N: u64>(u64);
153
154impl<const N: u64> MinaArrayNTooLong<N> {
155    fn new(actual: u64) -> Self {
156        MinaArrayNTooLong(actual)
157    }
158}
159
160impl<const N: u64> From<MinaArrayNTooLong<N>> for std::io::Error {
161    fn from(value: MinaArrayNTooLong<N>) -> Self {
162        std::io::Error::new(std::io::ErrorKind::InvalidData, Box::new(value))
163    }
164}
165
166impl<const N: u64> From<MinaArrayNTooLong<N>> for binprot::Error {
167    fn from(value: MinaArrayNTooLong<N>) -> Self {
168        binprot::Error::CustomError(Box::new(value))
169    }
170}
171
172/// Mina array limited to 16 elements.
173pub type ArrayN16<T> = ArrayN<T, 16>;
174
175/// Mina array limited to 4000 elements.
176pub type ArrayN4000<T> = ArrayN<T, 4000>;