substrate_stellar_xdr/
compound_types.rs

1//! Generic types for encoding XDR variable length arrays and strings
2
3use core::convert::AsRef;
4use sp_std::{prelude::*, vec::Vec};
5
6use crate::streams::{DecodeError, ReadStream, WriteStream};
7use crate::xdr_codec::XdrCodec;
8
9/// Error to indicate that the length of a limited var array or string is violated
10#[derive(Debug, Clone)]
11pub struct ExceedsMaximumLengthError {
12    pub requested_length: usize,
13    pub allowed_length: i32,
14}
15
16/// Type for binary data whose length is not predefined but bounded by a constant
17///
18/// The const generic `N` specifies the maxmimum number of bytes a value of this
19/// type is allowed to have.
20#[allow(dead_code)]
21#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct LimitedVarOpaque<const N: i32>(Vec<u8>);
23
24impl<const N: i32> LimitedVarOpaque<N> {
25    /// Construct a new `LimitedVarOpaque` from a byte vector
26    ///
27    /// The length of the byte vector must not exceed `N`. Otherwise this function returns
28    /// an error.
29    pub fn new(vec: Vec<u8>) -> Result<Self, ExceedsMaximumLengthError> {
30        match vec.len() > N as usize {
31            true => Err(ExceedsMaximumLengthError {
32                requested_length: vec.len(),
33                allowed_length: N,
34            }),
35            false => Ok(LimitedVarOpaque(vec)),
36        }
37    }
38
39    /// Returns a reference to the raw byte vector
40    pub fn get_vec(&self) -> &Vec<u8> {
41        &self.0
42    }
43}
44
45impl<const N: i32> XdrCodec for LimitedVarOpaque<N> {
46    /// The XDR encoder implementation for `LimitedVarOpaque`
47    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
48        write_stream.write_next_u32(self.0.len() as u32);
49        write_stream.write_next_binary_data(&self.0[..]);
50    }
51
52    /// The XDR decoder implementation for `LimitedVarOpaque`
53    fn from_xdr_buffered<R: AsRef<[u8]>>(
54        read_stream: &mut ReadStream<R>,
55    ) -> Result<Self, DecodeError> {
56        let length = read_stream.read_next_u32()? as i32;
57        match length > N {
58            true => Err(DecodeError::VarOpaqueExceedsMaxLength {
59                at_position: read_stream.get_position(),
60                max_length: N,
61                actual_length: length,
62            }),
63            false => Ok(
64                LimitedVarOpaque::new(read_stream.read_next_binary_data(length as usize)?).unwrap(),
65            ),
66        }
67    }
68}
69
70/// Type for binary data whose length is not predefined and not bounded
71///
72/// Actually an `UnlimitedVarOpaque` is limited: it must not have more than
73/// `i32::MAX` bytes.
74#[allow(dead_code)]
75pub type UnlimitedVarOpaque = LimitedVarOpaque<{ i32::MAX }>;
76
77/// Type for an ASCII string whose length is not predefined but bounded by a constant
78///
79/// The const generic `N` specifies the maxmimum number of ASCII characters a value of this
80/// type is allowed to have.
81#[allow(dead_code)]
82#[derive(Debug, Clone, Eq, PartialEq)]
83pub struct LimitedString<const N: i32>(Vec<u8>);
84
85impl<const N: i32> LimitedString<N> {
86    /// Construct a new `LimitedString` from a byte vector
87    ///
88    /// The byte vector represents an ASCII string.
89    /// The length of the byte vector must not exceed `N`. Otherwise this function returns
90    /// an error
91    pub fn new(vec: Vec<u8>) -> Result<Self, ExceedsMaximumLengthError> {
92        match vec.len() > N as usize {
93            true => Err(ExceedsMaximumLengthError {
94                requested_length: vec.len(),
95                allowed_length: N,
96            }),
97            false => Ok(LimitedString(vec)),
98        }
99    }
100
101    /// Returns a reference to the raw byte vector
102    pub fn get_vec(&self) -> &Vec<u8> {
103        &self.0
104    }
105}
106
107impl<const N: i32> XdrCodec for LimitedString<N> {
108    /// The XDR encoder implementation for `LimitedString`
109    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
110        write_stream.write_next_u32(self.0.len() as u32);
111        write_stream.write_next_binary_data(&self.0[..]);
112    }
113
114    /// The XDR decoder implementation for `LimitedString`
115    fn from_xdr_buffered<R: AsRef<[u8]>>(
116        read_stream: &mut ReadStream<R>,
117    ) -> Result<Self, DecodeError> {
118        let length = read_stream.read_next_u32()? as i32;
119        match length > N {
120            true => Err(DecodeError::StringExceedsMaxLength {
121                at_position: read_stream.get_position(),
122                max_length: N,
123                actual_length: length,
124            }),
125            false => Ok(
126                LimitedString::new(read_stream.read_next_binary_data(length as usize)?).unwrap(),
127            ),
128        }
129    }
130}
131
132/// Type for an ASCII string whose length is not predefined and not bounded
133///
134/// Actually an `UnlimitedString` is limited: it must not have more than
135/// `i32::MAX` characters.
136#[allow(dead_code)]
137pub type UnlimitedString = LimitedString<{ i32::MAX }>;
138
139/// Type for an array whose length is not predefined but bounded by a constant
140///
141/// The generic variable `T` specifies the types of the elements of this array.
142/// The const generic `N` specifies the maxmimum number of elements a value of this
143/// type is allowed to have.
144#[allow(dead_code)]
145#[derive(Debug, Clone, Eq, PartialEq)]
146pub struct LimitedVarArray<T, const N: i32>(Vec<T>);
147
148impl<T, const N: i32> LimitedVarArray<T, N> {
149    /// Construct a new `LimitedVarArray` from a vector
150    ///
151    /// The length of the vector must not exceed `N`. Otherwise this function returns
152    /// an error
153    pub fn new(vec: Vec<T>) -> Result<Self, ExceedsMaximumLengthError> {
154        match vec.len() > N as usize {
155            true => Err(ExceedsMaximumLengthError {
156                requested_length: vec.len(),
157                allowed_length: N,
158            }),
159            false => Ok(LimitedVarArray(vec)),
160        }
161    }
162
163    /// Returns a reference to the byte vector
164    pub fn get_vec(&self) -> &Vec<T> {
165        &self.0
166    }
167
168    /// Add an element to the byte vector
169    ///
170    /// Return an `Err` if the array already has the maximal number of elements.
171    pub fn push(&mut self, item: T) -> Result<(), ExceedsMaximumLengthError> {
172        if self.0.len() >= N as usize - 1 {
173            return Err(ExceedsMaximumLengthError {
174                requested_length: self.0.len() + 1,
175                allowed_length: N,
176            });
177        }
178
179        self.0.push(item);
180        Ok(())
181    }
182}
183
184impl<T: XdrCodec, const N: i32> XdrCodec for LimitedVarArray<T, N> {
185    /// The XDR encoder implementation for `LimitedVarArray`
186    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
187        write_stream.write_next_u32(self.0.len() as u32);
188        for item in self.0.iter() {
189            item.to_xdr_buffered(write_stream);
190        }
191    }
192
193    /// The XDR decoder implementation for `LimitedVarArray`
194    fn from_xdr_buffered<R: AsRef<[u8]>>(
195        read_stream: &mut ReadStream<R>,
196    ) -> Result<Self, DecodeError> {
197        let length = read_stream.read_next_u32()? as i32;
198        match length > N {
199            true => Err(DecodeError::VarArrayExceedsMaxLength {
200                at_position: read_stream.get_position(),
201                max_length: N,
202                actual_length: length,
203            }),
204            false => {
205                let mut result = Vec::<T>::with_capacity(length as usize);
206                for _ in 0..length {
207                    result.push(T::from_xdr_buffered(read_stream)?)
208                }
209                Ok(LimitedVarArray::new(result).unwrap())
210            }
211        }
212    }
213}
214
215/// Type for an XDR array whose length is not predefined and not bounded
216///
217/// Actually an `UnlimitedVarArray` is limited: it must not have more than
218/// `i32::MAX` characters.
219#[allow(dead_code)]
220pub type UnlimitedVarArray<T> = LimitedVarArray<T, { i32::MAX }>;