Skip to content

Commit

Permalink
add all required docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Shourya742 committed Nov 11, 2024
1 parent 9185560 commit 11db59f
Show file tree
Hide file tree
Showing 9 changed files with 655 additions and 462 deletions.
87 changes: 32 additions & 55 deletions protocols/v2/binary-sv2/no-serde-sv2/codec/src/codec/decodable.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,3 @@
//! This module provides an interface and implementation details for decoding complex data structures
//! from raw bytes or I/O streams. It is intended to handle deserialization of nested and primitive data
//! structures by defining traits, enums, and helper functions for managing the decoding process.
//!
//! # Overview
//! The core component of this module is the `Decodable` trait, which provides methods for defining the
//! structure of a type, managing the decoding of raw byte data, and constructing instances of the type
//! from decoded fields. This trait is designed to work with both in-memory byte slices and I/O streams,
//! making it flexible for various deserialization use cases.
//!
//! # Key Concepts and Types
//! - **`Decodable` Trait**: The primary trait for decoding types from byte data. It includes methods to
//! break down raw data, decode individual fields, and construct the final type.
//! - **`FieldMarker` and `PrimitiveMarker`**: These enums represent different data types or structures.
//! They guide the decoding process by defining the structure of fields and their respective types.
//! - **`DecodableField` and `DecodablePrimitive`**: Variants for decoded fields, representing either
//! primitive types or nested structures. They form the building blocks for assembling complex data types.
//! - **`SizeHint`**: Provides size information for fields and structures to assist in efficient decoding.
//!
//! # Error Handling
//! This module defines custom error types to handle issues that may arise during decoding,
//! such as insufficient data or unsupported types. Errors are surfaced through `Result`
//! types and managed gracefully to ensure reliability in data parsing tasks.
//!
//! # `no_std` Support
//! The module is compatible with `no_std` environments by conditional compilation. When
//! the `no_std` feature is enabled, I/O-dependent methods like `from_reader` are omitted,
//! allowing for a lightweight build in constrained environments.
use crate::{
codec::{GetSize, SizeHint},
datatypes::{
Expand All @@ -50,23 +22,23 @@ use std::io::{Cursor, Read};
/// - `from_bytes`: High-level method that manages the decoding process from raw bytes.
/// - `from_reader`: Reads and decodes data from a stream, useful when working with I/O sources like files or network sockets.
pub trait Decodable<'a>: Sized {
// Returns the structure of the type.
//
// This method defines the layout of the data fields within the type. The structure
// returned is used to split raw data into individual fields that can be decoded.
/// Returns the structure of the type.
///
/// This method defines the layout of the data fields within the type. The structure
/// returned is used to split raw data into individual fields that can be decoded.
fn get_structure(data: &[u8]) -> Result<Vec<FieldMarker>, Error>;

// Constructs the type from decoded fields.
//
// After the data has been split into fields, this method combines those fields
// back into the original type, handling nested structures or composite fields.
/// Constructs the type from decoded fields.
///
/// After the data has been split into fields, this method combines those fields
/// back into the original type, handling nested structures or composite fields.
fn from_decoded_fields(data: Vec<DecodableField<'a>>) -> Result<Self, Error>;

// Decodes the type from raw bytes.
//
// This method orchestrates the decoding process, calling `get_structure` to break down
// the raw data, decoding each field, and then using `from_decoded_fields` to reassemble
// the fields into the original type.
/// Decodes the type from raw bytes.
///
/// This method orchestrates the decoding process, calling `get_structure` to break down
/// the raw data, decoding each field, and then using `from_decoded_fields` to reassemble
/// the fields into the original type.
fn from_bytes(data: &'a mut [u8]) -> Result<Self, Error> {
let structure = Self::get_structure(data)?;
let mut fields = Vec::new();
Expand All @@ -84,11 +56,11 @@ pub trait Decodable<'a>: Sized {
Self::from_decoded_fields(fields)
}

// Decodes the type from a reader stream.
//
// Instead of working directly with byte slices, this method reads from an I/O source
// like a file or a network stream. It processes all available data, decodes it, and
// reconstructs the type.
/// Decodes the type from a reader stream.
///
/// Instead of working directly with byte slices, this method reads from an I/O source
/// like a file or a network stream. It processes all available data, decodes it, and
/// reconstructs the type.
#[cfg(not(feature = "no_std"))]
fn from_reader(reader: &mut impl Read) -> Result<Self, Error> {
let mut data = Vec::new();
Expand All @@ -106,10 +78,10 @@ pub trait Decodable<'a>: Sized {
}
}

/// Enum representing primitive data markers.
///
/// These markers are used to identify primitive types such as integers, booleans, and byte arrays.
/// Each variant represents a specific type and is used during decoding to interpret raw data correctly.
// Enum representing primitive data markers.
//
// These markers are used to identify primitive types such as integers, booleans, and byte arrays.
// Each variant represents a specific type and is used during decoding to interpret raw data correctly.
#[derive(Debug, Clone, Copy)]
pub enum PrimitiveMarker {
U8,
Expand All @@ -135,7 +107,9 @@ pub enum PrimitiveMarker {
/// understand the layout and type of each field in the data, guiding the decoding process.
#[derive(Debug, Clone)]
pub enum FieldMarker {
/// Primitive Marker
Primitive(PrimitiveMarker),
/// Struct Marker
Struct(Vec<FieldMarker>),
}

Expand All @@ -145,14 +119,15 @@ pub enum FieldMarker {
/// type of a given field. It is used to assist in decoding by indicating how to interpret
/// the data.
pub trait GetMarker {
/// This helps getting a marker for a type
fn get_marker() -> FieldMarker;
}

/// Represents a decoded primitive data type.
///
/// After decoding, the raw data is transformed into one of these variants, which represent
/// standard primitive types like integers or binary arrays. The decoder uses these values to
/// build the final structure of the message.
// Represents a decoded primitive data type.
//
// After decoding, the raw data is transformed into one of these variants, which represent
// standard primitive types like integers or binary arrays. The decoder uses these values to
// build the final structure of the message.
#[derive(Debug)]
pub enum DecodablePrimitive<'a> {
U8(u8),
Expand All @@ -179,7 +154,9 @@ pub enum DecodablePrimitive<'a> {
/// distinction.
#[derive(Debug)]
pub enum DecodableField<'a> {
/// Represents DecodeablePrimitive
Primitive(DecodablePrimitive<'a>),
/// Represents vector of DecodableField
Struct(Vec<DecodableField<'a>>),
}

Expand Down
164 changes: 93 additions & 71 deletions protocols/v2/binary-sv2/no-serde-sv2/codec/src/codec/encodable.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
//! This module provides an encoding framework for serializing various data types into bytes.
//!
//! The primary trait, [`Encodable`], is the core of this framework, enabling types to define
//! how they serialize their data into bytes. This functionality is key for transmitting data
//! between different components or systems in a consistent, byte-oriented format.
//!
//! ## Overview
//!
//! The module supports a wide variety of data types, including basic types (e.g., integers,
//! booleans, and byte arrays) and more complex structures. Each type’s encoding logic is
//! contained within enums like [`EncodablePrimitive`] and [`EncodableField`], allowing for
//! structured and hierarchical data serialization.
//!
//! ### Key Types
//!
//! - **[`Encodable`]**: Defines methods for converting an object into a byte array or writing
//! it directly to an output stream. It supports both primitive data types and complex structures.
//! - **[`EncodablePrimitive`]**: Represents basic types that can be serialized directly.
//! Variants include common data types like integers, booleans, and byte arrays.
//! - **[`EncodableField`]**: Extends the [`EncodablePrimitive`] concept to support structured
//! and nested data, allowing complex structures to be encoded recursively.
//!
//! ### `no_std` Compatibility
//!
//! When compiled with the `no_std` feature enabled, this module omits the `to_writer` method
//! implementations to support environments without the standard library. Only buffer-based encoding
//! (`to_bytes`) is available in this mode.
//!
//! ## Error Handling
//!
//! Errors during encoding are managed through the [`Error`] type. Common failure scenarios include
//! buffer overflows and type-specific serialization errors. Each encoding method returns an
//! appropriate error if encoding fails, allowing for comprehensive error handling.
//!
//! ## Trait Details
//!
//! ### [`Encodable`]
//! - **`to_bytes`**: Encodes the instance directly into a provided byte slice, returning the number
//! of bytes written or an error if encoding fails.
//! - **`to_writer`** (requires `std`): Encodes the instance directly into any [`Write`] implementor,
//! such as a file or network stream.
//!
//! ### Additional Enums and Methods
//!
//! The module includes additional utility types and methods for calculating sizes, encoding
//! hierarchical data, and supporting both owned and reference-based data variants.
//!
//! - **[`EncodablePrimitive`]** provides the encoding logic for each primitive type, handling the
//! details of serialization based on type-specific requirements.
//! - **[`EncodableField`]** extends this to support composite types and structured data, allowing
//! for recursive encoding of nested data structures.
//! - **[`GetSize`]** (trait): Calculates the size of an encodable field in bytes, facilitating
//! buffer management and pre-allocation.
//!
//! ## Summary
//!
//! This module is designed for flexibility and extensibility, supporting a wide range of data
//! serialization needs through customizable encoding strategies. By implementing the
//! [`Encodable`] trait for custom types, users can leverage this framework to ensure efficient
//! and consistent data serialization across various applications.
// This module provides an encoding framework for serializing various data types into bytes.
//
// The primary trait, [`Encodable`], is the core of this framework, enabling types to define
// how they serialize their data into bytes. This functionality is key for transmitting data
// between different components or systems in a consistent, byte-oriented format.
//
// ## Overview
//
// The module supports a wide variety of data types, including basic types (e.g., integers,
// booleans, and byte arrays) and more complex structures. Each type’s encoding logic is
// contained within enums like [`EncodablePrimitive`] and [`EncodableField`], allowing for
// structured and hierarchical data serialization.
//
// ### Key Types
//
// - **[`Encodable`]**: Defines methods for converting an object into a byte array or writing
// it directly to an output stream. It supports both primitive data types and complex structures.
// - **[`EncodablePrimitive`]**: Represents basic types that can be serialized directly.
// Variants include common data types like integers, booleans, and byte arrays.
// - **[`EncodableField`]**: Extends the [`EncodablePrimitive`] concept to support structured
// and nested data, allowing complex structures to be encoded recursively.
//
// ### `no_std` Compatibility
//
// When compiled with the `no_std` feature enabled, this module omits the `to_writer` method
// implementations to support environments without the standard library. Only buffer-based encoding
// (`to_bytes`) is available in this mode.
//
// ## Error Handling
//
// Errors during encoding are managed through the [`Error`] type. Common failure scenarios include
// buffer overflows and type-specific serialization errors. Each encoding method returns an
// appropriate error if encoding fails, allowing for comprehensive error handling.
//
// ## Trait Details
//
// ### [`Encodable`]
// - **`to_bytes`**: Encodes the instance directly into a provided byte slice, returning the number
// of bytes written or an error if encoding fails.
// - **`to_writer`** (requires `std`): Encodes the instance directly into any [`Write`] implementor,
// such as a file or network stream.
//
// ### Additional Enums and Methods
//
// The module includes additional utility types and methods for calculating sizes, encoding
// hierarchical data, and supporting both owned and reference-based data variants.
//
// - **[`EncodablePrimitive`]** provides the encoding logic for each primitive type, handling the
// details of serialization based on type-specific requirements.
// - **[`EncodableField`]** extends this to support composite types and structured data, allowing
// for recursive encoding of nested data structures.
// - **[`GetSize`]** (trait): Calculates the size of an encodable field in bytes, facilitating
// buffer management and pre-allocation.
//
// ## Summary
//
// This module is designed for flexibility and extensibility, supporting a wide range of data
// serialization needs through customizable encoding strategies. By implementing the
// [`Encodable`] trait for custom types, users can leverage this framework to ensure efficient
// and consistent data serialization across various applications.

use crate::{
codec::GetSize,
Expand Down Expand Up @@ -90,20 +90,20 @@ use std::io::{Error as E, Write};
/// especially useful when dealing with different data structures that need
/// to be serialized for transmission.
pub trait Encodable {
// Encodes the object into the provided byte slice.
//
// The method uses the destination buffer `dst` to write the serialized
// bytes. It returns the number of bytes written on success or an `Error`
// if encoding fails.
/// Encodes the object into the provided byte slice.
///
/// The method uses the destination buffer `dst` to write the serialized
/// bytes. It returns the number of bytes written on success or an `Error`
/// if encoding fails.
#[allow(clippy::wrong_self_convention)]
fn to_bytes(self, dst: &mut [u8]) -> Result<usize, Error>;

// Write the encoded object into the provided writer.
//
// This method serializes the object and writes it directly
// to the `dst` writer. It is only available in environments
// where `std` is available. If the encoding fails, error is
// returned.
/// Write the encoded object into the provided writer.
///
/// This method serializes the object and writes it directly
/// to the `dst` writer. It is only available in environments
/// where `std` is available. If the encoding fails, error is
/// returned.
#[cfg(not(feature = "no_std"))]
#[allow(clippy::wrong_self_convention)]
fn to_writer(self, dst: &mut impl Write) -> Result<(), E>;
Expand Down Expand Up @@ -132,21 +132,37 @@ impl<'a, T: Into<EncodableField<'a>>> Encodable for T {
/// type, and encoding logic is provided through the `encode` method.
#[derive(Debug)]
pub enum EncodablePrimitive<'a> {
/// U8 Primitive, representing a byte
U8(u8),
/// Owned U8 Primitive, representing an owned byte
OwnedU8(u8),
/// U16 Primitive, representing a u16 type
U16(u16),
/// Bool Primitive, representing a bool type
Bool(bool),
/// U24 Primitive, representing a U24 type
U24(U24),
/// U256 Primitive, representing a U256 type
U256(U256<'a>),
/// ShortTxId Primitive, representing a ShortTxId type
ShortTxId(ShortTxId<'a>),
/// Signature Primitive, representing a Signature type
Signature(Signature<'a>),
/// U32 Primitive, representing a u32 type
U32(u32),
/// U32AsRef Primitive, representing a U32AsRef type
U32AsRef(U32AsRef<'a>),
/// F32 Primitive, representing a f32 type
F32(f32),
/// U64 Primitive, representing a u64 type
U64(u64),
/// B032 Primitive, representing a B032 type
B032(B032<'a>),
/// B0255 Primitive, representing a B0255 type
B0255(B0255<'a>),
/// B064K Primitive, representing a B064K type
B064K(B064K<'a>),
/// B016M Primitive, representing a B016M type
B016M(B016M<'a>),
}

Expand Down Expand Up @@ -237,7 +253,9 @@ impl<'a> GetSize for EncodablePrimitive<'a> {
/// for complex hierarchical data structures to be serialized.
#[derive(Debug)]
pub enum EncodableField<'a> {
/// Represents an encodablePrimitive
Primitive(EncodablePrimitive<'a>),
/// Represents a structure of multiple Encodable Field
Struct(Vec<EncodableField<'a>>),
}

Expand All @@ -248,6 +266,10 @@ pub enum EncodableField<'a> {
/// each contained field. If the buffer is too small or encoding fails, the method
/// returns an error.
impl<'a> EncodableField<'a> {
/// The `encode` method serializes a field into the destination buffer `dst`, starting
/// at the provided `offset`. If the field is a structure, it recursively encodes
/// each contained field. If the buffer is too small or encoding fails, the method
/// returns an error.
pub fn encode(&self, dst: &mut [u8], mut offset: usize) -> Result<usize, Error> {
match (self, dst.len() >= offset) {
(Self::Primitive(p), true) => p.encode(&mut dst[offset..]),
Expand Down
Loading

0 comments on commit 11db59f

Please sign in to comment.