Add docs to SSZ
This commit is contained in:
parent
16a8cdb714
commit
94ab2479fe
@ -2,6 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
pub mod impls;
|
pub mod impls;
|
||||||
|
|
||||||
|
/// Returned when SSZ decoding fails.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DecodeError {
|
pub enum DecodeError {
|
||||||
/// The bytes supplied were too short to be decoded into the specified type.
|
/// The bytes supplied were too short to be decoded into the specified type.
|
||||||
@ -21,7 +22,14 @@ pub enum DecodeError {
|
|||||||
BytesInvalid(String),
|
BytesInvalid(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides SSZ decoding (de-serialization) via the `from_ssz_bytes(&bytes)` method.
|
||||||
|
///
|
||||||
|
/// See `examples/` for manual implementations or the crate root for implementations using
|
||||||
|
/// `#[derive(Decode)]`.
|
||||||
pub trait Decodable: Sized {
|
pub trait Decodable: Sized {
|
||||||
|
/// Returns `true` if this object has a fixed-length.
|
||||||
|
///
|
||||||
|
/// I.e., there are no variable length items in this object or any of it's contained objects.
|
||||||
fn is_ssz_fixed_len() -> bool;
|
fn is_ssz_fixed_len() -> bool;
|
||||||
|
|
||||||
/// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes.
|
/// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes.
|
||||||
@ -33,6 +41,10 @@ pub trait Decodable: Sized {
|
|||||||
BYTES_PER_LENGTH_OFFSET
|
BYTES_PER_LENGTH_OFFSET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to decode `Self` from `bytes`, returning a `DecodeError` on failure.
|
||||||
|
///
|
||||||
|
/// The supplied bytes must be the exact length required to decode `Self`, excess bytes will
|
||||||
|
/// result in an error.
|
||||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError>;
|
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +54,12 @@ pub struct Offset {
|
|||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds an `SszDecoder`.
|
||||||
|
///
|
||||||
|
/// The purpose of this struct is to split some SSZ bytes into individual slices. The builder is
|
||||||
|
/// then converted into a `SszDecoder` which decodes those values into object instances.
|
||||||
|
///
|
||||||
|
/// See [`SszDecoder`](struct.SszDecoder.html) for usage examples.
|
||||||
pub struct SszDecoderBuilder<'a> {
|
pub struct SszDecoderBuilder<'a> {
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
items: Vec<&'a [u8]>,
|
items: Vec<&'a [u8]>,
|
||||||
@ -50,6 +68,8 @@ pub struct SszDecoderBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SszDecoderBuilder<'a> {
|
impl<'a> SszDecoderBuilder<'a> {
|
||||||
|
/// Instantiate a new builder that should build a `SszDecoder` over the given `bytes` which
|
||||||
|
/// are assumed to be the SSZ encoding of some object.
|
||||||
pub fn new(bytes: &'a [u8]) -> Self {
|
pub fn new(bytes: &'a [u8]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bytes,
|
bytes,
|
||||||
@ -59,6 +79,7 @@ impl<'a> SszDecoderBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declares that some type `T` is the next item in `bytes`.
|
||||||
pub fn register_type<T: Decodable>(&mut self) -> Result<(), DecodeError> {
|
pub fn register_type<T: Decodable>(&mut self) -> Result<(), DecodeError> {
|
||||||
if T::is_ssz_fixed_len() {
|
if T::is_ssz_fixed_len() {
|
||||||
let start = self.items_index;
|
let start = self.items_index;
|
||||||
@ -137,6 +158,7 @@ impl<'a> SszDecoderBuilder<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finalizes the builder, returning a `SszDecoder` that may be used to instantiate objects.
|
||||||
pub fn build(mut self) -> Result<SszDecoder<'a>, DecodeError> {
|
pub fn build(mut self) -> Result<SszDecoder<'a>, DecodeError> {
|
||||||
self.finalize()?;
|
self.finalize()?;
|
||||||
|
|
||||||
@ -144,6 +166,45 @@ impl<'a> SszDecoderBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decodes some slices of SSZ into object instances. Should be instantiated using
|
||||||
|
/// [`SszDecoderBuilder`](struct.SszDecoderBuilder.html).
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use ssz_derive::{Encode, Decode};
|
||||||
|
/// use ssz::{Decodable, Encodable, SszDecoder, SszDecoderBuilder};
|
||||||
|
///
|
||||||
|
/// #[derive(PartialEq, Debug, Encode, Decode)]
|
||||||
|
/// struct Foo {
|
||||||
|
/// a: u64,
|
||||||
|
/// b: Vec<u16>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let foo = Foo {
|
||||||
|
/// a: 42,
|
||||||
|
/// b: vec![1, 3, 3, 7]
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let bytes = foo.as_ssz_bytes();
|
||||||
|
///
|
||||||
|
/// let mut builder = SszDecoderBuilder::new(&bytes);
|
||||||
|
///
|
||||||
|
/// builder.register_type::<u64>().unwrap();
|
||||||
|
/// builder.register_type::<Vec<u16>>().unwrap();
|
||||||
|
///
|
||||||
|
/// let mut decoder = builder.build().unwrap();
|
||||||
|
///
|
||||||
|
/// let decoded_foo = Foo {
|
||||||
|
/// a: decoder.decode_next().unwrap(),
|
||||||
|
/// b: decoder.decode_next().unwrap(),
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(foo, decoded_foo);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub struct SszDecoder<'a> {
|
pub struct SszDecoder<'a> {
|
||||||
items: Vec<&'a [u8]>,
|
items: Vec<&'a [u8]>,
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,20 @@ use super::*;
|
|||||||
|
|
||||||
mod impls;
|
mod impls;
|
||||||
|
|
||||||
|
/// Provides SSZ encoding (serialization) via the `as_ssz_bytes(&self)` method.
|
||||||
|
///
|
||||||
|
/// See `examples/` for manual implementations or the crate root for implementations using
|
||||||
|
/// `#[derive(Encode)]`.
|
||||||
pub trait Encodable {
|
pub trait Encodable {
|
||||||
|
/// Returns `true` if this object has a fixed-length.
|
||||||
|
///
|
||||||
|
/// I.e., there are no variable length items in this object or any of it's contained objects.
|
||||||
fn is_ssz_fixed_len() -> bool;
|
fn is_ssz_fixed_len() -> bool;
|
||||||
|
|
||||||
|
/// Append the encoding `self` to `buf`.
|
||||||
|
///
|
||||||
|
/// Note, variable length objects need only to append their "variable length" portion, they do
|
||||||
|
/// not need to provide their offset.
|
||||||
fn ssz_append(&self, buf: &mut Vec<u8>);
|
fn ssz_append(&self, buf: &mut Vec<u8>);
|
||||||
|
|
||||||
/// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes.
|
/// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes.
|
||||||
@ -16,6 +27,9 @@ pub trait Encodable {
|
|||||||
BYTES_PER_LENGTH_OFFSET
|
BYTES_PER_LENGTH_OFFSET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the full-form encoding of this object.
|
||||||
|
///
|
||||||
|
/// The default implementation of this method should suffice for most cases.
|
||||||
fn as_ssz_bytes(&self) -> Vec<u8> {
|
fn as_ssz_bytes(&self) -> Vec<u8> {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
|
||||||
@ -29,6 +43,41 @@ pub trait Encodable {
|
|||||||
///
|
///
|
||||||
/// **You must call `finalize(..)` after the final `append(..)` call** to ensure the bytes are
|
/// **You must call `finalize(..)` after the final `append(..)` call** to ensure the bytes are
|
||||||
/// written to `buf`.
|
/// written to `buf`.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// Use `SszEncoder` to produce identical output to `foo.as_ssz_bytes()`:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use ssz_derive::{Encode, Decode};
|
||||||
|
/// use ssz::{Decodable, Encodable, SszEncoder};
|
||||||
|
///
|
||||||
|
/// #[derive(PartialEq, Debug, Encode, Decode)]
|
||||||
|
/// struct Foo {
|
||||||
|
/// a: u64,
|
||||||
|
/// b: Vec<u16>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let foo = Foo {
|
||||||
|
/// a: 42,
|
||||||
|
/// b: vec![1, 3, 3, 7]
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let mut buf: Vec<u8> = vec![];
|
||||||
|
/// let offset = <u64 as Encodable>::ssz_fixed_len() + <Vec<u16> as Encodable>::ssz_fixed_len();
|
||||||
|
///
|
||||||
|
/// let mut encoder = SszEncoder::container(&mut buf, offset);
|
||||||
|
///
|
||||||
|
/// encoder.append(&foo.a);
|
||||||
|
/// encoder.append(&foo.b);
|
||||||
|
///
|
||||||
|
/// encoder.finalize();
|
||||||
|
///
|
||||||
|
/// assert_eq!(foo.as_ssz_bytes(), buf);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub struct SszEncoder<'a> {
|
pub struct SszEncoder<'a> {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
buf: &'a mut Vec<u8>,
|
buf: &'a mut Vec<u8>,
|
||||||
@ -36,10 +85,14 @@ pub struct SszEncoder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SszEncoder<'a> {
|
impl<'a> SszEncoder<'a> {
|
||||||
|
/// Instantiate a new encoder for encoding a SSZ list.
|
||||||
|
///
|
||||||
|
/// Identical to `Self::container`.
|
||||||
pub fn list(buf: &'a mut Vec<u8>, num_fixed_bytes: usize) -> Self {
|
pub fn list(buf: &'a mut Vec<u8>, num_fixed_bytes: usize) -> Self {
|
||||||
Self::container(buf, num_fixed_bytes)
|
Self::container(buf, num_fixed_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiate a new encoder for encoding a SSZ container.
|
||||||
pub fn container(buf: &'a mut Vec<u8>, num_fixed_bytes: usize) -> Self {
|
pub fn container(buf: &'a mut Vec<u8>, num_fixed_bytes: usize) -> Self {
|
||||||
buf.reserve(num_fixed_bytes);
|
buf.reserve(num_fixed_bytes);
|
||||||
|
|
||||||
@ -50,6 +103,7 @@ impl<'a> SszEncoder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append some `item` to the SSZ bytes.
|
||||||
pub fn append<T: Encodable>(&mut self, item: &T) {
|
pub fn append<T: Encodable>(&mut self, item: &T) {
|
||||||
if T::is_ssz_fixed_len() {
|
if T::is_ssz_fixed_len() {
|
||||||
item.ssz_append(&mut self.buf);
|
item.ssz_append(&mut self.buf);
|
||||||
@ -61,6 +115,10 @@ impl<'a> SszEncoder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the variable bytes to `self.bytes`.
|
||||||
|
///
|
||||||
|
/// This method must be called after the final `append(..)` call when serializing
|
||||||
|
/// variable-length items.
|
||||||
pub fn finalize(&mut self) -> &mut Vec<u8> {
|
pub fn finalize(&mut self) -> &mut Vec<u8> {
|
||||||
self.buf.append(&mut self.variable_bytes);
|
self.buf.append(&mut self.variable_bytes);
|
||||||
|
|
||||||
|
@ -1,13 +1,52 @@
|
|||||||
|
//! Provides encoding (serialization) and decoding (deserialization) in the SimpleSerialize (SSZ)
|
||||||
|
//! format designed for use in Ethereum 2.0.
|
||||||
|
//!
|
||||||
|
//! Conforms to
|
||||||
|
//! [v0.6.1](https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/simple-serialize.md) of the
|
||||||
|
//! Ethereum 2.0 specification.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use ssz_derive::{Encode, Decode};
|
||||||
|
//! use ssz::{Decodable, Encodable};
|
||||||
|
//!
|
||||||
|
//! #[derive(PartialEq, Debug, Encode, Decode)]
|
||||||
|
//! struct Foo {
|
||||||
|
//! a: u64,
|
||||||
|
//! b: Vec<u16>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! let foo = Foo {
|
||||||
|
//! a: 42,
|
||||||
|
//! b: vec![1, 3, 3, 7]
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let ssz_bytes: Vec<u8> = foo.as_ssz_bytes();
|
||||||
|
//!
|
||||||
|
//! let decoded_foo = Foo::from_ssz_bytes(&ssz_bytes).unwrap();
|
||||||
|
//!
|
||||||
|
//! assert_eq!(foo, decoded_foo);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! See `examples/` for manual implementations of the `Encodable` and `Decodable` traits.
|
||||||
|
|
||||||
mod decode;
|
mod decode;
|
||||||
mod encode;
|
mod encode;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub use decode::{
|
pub use decode::{
|
||||||
impls::decode_list_of_variable_length_items, Decodable, DecodeError, SszDecoderBuilder,
|
impls::decode_list_of_variable_length_items, Decodable, DecodeError, SszDecoder,
|
||||||
|
SszDecoderBuilder,
|
||||||
};
|
};
|
||||||
pub use encode::{Encodable, SszEncoder};
|
pub use encode::{Encodable, SszEncoder};
|
||||||
|
|
||||||
|
/// The number of bytes used to represent an offset.
|
||||||
pub const BYTES_PER_LENGTH_OFFSET: usize = 4;
|
pub const BYTES_PER_LENGTH_OFFSET: usize = 4;
|
||||||
|
/// The maximum value that can be represented using `BYTES_PER_LENGTH_OFFSET`.
|
||||||
pub const MAX_LENGTH_VALUE: usize = (1 << (BYTES_PER_LENGTH_OFFSET * 8)) - 1;
|
pub const MAX_LENGTH_VALUE: usize = (1 << (BYTES_PER_LENGTH_OFFSET * 8)) - 1;
|
||||||
|
|
||||||
/// Convenience function to SSZ encode an object supporting ssz::Encode.
|
/// Convenience function to SSZ encode an object supporting ssz::Encode.
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
/// Implements `Encodable` for `$impl_type` using an implementation of `From<$impl_type> for
|
||||||
|
/// $from_type`.
|
||||||
|
///
|
||||||
|
/// In effect, this allows for easy implementation of `Encodable` for some type that implements a
|
||||||
|
/// `From` conversion into another type that already has `Encodable` implemented.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_encode_via_from {
|
macro_rules! impl_encode_via_from {
|
||||||
($impl_type: ty, $from_type: ty) => {
|
($impl_type: ty, $from_type: ty) => {
|
||||||
@ -19,6 +24,11 @@ macro_rules! impl_encode_via_from {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements `Decodable` for `$impl_type` using an implementation of `From<$impl_type> for
|
||||||
|
/// $from_type`.
|
||||||
|
///
|
||||||
|
/// In effect, this allows for easy implementation of `Decodable` for some type that implements a
|
||||||
|
/// `From` conversion into another type that already has `Decodable` implemented.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_decode_via_from {
|
macro_rules! impl_decode_via_from {
|
||||||
($impl_type: ty, $from_type: tt) => {
|
($impl_type: ty, $from_type: tt) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user