binary_codec_sv2/codec/
encodable.rs

1use crate::{
2    codec::GetSize,
3    datatypes::{Signature, Sv2DataType, U32AsRef, B016M, B0255, B032, B064K, U24, U256},
4    Error,
5};
6use alloc::vec::Vec;
7#[cfg(not(feature = "no_std"))]
8use std::io::{Error as E, Write};
9
10/// The `Encodable` trait defines the interface for encoding a type into bytes.
11///
12/// The trait provides methods for serializing an instance of a type into a byte
13/// array or writing it directly into an output writer. The trait is flexible,
14/// allowing various types, including primitives, structures, and collections,
15/// to implement custom serialization logic.
16///
17/// The trait offers two key methods for encoding:
18///
19/// - The first, `to_bytes`, takes a mutable byte slice as a destination buffer. This method encodes
20///   the object directly into the provided buffer, returning the number of bytes written or an
21///   error if the encoding process fails.
22/// - The second, `to_writer`, (only available when not compiling for `no-std`) accepts a writer as
23///   a destination for the encoded bytes, allowing the serialized data to be written to any
24///   implementor of the `Write` trait.
25///
26/// Implementing types can define custom encoding logic, and this trait is
27/// especially useful when dealing with different data structures that need
28/// to be serialized for transmission.
29pub trait Encodable {
30    /// Encodes the object into the provided byte slice.
31    ///
32    /// The method uses the destination buffer `dst` to write the serialized
33    /// bytes. It returns the number of bytes written on success or an `Error`
34    /// if encoding fails.
35    #[allow(clippy::wrong_self_convention)]
36    fn to_bytes(self, dst: &mut [u8]) -> Result<usize, Error>;
37
38    /// Write the encoded object into the provided writer.
39    ///
40    /// Serializes the object and writes it directly
41    /// to the `dst` writer. It is only available in environments
42    /// where `std` is available. If the encoding fails, error is
43    /// returned.
44    #[cfg(not(feature = "no_std"))]
45    #[allow(clippy::wrong_self_convention)]
46    fn to_writer(self, dst: &mut impl Write) -> Result<(), E>;
47}
48
49impl<'a, T: Into<EncodableField<'a>>> Encodable for T {
50    #[allow(clippy::wrong_self_convention)]
51    fn to_bytes(self, dst: &mut [u8]) -> Result<usize, Error> {
52        let encoded_field = self.into();
53        encoded_field.encode(dst, 0)
54    }
55
56    #[cfg(not(feature = "no_std"))]
57    #[allow(clippy::wrong_self_convention, unconditional_recursion)]
58    fn to_writer(self, dst: &mut impl Write) -> Result<(), E> {
59        let encoded_field = self.into();
60        encoded_field.to_writer(dst)
61    }
62}
63
64/// The `EncodablePrimitive` enum defines primitive types  that can be encoded.
65///
66/// The enum represents various data types, such a integers, bool, and byte array
67/// that can be encoded into a byte representation. Each variant holds a specific
68/// type, and encoding logic is provided through the `encode` method.
69#[derive(Debug)]
70pub enum EncodablePrimitive<'a> {
71    /// U8 Primitive, representing a byte
72    U8(u8),
73    /// Owned U8 Primitive, representing an owned byte
74    OwnedU8(u8),
75    /// U16 Primitive, representing a u16 type
76    U16(u16),
77    /// Bool Primitive, representing a bool type
78    Bool(bool),
79    /// U24 Primitive, representing a U24 type
80    U24(U24),
81    /// U256 Primitive, representing a U256 type
82    U256(U256<'a>),
83    /// Signature Primitive, representing a Signature type
84    Signature(Signature<'a>),
85    /// U32 Primitive, representing a u32 type
86    U32(u32),
87    /// U32AsRef Primitive, representing a U32AsRef type
88    U32AsRef(U32AsRef<'a>),
89    /// F32 Primitive, representing a f32 type
90    F32(f32),
91    /// U64 Primitive, representing a u64 type
92    U64(u64),
93    /// B032 Primitive, representing a B032 type
94    B032(B032<'a>),
95    /// B0255 Primitive, representing a B0255 type
96    B0255(B0255<'a>),
97    /// B064K Primitive, representing a B064K type
98    B064K(B064K<'a>),
99    /// B016M Primitive, representing a B016M type
100    B016M(B016M<'a>),
101}
102
103impl EncodablePrimitive<'_> {
104    // Provides the encoding logic for each primitive type.
105    //
106    // The `encode` method takes the `EncodablePrimitive` variant and serializes it
107    // into the destination buffer `dst`. The method returns the number of bytes written
108    // . If the buffer is too small or encoding fails, it returns an error.
109    fn encode(&self, dst: &mut [u8]) -> Result<usize, Error> {
110        match self {
111            Self::U8(v) => v.to_slice(dst),
112            Self::OwnedU8(v) => v.to_slice(dst),
113            Self::U16(v) => v.to_slice(dst),
114            Self::Bool(v) => v.to_slice(dst),
115            Self::U24(v) => v.to_slice(dst),
116            Self::U256(v) => v.to_slice(dst),
117            Self::Signature(v) => v.to_slice(dst),
118            Self::U32(v) => v.to_slice(dst),
119            Self::U32AsRef(v) => v.to_slice(dst),
120            Self::F32(v) => v.to_slice(dst),
121            Self::U64(v) => v.to_slice(dst),
122            Self::B032(v) => v.to_slice(dst),
123            Self::B0255(v) => v.to_slice(dst),
124            Self::B064K(v) => v.to_slice(dst),
125            Self::B016M(v) => v.to_slice(dst),
126        }
127    }
128
129    // Write the encoded object into the provided writer.
130    //
131    // Serializes the object and writes it directly to the
132    // provided writer. It is only available in environments where `std`
133    // is available.
134    #[cfg(not(feature = "no_std"))]
135    pub fn write(&self, writer: &mut impl Write) -> Result<(), E> {
136        match self {
137            Self::U8(v) => v.to_writer_(writer),
138            Self::OwnedU8(v) => v.to_writer_(writer),
139            Self::U16(v) => v.to_writer_(writer),
140            Self::Bool(v) => v.to_writer_(writer),
141            Self::U24(v) => v.to_writer_(writer),
142            Self::U256(v) => v.to_writer_(writer),
143            Self::Signature(v) => v.to_writer_(writer),
144            Self::U32(v) => v.to_writer_(writer),
145            Self::U32AsRef(v) => v.to_writer_(writer),
146            Self::F32(v) => v.to_writer_(writer),
147            Self::U64(v) => v.to_writer_(writer),
148            Self::B032(v) => v.to_writer_(writer),
149            Self::B0255(v) => v.to_writer_(writer),
150            Self::B064K(v) => v.to_writer_(writer),
151            Self::B016M(v) => v.to_writer_(writer),
152        }
153    }
154}
155
156// Provides the logic for calculating the size of the encodable field.
157impl GetSize for EncodablePrimitive<'_> {
158    fn get_size(&self) -> usize {
159        match self {
160            Self::U8(v) => v.get_size(),
161            Self::OwnedU8(v) => v.get_size(),
162            Self::U16(v) => v.get_size(),
163            Self::Bool(v) => v.get_size(),
164            Self::U24(v) => v.get_size(),
165            Self::U256(v) => v.get_size(),
166            Self::Signature(v) => v.get_size(),
167            Self::U32(v) => v.get_size(),
168            Self::U32AsRef(v) => v.get_size(),
169            Self::F32(v) => v.get_size(),
170            Self::U64(v) => v.get_size(),
171            Self::B032(v) => v.get_size(),
172            Self::B0255(v) => v.get_size(),
173            Self::B064K(v) => v.get_size(),
174            Self::B016M(v) => v.get_size(),
175        }
176    }
177}
178
179/// The [`EncodableField`] enum defines encodable fields, which may be a primitive or struct.
180///
181/// Each [`EncodableField`] represents either a primitive value or a collection of values
182/// (a struct). The encoding process for [`EncodableField`] supports nesting, allowing
183/// for complex hierarchical data structures to be serialized.
184#[derive(Debug)]
185pub enum EncodableField<'a> {
186    /// Represents a primitive value
187    ///
188    /// For the full supported list please see [`EncodablePrimitive`]
189    Primitive(EncodablePrimitive<'a>),
190    /// Represents a struct like field structure.
191    ///
192    /// Note that this is a recursive enum type.
193    Struct(Vec<EncodableField<'a>>),
194}
195
196impl EncodableField<'_> {
197    /// The `encode` method serializes a field into the destination buffer `dst`, starting
198    /// at the provided `offset`. If the field is a structure, it recursively encodes
199    /// each contained field. If the buffer is too small or encoding fails, the method
200    /// returns an error.
201    pub fn encode(&self, dst: &mut [u8], mut offset: usize) -> Result<usize, Error> {
202        match (self, dst.len() >= offset) {
203            (Self::Primitive(p), true) => p.encode(&mut dst[offset..]),
204            (Self::Struct(ps), true) => {
205                let mut result = 0;
206                for p in ps {
207                    let encoded_bytes = p.encode(dst, offset)?;
208                    offset += encoded_bytes;
209                    result += encoded_bytes;
210                }
211                Ok(result)
212            }
213            (_, false) => Err(Error::WriteError(offset, dst.len())),
214        }
215    }
216
217    #[cfg(not(feature = "no_std"))]
218    pub fn to_writer(&self, writer: &mut impl Write) -> Result<(), E> {
219        match self {
220            Self::Primitive(p) => p.write(writer),
221            Self::Struct(ps) => {
222                for p in ps {
223                    p.to_writer(writer)?;
224                }
225                Ok(())
226            }
227        }
228    }
229}
230
231impl GetSize for EncodableField<'_> {
232    fn get_size(&self) -> usize {
233        match self {
234            Self::Primitive(p) => p.get_size(),
235            Self::Struct(ps) => {
236                let mut size = 0;
237                for p in ps {
238                    size += p.get_size();
239                }
240                size
241            }
242        }
243    }
244}