jam-std-common 0.1.29

Common datatypes and utilities for the JAM nodes and tooling
Documentation
use bytes::{Buf, Bytes};
use codec::{Decode, Input};

/// [`BytesCursor`] is a [`Bytes`] wrapper implementing [`Input`].
///
/// It supports zero-copy decoding of `Bytes` fields, and provides a
/// [`read_bytes`](Self::read_bytes) method which can be used to implement zero-copy decoding of
/// other types.
pub struct BytesCursor {
	bytes: Bytes,
	position: usize,
}

impl BytesCursor {
	/// Returns `true` iff there are no bytes left to read.
	pub fn is_empty(&self) -> bool {
		self.position == self.bytes.len()
	}

	/// Returns the number of bytes left to read.
	///
	/// Note that this is "infallible" in contrast to [`Input::remaining_len`], which can return
	/// `Err` or `Ok(None)`.
	pub fn infallible_remaining_len(&self) -> usize {
		self.bytes.len() - self.position
	}

	fn align(&mut self) {
		self.bytes.advance(self.position);
		self.position = 0;
	}

	/// Returns a reference to a [`Bytes`] object containing the remaining bytes.
	///
	/// The length of the `Bytes` should match `self.infallible_remaining_len()`.
	pub fn remaining(&mut self) -> &Bytes {
		self.align();
		&self.bytes
	}

	/// Read `len` bytes.
	///
	/// This is zero-copy; the returned `Bytes` uses the same underlying storage as the wrapped
	/// `Bytes` object.
	pub fn read_bytes(&mut self, len: usize) -> Result<Bytes, codec::Error> {
		self.align();
		if len > self.bytes.len() {
			return Err("Not enough data".into())
		}
		Ok(self.bytes.split_to(len))
	}

	/// Convenience method to decode a value and ensure all bytes are consumed.
	pub fn decode_all<T: Decode>(&mut self) -> Result<T, codec::Error> {
		let value = T::decode(self)?;
		if !self.is_empty() {
			return Err("Extraneous bytes".into())
		}
		Ok(value)
	}
}

impl Input for BytesCursor {
	fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
		Ok(Some(self.infallible_remaining_len()))
	}

	fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
		if into.len() > self.infallible_remaining_len() {
			return Err("Not enough data".into())
		}
		into.copy_from_slice(&self.bytes[self.position..self.position + into.len()]);
		self.position += into.len();
		Ok(())
	}

	fn scale_internal_decode_bytes(&mut self) -> Result<Bytes, codec::Error> {
		let length = <codec::Compact<u32>>::decode(self)?.0 as usize;
		self.read_bytes(length)
	}
}

impl From<Bytes> for BytesCursor {
	fn from(bytes: Bytes) -> Self {
		Self { bytes, position: 0 }
	}
}

impl From<Vec<u8>> for BytesCursor {
	fn from(vec: Vec<u8>) -> Self {
		Bytes::from(vec).into()
	}
}

unsafe impl castaway::LifetimeFree for BytesCursor {}