macro_rules! doc_comment {
($($x:expr)*; $($tt:tt)*) => {
doc_comment!(@doc concat!($($x, "\n",)*), $($tt)*);
};
(@doc $x:expr, $($tt:tt)*) => {
#[doc = $x]
$($tt)*
};
}
macro_rules! impl_buffer {
($name:ident, $result:ident, $value:ident, $value_call:ident, $parameterized:ident, $parameterized_call:ident, $split:ident) => {
impl<'a> $name<'a> {
doc_comment! {
"Decode a slice of bytes by `count`, removing the slice from the current buffer"
"```"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2, 3, 4];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"let (slice, buffer) = buffer.decode_slice(5).unwrap();"
"assert_eq!(slice, [0u8, 1, 2, 3, 4][..]);"
""
"assert!(buffer.is_empty());"
"```";
#[inline]
pub fn decode_slice(self, count: usize) -> $result<'a, $name<'a>> {
self.ensure_len(count)?;
let (slice, remaining) = self.bytes.$split(count);
Ok((Self::new(slice), Self::new(remaining)))
}
}
doc_comment! {
"Decode a value of type `T`, splitting the data from the current buffer"
"```"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2, 3, 4, 5, 6];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"let (value, buffer) = buffer.decode::<u8>().unwrap();"
"assert_eq!(value, 0);"
""
"let (value, buffer) = buffer.decode::<u16>().unwrap();"
"assert_eq!(value, 258);"
""
"let (value, buffer) = buffer.decode::<u32>().unwrap();"
"assert_eq!(value, 50_595_078);"
""
"assert!(buffer.is_empty());"
"```";
#[inline]
pub fn decode<T: $value<'a>>(self) -> $result<'a, T> {
T::$value_call(self)
}
}
doc_comment! {
"Decode a slice prefixed by type `Length`, splitting the data from the"
"current buffer."
"With a `Length` as encoded `u8`:"
"```rust"
"# use s2n_codec::*;"
"let mut data = [5, 0, 1, 2, 3, 4];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let (slice, buffer) = buffer.decode_slice_with_len_prefix::<u8>().unwrap();"
"assert_eq!(slice, [0u8, 1, 2, 3, 4][..]);"
"assert!(buffer.is_empty())"
"```"
"With a `Length` as encoded `u16`:"
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 5, 0, 1, 2, 3, 4];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let (slice, buffer) = buffer.decode_slice_with_len_prefix::<u16>().unwrap();"
"assert_eq!(slice, [0u8, 1, 2, 3, 4][..]);"
"assert!(buffer.is_empty())"
"```";
#[inline]
pub fn decode_slice_with_len_prefix<Length: $value<'a> + core::convert::TryInto<usize>>(
self,
) -> $result<'a, Self> {
let (len, buffer) = self.decode::<Length>()?;
let len = len.try_into().map_err(|_| DecoderError::LengthCapacityExceeded)?;
buffer.decode_slice(len)
}
}
doc_comment! {
"Decode a value of type `T` prefixed by type `Length`, splitting the data from the"
"current buffer."
"With a `Length` as encoded `u8` and `T` as `u16`:"
"```rust"
"# use s2n_codec::*;"
"let mut data = [2, 0, 1, 2, 3];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let (value, buffer) = buffer.decode_with_len_prefix::<u8, u16>().unwrap();"
"assert_eq!(value, 1);"
"assert_eq!(buffer, [2, 3][..])"
"```"
concat!("The `", stringify!($value) ,"` implementation of `T` must consume the entire subslice")
"otherwise an error will be returned."
"```rust"
"# use s2n_codec::*;"
"let mut data = [3, 0, 1, 2];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let result = buffer.decode_with_len_prefix::<u8, u16>();"
"assert!(result.is_err())"
"```";
#[inline]
pub fn decode_with_len_prefix<Length: $value<'a> + core::convert::TryInto<usize>, T: $value<'a>>(
self,
) -> $result<'a, T> {
let (slice, buffer) = self.decode_slice_with_len_prefix::<Length>()?;
let (value, slice) = slice.decode::<T>()?;
slice.ensure_empty()?;
Ok((value, buffer))
}
}
doc_comment! {
"Decode a parameterized value of type `T` implementing `"
stringify!($parameterized) "`";
#[inline]
pub fn decode_parameterized<T: $parameterized<'a>>(
self,
parameter: T::Parameter,
) -> $result<'a, T> {
T::$parameterized_call(parameter, self)
}
}
doc_comment! {
"Skip a `count` of bytes, discarding the bytes"
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2, 3, 4];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let buffer = buffer.skip(3).unwrap();"
"assert_eq!(buffer, [3, 4][..]);"
"```";
#[inline]
pub fn skip(self, count: usize) -> Result<$name<'a>, DecoderError> {
self.decode_slice(count).map(|(_, buffer)| buffer)
}
}
doc_comment! {
"Skip a number of bytes encoded as a length prefix of type `Length`"
"With a `Length` encoded as `u8`:"
"```rust"
"# use s2n_codec::*;"
"let mut data = [5, 0, 1, 2, 3, 4];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
"let buffer = buffer.skip_with_len_prefix::<u8>().unwrap();"
"assert!(buffer.is_empty());"
"```";
#[inline]
pub fn skip_with_len_prefix<Length: $value<'a> + core::convert::TryInto<usize>>(
self,
) -> Result<$name<'a>, DecoderError> {
let (len, buffer) = self.decode::<Length>()?;
let len = len.try_into().map_err(|_| DecoderError::LengthCapacityExceeded)?;
buffer.skip(len)
}
}
doc_comment! {
"Skip a `count` of bytes, returning a `CheckedRange` for later access";
#[inline]
pub fn skip_into_range(
self,
count: usize,
original_buffer: &crate::DecoderBufferMut,
) -> $result<'a, crate::CheckedRange> {
let start = original_buffer.len() - self.len();
let (slice, buffer) = self.decode_slice(count)?;
let end = start + count;
Ok((
crate::CheckedRange::new(start, end, slice.bytes.as_ptr()),
buffer,
))
}
}
doc_comment! {
"Skip a number of bytes encoded as a length prefix of type `Length`"
"into a `CheckedRange` for later access";
#[inline]
pub fn skip_into_range_with_len_prefix<Length: $value<'a> + core::convert::TryInto<usize>>(
self,
original_buffer: &crate::DecoderBufferMut,
) -> $result<'a, crate::CheckedRange> {
let (len, buffer) = self.decode::<Length>()?;
let len = len.try_into().map_err(|_| DecoderError::LengthCapacityExceeded)?;
buffer.skip_into_range(len, original_buffer)
}
}
doc_comment! {
"Reads data from a `CheckedRange`";
#[inline]
pub fn get_checked_range(&self, range: &crate::CheckedRange) -> DecoderBuffer {
range.get(self.bytes).into()
}
}
doc_comment! {
"Create a peeking `DecoderBuffer` from the current buffer view"
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 1];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"let peek = buffer.peek();"
"let (value, peek) = peek.decode::<u16>().unwrap();"
"assert_eq!(value, 1);"
"assert!(peek.is_empty());"
""
"// `buffer` still contains the previous view"
"assert_eq!(buffer, [0, 1][..]);"
"```";
#[inline]
#[must_use]
pub fn peek(&'a self) -> crate::DecoderBuffer<'a> {
crate::DecoderBuffer::new(self.bytes)
}
}
doc_comment! {
"Returns a single byte at `index`"
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"assert_eq!(buffer.peek_byte(0).unwrap(), 0);"
"assert_eq!(buffer.peek_byte(1).unwrap(), 1);"
"assert_eq!(buffer.peek_byte(2).unwrap(), 2);"
""
"// `buffer` has not changed"
"assert_eq!(buffer, [0, 1, 2][..]);"
"```";
#[inline]
pub fn peek_byte(&self, index: usize) -> Result<u8, DecoderError> {
self.bytes
.get(index)
.cloned()
.ok_or_else(|| DecoderError::UnexpectedEof(index))
}
}
#[inline]
pub fn peek_range(
&self,
range: core::ops::Range<usize>,
) -> Result<crate::DecoderBuffer, DecoderError> {
let end = range.end;
self.bytes
.get(range)
.map(|bytes| bytes.into())
.ok_or_else(|| DecoderError::UnexpectedEof(end))
}
doc_comment! {
"Returns an error if the buffer is not empty."
"```rust"
"# use s2n_codec::*;"
"let mut data = [1];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"assert!(buffer.ensure_empty().is_err());"
"let (_, buffer) = buffer.decode::<u8>().unwrap();"
"assert!(buffer.ensure_empty().is_ok());"
"```";
#[inline]
pub fn ensure_empty(&self) -> Result<(), DecoderError> {
if !self.is_empty() {
Err(DecoderError::UnexpectedBytes(self.len()))
} else {
Ok(())
}
}
}
doc_comment! {
"Returns an error if the buffer does not have at least `len` bytes."
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"assert!(buffer.ensure_len(2).is_ok());"
"assert!(buffer.ensure_len(5).is_err());"
"```";
#[inline]
pub fn ensure_len(&self, len: usize) -> Result<(), DecoderError> {
if self.len() < len {
Err(DecoderError::UnexpectedEof(len))
} else {
Ok(())
}
}
}
doc_comment! {
"Returns the number of bytes in the buffer."
"```rust"
"# use s2n_codec::*;"
"let mut data = [0, 1, 2];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"assert_eq!(buffer.len(), 3);"
"let (_, buffer) = buffer.decode::<u8>().unwrap();"
"assert_eq!(buffer.len(), 2);"
"```";
#[inline]
pub fn len(&self) -> usize {
self.bytes.len()
}
}
doc_comment! {
"Returns true if the buffer has a length of 0."
"```rust"
"# use s2n_codec::*;"
"let mut data = [1];"
concat!("let buffer = ", stringify!($name), "::new(&mut data);")
""
"assert!(!buffer.is_empty());"
"let (_, buffer) = buffer.decode::<u8>().unwrap();"
"assert!(buffer.is_empty());"
"```";
#[inline]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
#[inline]
pub fn as_less_safe_slice(&'a self) -> &'a [u8] {
self.bytes
}
}
impl<'a> From<&'a mut [u8]> for $name<'a> {
#[inline]
fn from(bytes: &'a mut [u8]) -> Self {
Self::new(bytes)
}
}
impl<'a> PartialEq<[u8]> for $name<'a> {
#[inline]
fn eq(&self, rhs: &[u8]) -> bool {
let bytes: &[u8] = self.bytes.as_ref();
bytes.eq(rhs)
}
}
};
}
pub mod buffer;
pub mod buffer_mut;
pub mod checked_range;
#[macro_use]
pub mod value;
pub use buffer::*;
pub use buffer_mut::*;
pub use checked_range::*;
pub use value::*;
#[derive(Clone, Copy, Debug)]
pub enum DecoderError {
UnexpectedEof(usize),
UnexpectedBytes(usize),
LengthCapacityExceeded,
InvariantViolation(&'static str), }
use core::fmt;
impl fmt::Display for DecoderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if cfg!(kani) {
return Ok(());
}
match self {
Self::UnexpectedEof(len) => write!(f, "unexpected eof: {len}"),
Self::UnexpectedBytes(len) => write!(f, "unexpected bytes: {len}"),
Self::LengthCapacityExceeded => write!(
f,
"length could not be represented in platform's usize type"
),
Self::InvariantViolation(msg) => write!(f, "{msg}"),
}
}
}
impl From<DecoderError> for &'static str {
fn from(error: DecoderError) -> Self {
match error {
DecoderError::UnexpectedEof(_len) => "unexpected eof",
DecoderError::UnexpectedBytes(_len) => "unexpected bytes",
DecoderError::LengthCapacityExceeded => {
"length could not be represented in platform's usize type"
}
DecoderError::InvariantViolation(msg) => msg,
}
}
}
#[macro_export]
macro_rules! decoder_invariant {
($expr:expr, $invariant:expr) => {
if !($expr) {
return ::core::result::Result::Err(
$crate::decoder::DecoderError::InvariantViolation($invariant).into(),
);
}
};
}