seda_sdk_rs/
bytes.rs

1//! Module for handling byte arrays in a oracle program compatible way.
2//!
3//! Creating a standardized way to handle byte arrays is important for
4//! oracle programs, as they are expected to return promises in a specific
5//! format.
6//!
7//! This module provides a [`Bytes`] type that wraps a vector of bytes
8//! and implements the [`ToBytes`] and [`FromBytes`] traits for various types.
9
10use std::ops::Deref;
11
12use serde::{Deserialize, Serialize};
13
14use crate::{errors, errors::Result};
15
16/// A wrapper around a vector of bytes that provides convenience methods for
17/// the format that oracle promises are expected to be in.
18#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
19pub struct Bytes(Vec<u8>);
20
21impl Bytes {
22    /// Get the inner vector of bytes.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use seda_sdk_rs::bytes::{Bytes, ToBytes};
28    /// let bytes: Bytes = "Hello, world!".to_bytes();
29    /// let inner: Vec<u8> = bytes.eject();
30    /// assert_eq!(inner, b"Hello, world!");
31    /// ```
32    pub fn eject(self) -> Vec<u8> {
33        self.0
34    }
35}
36
37impl Deref for Bytes {
38    type Target = [u8];
39
40    fn deref(&self) -> &Self::Target {
41        self.0.as_slice()
42    }
43}
44
45/// A trait for types that can be converted to the [`Bytes`] type.
46///
47/// This trait is implemented for various types such as `Vec<u8>`, `String`, `&str`, and primitive types like `u8`, `i32`, etc.
48///
49/// Additionally it supports an JSON serializable type via the [`serde`] and [`serde_json`] crates.
50pub trait ToBytes {
51    /// Converts the implementing type to a [`Bytes`] instance.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use seda_sdk_rs::bytes::{Bytes, ToBytes};
57    /// let bytes: Bytes = "Hello, world!".to_bytes();
58    /// assert_eq!(bytes.eject(), b"Hello, world!");
59    /// ```
60    fn to_bytes(self) -> Bytes;
61}
62
63impl ToBytes for Bytes {
64    fn to_bytes(self) -> Bytes {
65        self
66    }
67}
68
69impl ToBytes for Vec<u8> {
70    fn to_bytes(self) -> Bytes {
71        Bytes(self)
72    }
73}
74
75impl ToBytes for String {
76    fn to_bytes(self) -> Bytes {
77        Bytes(self.as_bytes().to_vec())
78    }
79}
80
81impl ToBytes for &str {
82    fn to_bytes(self) -> Bytes {
83        Bytes(self.as_bytes().to_vec())
84    }
85}
86
87impl ToBytes for bool {
88    fn to_bytes(self) -> Bytes {
89        Bytes(vec![self as u8])
90    }
91}
92
93impl ToBytes for () {
94    fn to_bytes(self) -> Bytes {
95        Bytes::default()
96    }
97}
98
99/// A trait to convert [`Bytes`] into a specific type.
100///
101/// This trait is implemented for various types such as `Vec<u8>`, `String`, `&str`, and primitive types like `u8`, `i32`, etc.
102///
103/// Additionally it supports an JSON deserializable type via the [`serde`] and [`serde_json`] crates.
104pub trait FromBytes
105where
106    Self: Sized,
107{
108    /// A way to convert the [`Bytes`] into the implementing type without consuming the original bytes.
109    ///
110    /// # Errors
111    ///
112    /// There are several reasons why this conversion might fail returning an [`errors::SDKError`]:
113    ///
114    /// - [`errors::SDKError::FromUtf8Error`] if the bytes are not valid UTF-8.
115    /// - [`errors::SDKError::NumBytesConversion`] if the bytes are not of the expected length for the type of number primitive.
116    /// - [`errors::SDKError::InvalidValue`] if the bytes do not represent a valid value for the type.
117    /// - [`errors::SDKError::Serde`] if the bytes cannot be deserialized into the type.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use seda_sdk_rs::bytes::{FromBytes, ToBytes};
123    /// let bytes = "Hello, world!".to_bytes();
124    /// let string: String = String::from_bytes(&bytes).expect("Should be valid UTF-8");
125    /// assert_eq!(string, "Hello, world!");
126    /// ```
127    fn from_bytes(bytes: &[u8]) -> Result<Self>;
128
129    /// A way to convert the [`Bytes`] into the implementing type and consume the original bytes.
130    ///
131    /// # Errors
132    ///
133    /// There are several reasons why this conversion might fail returning an [`errors::SDKError`]:
134    ///
135    /// - [`errors::SDKError::FromUtf8Error`] if the bytes are not valid UTF-8.
136    /// - [`errors::SDKError::NumBytesConversion`] if the bytes are not of the expected length for the type of number primitive.
137    /// - [`errors::SDKError::InvalidValue`] if the bytes do not represent a valid value for the type.
138    /// - [`errors::SDKError::Serde`] if the bytes cannot be deserialized into the type.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use seda_sdk_rs::bytes::{FromBytes, ToBytes};
144    /// let bytes = "Hello, world!".to_bytes();
145    /// let string: String = String::from_bytes_vec(bytes.eject()).expect("Should be valid UTF-8");
146    /// assert_eq!(string, "Hello, world!");
147    /// ```
148    fn from_bytes_vec(bytes: Vec<u8>) -> Result<Self>;
149}
150
151impl FromBytes for Vec<u8> {
152    fn from_bytes(bytes: &[u8]) -> Result<Self> {
153        Ok(bytes.to_vec())
154    }
155
156    fn from_bytes_vec(bytes: Vec<u8>) -> Result<Self> {
157        Ok(bytes)
158    }
159}
160
161impl FromBytes for String {
162    fn from_bytes(bytes: &[u8]) -> Result<Self> {
163        Ok(std::str::from_utf8(bytes)?.into())
164    }
165
166    fn from_bytes_vec(bytes: Vec<u8>) -> Result<Self> {
167        Self::from_bytes(bytes.as_slice())
168    }
169}
170
171impl FromBytes for bool {
172    fn from_bytes(bytes: &[u8]) -> Result<Self> {
173        match bytes[0] {
174            0 => Ok(false),
175            1 => Ok(true),
176            _ => Err(errors::SDKError::InvalidValue),
177        }
178    }
179
180    fn from_bytes_vec(bytes: Vec<u8>) -> Result<Self> {
181        if bytes.len() != 1 {
182            Err(errors::SDKError::InvalidValue)
183        } else {
184            Self::from_bytes(bytes.as_slice())
185        }
186    }
187}
188
189macro_rules! bytes_impls_le_bytes {
190    ($type_:ty, $num_bytes:expr) => {
191        impl ToBytes for $type_ {
192            fn to_bytes(self) -> Bytes {
193                Bytes(self.to_le_bytes().to_vec())
194            }
195        }
196
197        impl FromBytes for $type_ {
198            fn from_bytes(bytes: &[u8]) -> Result<Self> {
199                let bytes: [u8; $num_bytes] = bytes.try_into()?;
200                Ok(<$type_>::from_le_bytes(bytes))
201            }
202
203            fn from_bytes_vec(bytes: Vec<u8>) -> Result<Self> {
204                Self::from_bytes(bytes.as_slice())
205            }
206        }
207    };
208}
209
210/// Implements `ToBytes` and `FromBytes` via JSON serialization/deserialization for the given type.
211///
212/// This macro generates:
213/// - a `ToBytes` impl that serializes the type to a `Vec<u8>` using `serde_json::to_vec`
214///   and wraps it in `seda_sdk_rs::Bytes`.
215/// - a `FromBytes` impl that deserializes from a `&[u8]` or `Vec<u8>` using `serde_json::from_slice`.
216///
217/// # Example
218///
219/// # Example
220///
221/// ```
222/// use serde::{Serialize, Deserialize};
223/// use seda_sdk_rs::bytes::{Bytes, ToBytes, FromBytes};
224/// use seda_sdk_rs::bytes_serde_json;
225///
226/// #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
227/// struct MyType { foo: String, bar: i32 }
228///
229/// // Generate the ToBytes/FromBytes impls
230/// bytes_serde_json!(MyType);
231///
232/// let original = MyType { foo: "hi".into(), bar: 123 };
233/// let bytes = original.clone().to_bytes();
234/// let decoded = MyType::from_bytes(&bytes).unwrap();
235/// assert_eq!(original, decoded);
236/// ```
237#[macro_export]
238macro_rules! bytes_serde_json {
239    ($type_:ty) => {
240        impl $crate::bytes::ToBytes for $type_ {
241            fn to_bytes(self) -> $crate::bytes::Bytes {
242                serde_json::to_vec(&self).unwrap().to_bytes()
243            }
244        }
245
246        impl $crate::bytes::FromBytes for $type_ {
247            fn from_bytes(bytes: &[u8]) -> $crate::errors::Result<Self> {
248                Ok(serde_json::from_slice(bytes)?)
249            }
250
251            fn from_bytes_vec(bytes: Vec<u8>) -> $crate::errors::Result<Self> {
252                Self::from_bytes(&bytes)
253            }
254        }
255    };
256}
257
258bytes_impls_le_bytes!(u8, 1);
259bytes_impls_le_bytes!(u32, 4);
260bytes_impls_le_bytes!(u64, 8);
261bytes_impls_le_bytes!(u128, 16);
262bytes_impls_le_bytes!(i8, 1);
263bytes_impls_le_bytes!(i32, 4);
264bytes_impls_le_bytes!(i64, 8);
265bytes_impls_le_bytes!(i128, 16);
266bytes_impls_le_bytes!(f32, 4);
267bytes_impls_le_bytes!(f64, 8);