// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 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"; // TODO add doctest #[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"; // TODO add doctest #[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`"; // TODO add doctest #[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)) } } /// Returns a `PeekBuffer` by `range` #[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() } } /// Borrows the buffer's slice. This should be used with caution, as it /// removes any panic protection this struct provides. #[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(Debug)] pub enum DecoderError { UnexpectedEof(usize), UnexpectedBytes(usize), LengthCapacityExceeded, InvariantViolation(&'static str), // TODO replace with a &'static Invariant } use core::fmt; impl fmt::Display for DecoderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // https://github.com/model-checking/kani/issues/1767#issuecomment-1275449305 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(), ); } }; }