Expand description

A crate that provides a Packable trait to serialize and deserialize types.

For more information about the design of this crate please read the Packable, unpacker, packer, UnpackError and UnpackErrorExt documentation.

Motivation

This crate was written as a no_std replacement for the Packable serialization framework used in the Bee node implementation for Chrysalis Part 2.

The old Packable trait

The need for a serialization API existed before Coordicide. Efforts to satisfy this need culminated with the introduction of the Packable trait in the bee-common crate during the Chrysalis part 2 period. Most of the design decisions behind this crate were done to simplify the serialization of the IOTA protocol messages. The proposed trait was the following:

use std::io::{Read, Write};

pub trait Packable {
    type Error: std::fmt::Debug;

    fn packed_len(&self) -> usize;

    fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error>;

    fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
    where
        Self: Sized;
}

The main issue with this trait is that it cannot be used in a no_std environment because it depends explicitly on the std::io API, whose transition to the core crate has not been decided yet. Another issue is that the Error type is used to represent three different kinds of errors:

  • Writing errors: Raised when there are issues while writing bytes.
  • Reading errors: Raised when there are issues while reading bytes.
  • Deserialization errors: Raised when the bytes being used to create a value are invalid for the data layout of such value.

Replacing std::io

We introduced the Packer and Unpacker taits to abstract away any IO operation without relying on std::io. This has the additional benefit of allowing us to pack and unpack values from different kinds of buffers.

Types that implement Packable

The Packable trait is implemented for every integer type by encoding the value as an array of bytes in little-endian order. Booleans are packed following Rust’s data layout, meaning that true is packed as a 1 byte and false as a 0 byte. However, boolean unpacking is less strict and unpacks any non-zero byte as true. Additional implementations of Packable are provided for Vec<T>, Box<[T]>, [T; N] and Option<T> if T implements Packable.

Check the Packable impl section for further information.

Modules

Types and utilities related to bounded integers.

Errors related to packable operations.

Types and utilities related to packing and unpacking Option values.

A module to pack any value that implements Packable.

Types and utilities used to pack and unpack dynamic sequences of values with restricted length prefixes.

A module to unpack any value that implements Packable.

Traits

A type that can be packed and unpacked.

Extension trait for types that implement Packable.

Derive Macros