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}