ssz 0.2.0

Simple serialization implementation
Documentation
use crate::{Encode, Decode, Error, LengthOffset};
use alloc::vec::Vec;
use alloc::collections::VecDeque;

#[derive(Eq, PartialEq, Clone, Debug)]
/// Item in a ssz series.
pub enum SeriesItem {
	/// Fixed-sized item.
	Fixed(Vec<u8>),
	/// Variable-sized item.
	Variable(Vec<u8>),
}

#[derive(Default, Eq, PartialEq, Clone, Debug)]
/// Represents a ssz series. Items in it can either be fixed-sized or
/// variable-sized.
pub struct Series(pub Vec<SeriesItem>);

impl Series {
	/// Encode the current series into raw bytes.
	pub fn encode(&self) -> Vec<u8> {
		let mut ret = Vec::new();

		let fixed_parts_size = self.0.iter().fold(0, |acc, part| {
			acc + match part {
				SeriesItem::Fixed(ref fixed) => fixed.len(),
				SeriesItem::Variable(_) => LengthOffset::default()
					.using_encoded(|buf| buf.len()),
			}
		});

		let mut offset = fixed_parts_size;

		for part in &self.0 {
			match part {
				SeriesItem::Fixed(ref fixed) => {
					ret.extend_from_slice(fixed);
				},
				SeriesItem::Variable(ref variable) => {
					(offset as LengthOffset).using_encoded(|buf| ret.extend_from_slice(buf));
					offset += variable.len();
				},
			}
		}

		for part in &self.0 {
			match part {
				SeriesItem::Fixed(_) => (),
				SeriesItem::Variable(ref variable) => {
					ret.extend_from_slice(variable);
				},
			}
		}

		ret
	}

	/// Decode raw bytes as a ssz vector, with given types. The length of types
	/// must equal to the length of values in the vector.
	pub fn decode_vector(value: &[u8], typs: &[Option<usize>]) -> Result<Self, Error> {
		let mut ret = Vec::new();
		let mut variable_offsets = VecDeque::new();

		let mut pos = 0;
		for typ in typs {
			match typ {
				Some(fixed_len) => {
					ret.push(
						SeriesItem::Fixed(value[pos..(pos + fixed_len)].to_vec())
					);
					pos += fixed_len;
				},
				None => {
					ret.push(SeriesItem::Variable(Default::default()));
					let len = LengthOffset::default().using_encoded(|buf| buf.len());
					variable_offsets.push_back(LengthOffset::decode(&value[pos..(pos + len)])? as usize);
					pos += len;
				},
			}
		}

		for part in &mut ret {
			match part {
				SeriesItem::Fixed(_) => (),
				SeriesItem::Variable(ref mut part) => {
					let offset = variable_offsets.pop_front().expect(
						"One variable offset is pushed with one variable item inserted; qed"
					) as usize;
					let next_offset = variable_offsets.front().map(|v| *v as usize)
						.unwrap_or(value.len());

					part.extend_from_slice(&value[offset..next_offset]);
				},
			}
		}

		Ok(Self(ret))
	}

	/// Decode raw bytes as a ssz list, with the given type.
	pub fn decode_list(value: &[u8], typ: Option<usize>) -> Result<Self, Error> {
		let mut ret = Vec::new();

		match typ {
			Some(fixed_len) => {
				let mut pos = 0;

				while pos + fixed_len <= value.len() {
					ret.push(
						SeriesItem::Fixed(value[pos..(pos + fixed_len)].to_vec())
					);
					pos += fixed_len;
				}
			},
			None => {
				let mut pos = 0;
				let mut variable_offsets = VecDeque::new();
				let fixed_len = LengthOffset::default().using_encoded(|buf| buf.len());

				while pos + fixed_len <= value.len() &&
					variable_offsets.front().map(|f| pos + fixed_len <= *f).unwrap_or(true)
				{
					variable_offsets.push_back(LengthOffset::decode(&value[pos..(pos + fixed_len)])? as usize);
					pos += fixed_len;
				}

				while let Some(offset) = variable_offsets.pop_front() {
					let offset = offset as usize;
					let next_offset = variable_offsets.front().map(|v| *v as usize)
						.unwrap_or(value.len());

					ret.push(
						SeriesItem::Variable(value[offset..next_offset].to_vec())
					);
				}
			},
		}

		Ok(Self(ret))
	}
}