substrate_stellar_sdk/xdr/
xdr_codec.rs1use base64::{decode_config_slice, encode_config_slice};
4use core::convert::{AsRef, TryInto};
5use sp_std::{boxed::Box, vec::Vec};
6
7use super::streams::{DecodeError, ReadStream, WriteStream};
8
9pub trait XdrCodec: Sized {
13 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 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 { remaining_no_of_bytes: read_stream.no_of_bytes_left_to_read() })
30 }
31
32 Ok(value)
33 }
34
35 fn to_base64_xdr(&self) -> Vec<u8> {
40 let xdr = self.to_xdr();
41 let mut base64_buffer = Vec::new();
42 base64_buffer.resize(xdr.len() * 4 / 3 + 4, 0);
43 let bytes_written = encode_config_slice(xdr, base64::STANDARD, &mut base64_buffer);
44 base64_buffer.resize(bytes_written, 0);
45 base64_buffer
46 }
47
48 fn from_base64_xdr<T: AsRef<[u8]>>(input: T) -> Result<Self, DecodeError> {
53 let input = input.as_ref();
54 let mut buf = Vec::new();
55 buf.resize(input.len() * 4 / 3 + 4, 0);
56
57 match decode_config_slice(input, base64::STANDARD, &mut buf) {
58 Ok(bytes_written) => {
59 buf.resize(bytes_written, 0);
60 Self::from_xdr(buf)
61 },
62 Err(_) => Err(DecodeError::InvalidBase64),
63 }
64 }
65
66 fn to_xdr_buffered(&self, write_stream: &mut WriteStream);
71
72 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError>;
77}
78
79impl XdrCodec for u64 {
81 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
82 write_stream.write_next_u64(*self);
83 }
84
85 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
86 read_stream.read_next_u64()
87 }
88}
89
90impl XdrCodec for i64 {
92 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
93 write_stream.write_next_i64(*self);
94 }
95
96 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
97 read_stream.read_next_i64()
98 }
99}
100
101impl XdrCodec for u32 {
103 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
104 write_stream.write_next_u32(*self);
105 }
106
107 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
108 read_stream.read_next_u32()
109 }
110}
111
112impl XdrCodec for i32 {
114 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
115 write_stream.write_next_i32(*self);
116 }
117
118 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
119 read_stream.read_next_i32()
120 }
121}
122
123impl XdrCodec for bool {
125 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
126 write_stream.write_next_i32(if *self { 1 } else { 0 });
127 }
128
129 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
130 let parsed_int = read_stream.read_next_i32()?;
131 match parsed_int {
132 0 => Ok(false),
133 1 => Ok(true),
134 _ =>
135 Err(DecodeError::InvalidBoolean { found_integer: parsed_int, at_position: read_stream.get_position() }),
136 }
137 }
138}
139
140impl<T: XdrCodec, const N: usize> XdrCodec for [T; N] {
144 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
145 for item in self.iter() {
146 item.to_xdr_buffered(write_stream);
147 }
148 }
149
150 fn from_xdr_buffered<R: AsRef<[u8]>>(read_stream: &mut ReadStream<R>) -> Result<Self, DecodeError> {
151 let mut result = Vec::<T>::with_capacity(N);
152 for _ in 0..N {
153 result.push(T::from_xdr_buffered(read_stream)?)
154 }
155 result.try_into().map_err(|_| unreachable!())
156 }
157}
158
159impl<const N: usize> XdrCodec for [u8; N] {
161 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
162 write_stream.write_next_binary_data(self);
163 }
164
165 fn from_xdr_buffered<T: AsRef<[u8]>>(read_stream: &mut ReadStream<T>) -> Result<Self, DecodeError> {
166 let value = read_stream.read_next_binary_data(N)?;
167 value.try_into().map_err(|_| unreachable!())
168 }
169}
170
171impl<T: XdrCodec> XdrCodec for Option<T> {
175 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
176 match self {
177 None => write_stream.write_next_u32(0),
178 Some(value) => {
179 write_stream.write_next_u32(1);
180 value.to_xdr_buffered(write_stream);
181 },
182 }
183 }
184
185 fn from_xdr_buffered<R: AsRef<[u8]>>(read_stream: &mut ReadStream<R>) -> Result<Self, DecodeError> {
186 match read_stream.read_next_u32()? {
187 0 => Ok(None),
188 1 => T::from_xdr_buffered(read_stream).map(|ok| Some(ok)),
189 code => Err(DecodeError::InvalidOptional { at_position: read_stream.get_position(), has_code: code }),
190 }
191 }
192}
193
194impl<T: XdrCodec> XdrCodec for Box<T> {
198 fn to_xdr_buffered(&self, write_stream: &mut WriteStream) {
199 self.as_ref().to_xdr_buffered(write_stream)
200 }
201
202 fn from_xdr_buffered<R: AsRef<[u8]>>(read_stream: &mut ReadStream<R>) -> Result<Self, DecodeError> {
203 Ok(Box::new(T::from_xdr_buffered(read_stream)?))
204 }
205}
206
207#[cfg_attr(feature = "all-types", doc = "```")]
214#[cfg_attr(not(feature = "all-types"), doc = "```ignore")]
215#[macro_export]
224macro_rules! parse_stellar_type {
225 ($ref:ident, $struct_str:ident) => {{
226 use $crate::{types::$struct_str, StellarSdkError, XdrCodec};
227
228 let ret: Result<$struct_str, StellarSdkError> =
229 $struct_str::from_xdr($ref).map_err(|_| StellarSdkError::DecodeError(stringify!($struct_str).into()));
230 ret
231 }};
232}