substrate_stellar_xdr/
xdr_codec.rs

1//! Trait for types that can be XDR encoded/decoded
2
3use base64::{decode_config_slice, encode_config_slice};
4use core::convert::{AsRef, TryInto};
5use sp_std::{boxed::Box, vec::Vec};
6
7use crate::streams::{DecodeError, ReadStream, WriteStream};
8
9/// The XDR decoder/encoder trait
10///
11/// A type that implements this trait can be encoded as XDR or decoded from XDR
12pub trait XdrCodec: Sized {
13    /// Encode this type as XDR
14    ///
15    /// The binary XDR is returned as a byte vector
16    fn to_xdr(&self) -> Vec<u8> {
17        let mut write_stream = WriteStream::new();
18        self.to_xdr_buffered(&mut write_stream);
19        write_stream.get_result()
20    }
21
22    /// Decode XDR provided as a reference to a byte vector
23    ///
24    /// This will return error if decoding was not successful
25    fn from_xdr<T: AsRef<[u8]>>(input: T) -> Result<Self, DecodeError> {
26        let mut read_stream = ReadStream::new(input);
27        let value = Self::from_xdr_buffered(&mut read_stream)?;
28        if read_stream.no_of_bytes_left_to_read() != 0 {
29            return Err(DecodeError::TypeEndsTooEarly {
30                remaining_no_of_bytes: read_stream.no_of_bytes_left_to_read(),
31            });
32        }
33
34        Ok(value)
35    }
36
37    /// Encode this type as base64 encoded XDR
38    ///
39    /// This returns an ASCII string (as a byte vector) that is the base64 encoding
40    /// of the XDR encoding of this type.
41    fn to_base64_xdr(&self) -> Vec<u8> {
42        let xdr = self.to_xdr();
43        let mut base64_buffer = Vec::new();
44        base64_buffer.resize(xdr.len() * 4 / 3 + 4, 0);
45        let bytes_written = encode_config_slice(xdr, base64::STANDARD, &mut base64_buffer);
46        base64_buffer.resize(bytes_written, 0);
47        base64_buffer
48    }
49
50    /// Decode this type from base64 encoded XDR
51    ///
52    /// This takes a reference to an ASCII string (as a byte vector), decodes it as base64
53    /// and then decodes the resulting binary array as XDR.
54    fn from_base64_xdr<T: AsRef<[u8]>>(input: T) -> Result<Self, DecodeError> {
55        let input = input.as_ref();
56        let mut buf = Vec::new();
57        buf.resize(input.len() * 4 / 3 + 4, 0);
58
59        match decode_config_slice(input, base64::STANDARD, &mut buf) {
60            Ok(bytes_written) => {
61                buf.resize(bytes_written, 0);
62                Self::from_xdr(buf)
63            }
64            Err(_) => Err(DecodeError::InvalidBase64),
65        }
66    }
67
68    /// Encode the XDR to a write stream
69    ///
70    /// This is the basic implementation of the XDR encoder of this type. The methods
71    /// `to_xdr` and `to_base64_xdr` call this function to do the heavy lifting.
72    fn to_xdr_buffered(&self, write_stream: &mut WriteStream);
73
74    /// Decode the XDR from a read stream
75    ///
76    /// This is the basic implementation of the XDR decoder of this type. The methods
77    /// `from_xdr` and `from_base64_xdr` call this function to do the heavy lifting.
78    fn from_xdr_buffered<T: AsRef<[u8]>>(
79        read_stream: &mut ReadStream<T>,
80    ) -> Result<Self, DecodeError>;
81}
82
83/// Implementation of the XDR decoder/encoder for `u64`
84impl XdrCodec for u64 {
85    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
86        write_stream.write_next_u64(*self);
87    }
88
89    fn from_xdr_buffered<T: AsRef<[u8]>>(
90        read_stream: &mut ReadStream<T>,
91    ) -> Result<Self, DecodeError> {
92        read_stream.read_next_u64()
93    }
94}
95
96/// Implementation of the XDR decoder/encoder for `i64`
97impl XdrCodec for i64 {
98    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
99        write_stream.write_next_i64(*self);
100    }
101
102    fn from_xdr_buffered<T: AsRef<[u8]>>(
103        read_stream: &mut ReadStream<T>,
104    ) -> Result<Self, DecodeError> {
105        read_stream.read_next_i64()
106    }
107}
108
109/// Implementation of the XDR decoder/encoder for `u32`
110impl XdrCodec for u32 {
111    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
112        write_stream.write_next_u32(*self);
113    }
114
115    fn from_xdr_buffered<T: AsRef<[u8]>>(
116        read_stream: &mut ReadStream<T>,
117    ) -> Result<Self, DecodeError> {
118        read_stream.read_next_u32()
119    }
120}
121
122/// Implementation of the XDR decoder/encoder for `i32`
123impl XdrCodec for i32 {
124    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
125        write_stream.write_next_i32(*self);
126    }
127
128    fn from_xdr_buffered<T: AsRef<[u8]>>(
129        read_stream: &mut ReadStream<T>,
130    ) -> Result<Self, DecodeError> {
131        read_stream.read_next_i32()
132    }
133}
134
135/// Implementation of the XDR decoder/encoder for `bool`
136impl XdrCodec for bool {
137    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
138        write_stream.write_next_i32(if *self { 1 } else { 0 });
139    }
140
141    fn from_xdr_buffered<T: AsRef<[u8]>>(
142        read_stream: &mut ReadStream<T>,
143    ) -> Result<Self, DecodeError> {
144        let parsed_int = read_stream.read_next_i32()?;
145        match parsed_int {
146            0 => Ok(false),
147            1 => Ok(true),
148            _ => Err(DecodeError::InvalidBoolean {
149                found_integer: parsed_int,
150                at_position: read_stream.get_position(),
151            }),
152        }
153    }
154}
155
156/// Implementation of the XDR decoder/encoder for a fixed size array
157///
158/// This requires that the inner type already implements `XdrCodec`
159impl<T: XdrCodec, const N: usize> XdrCodec for [T; N] {
160    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
161        for item in self.iter() {
162            item.to_xdr_buffered(write_stream);
163        }
164    }
165
166    fn from_xdr_buffered<R: AsRef<[u8]>>(
167        read_stream: &mut ReadStream<R>,
168    ) -> Result<Self, DecodeError> {
169        let mut result = Vec::<T>::with_capacity(N);
170        for _ in 0..N {
171            result.push(T::from_xdr_buffered(read_stream)?)
172        }
173        result.try_into().map_err(|_| unreachable!())
174    }
175}
176
177/// Implementation of the XDR decoder/encoder for fixed length binary data
178impl<const N: usize> XdrCodec for [u8; N] {
179    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
180        write_stream.write_next_binary_data(self);
181    }
182
183    fn from_xdr_buffered<T: AsRef<[u8]>>(
184        read_stream: &mut ReadStream<T>,
185    ) -> Result<Self, DecodeError> {
186        let value = read_stream.read_next_binary_data(N)?;
187        value.try_into().map_err(|_| unreachable!())
188    }
189}
190
191/// Implementation of the XDR decoder/encoder for an `Option`.
192///
193/// This requires that the inner type already implements `XdrCodec`
194impl<T: XdrCodec> XdrCodec for Option<T> {
195    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
196        match self {
197            None => write_stream.write_next_u32(0),
198            Some(value) => {
199                write_stream.write_next_u32(1);
200                value.to_xdr_buffered(write_stream);
201            }
202        }
203    }
204
205    fn from_xdr_buffered<R: AsRef<[u8]>>(
206        read_stream: &mut ReadStream<R>,
207    ) -> Result<Self, DecodeError> {
208        match read_stream.read_next_u32()? {
209            0 => Ok(None),
210            1 => T::from_xdr_buffered(read_stream).map(|ok| Some(ok)),
211            code => Err(DecodeError::InvalidOptional {
212                at_position: read_stream.get_position(),
213                has_code: code,
214            }),
215        }
216    }
217}
218
219/// Implementation of the XDR decoder/encoder for an `Box`.
220///
221/// This requires that the inner type already implements `XdrCodec`
222impl<T: XdrCodec> XdrCodec for Box<T> {
223    fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
224        self.as_ref().to_xdr_buffered(write_stream)
225    }
226
227    fn from_xdr_buffered<R: AsRef<[u8]>>(
228        read_stream: &mut ReadStream<R>,
229    ) -> Result<Self, DecodeError> {
230        Ok(Box::new(T::from_xdr_buffered(read_stream)?))
231    }
232}