mina_p2p_messages/
array.rs

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