diff --git a/benches/simple.rs b/benches/simple.rs index 53c00f9..59bb719 100644 --- a/benches/simple.rs +++ b/benches/simple.rs @@ -1,30 +1,28 @@ use std::time::Instant; -use compact_encoding::{CompactEncoding, State}; +use compact_encoding::{map_decode, map_encode, sum_encoded_size, CompactEncoding, EncodingError}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; const U32_VALUE: u32 = 0xF0E1D2C3; const STR_VALUE: &str = "foo"; const U64_VALUE: u64 = u64::MAX; -fn preencode() -> State { - let mut enc_state = State::new(); - enc_state.preencode(&U32_VALUE).unwrap(); - enc_state.preencode_str(STR_VALUE).unwrap(); - enc_state.preencode(&U64_VALUE).unwrap(); - enc_state +fn preencode() -> Result { + Ok(sum_encoded_size!(U32_VALUE, STR_VALUE, U64_VALUE)) } -fn encode(enc_state: &mut State, buffer: &mut [u8]) { - enc_state.encode(&U32_VALUE, buffer).unwrap(); - enc_state.encode_str(STR_VALUE, buffer).unwrap(); - enc_state.encode(&U64_VALUE, buffer).unwrap(); +fn encode(buffer: &mut [u8]) -> Result<(), EncodingError> { + let _ = map_encode!(buffer, U32_VALUE, STR_VALUE, U64_VALUE); + Ok(()) } -fn decode(dec_state: &mut State, buffer: &[u8]) { - let _: u32 = dec_state.decode(buffer).unwrap(); - let _: String = dec_state.decode(buffer).unwrap(); - let _: u64 = dec_state.decode(buffer).unwrap(); +fn decode(buffer: &[u8]) -> Result<(), EncodingError> { + map_decode!(buffer, [u32, String, u64]); + Ok(()) +} + +fn create_buffer(encoded_size: usize) -> Box<[u8]> { + vec![0; encoded_size].into_boxed_slice() } fn preencode_generic_simple(c: &mut Criterion) { @@ -36,10 +34,10 @@ fn preencode_generic_simple(c: &mut Criterion) { fn create_buffer_generic_simple(c: &mut Criterion) { c.bench_function("create buffer generic simple", |b| { b.iter_custom(|iters| { - let enc_state = preencode(); + let encoded_size = preencode().unwrap(); let start = Instant::now(); for _ in 0..iters { - black_box(enc_state.create_buffer()); + black_box(create_buffer(encoded_size)); } start.elapsed() }); @@ -50,13 +48,12 @@ fn create_buffer_generic_simple(c: &mut Criterion) { fn encode_generic_simple(c: &mut Criterion) { c.bench_function("encode generic simple", |b| { b.iter_custom(|iters| { - let enc_state = preencode(); - let buffer = enc_state.create_buffer(); + let encoded_size = preencode().unwrap(); + let buffer = create_buffer(encoded_size); let start = Instant::now(); for _ in 0..iters { - let mut enc_state = enc_state.clone(); let mut buffer = buffer.clone(); - black_box(encode(&mut enc_state, &mut buffer)); + black_box(encode(&mut buffer).unwrap()); } start.elapsed() }); @@ -67,15 +64,13 @@ fn encode_generic_simple(c: &mut Criterion) { fn decode_generic_simple(c: &mut Criterion) { c.bench_function("decode generic simple", |b| { b.iter_custom(|iters| { - let mut enc_state = preencode(); - let mut buffer = enc_state.create_buffer(); - encode(&mut enc_state, &mut buffer); - let dec_state = State::from_buffer(&buffer); + let encoded_size = preencode().unwrap(); + let mut buffer = vec![0_u8; encoded_size]; + encode(&mut buffer).unwrap(); let start = Instant::now(); for _ in 0..iters { - let mut dec_state = dec_state.clone(); let buffer = buffer.clone(); - black_box(decode(&mut dec_state, &buffer)); + black_box(decode(&buffer).unwrap()); } start.elapsed() }); diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..04b8f4a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,93 @@ +//! Basic types of compact_encoding. +use std::fmt; + +/// Specific type [EncodingError] +#[derive(fmt::Debug, Clone, PartialEq)] +pub enum EncodingErrorKind { + /// Encoding or decoding did not stay within the bounds of the buffer + OutOfBounds, + /// Buffer data overflowed type during encoding or decoding. + Overflow, + /// Buffer contained invalid data during decoding. + InvalidData, + /// Some external error occurred causing a [`crate::CompactEncoding`] method to fail. + External, +} + +/// Encoding/decoding error. +#[derive(fmt::Debug, Clone, PartialEq)] +pub struct EncodingError { + /// Specific type of error + pub kind: EncodingErrorKind, + /// Message for the error + pub message: String, +} + +impl std::error::Error for EncodingError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +impl EncodingError { + /// Create EncodingError + pub fn new(kind: EncodingErrorKind, message: &str) -> Self { + Self { + kind, + message: message.to_string(), + } + } + /// Helper function for making an overflow error + pub fn overflow(message: &str) -> Self { + Self { + kind: EncodingErrorKind::Overflow, + message: message.to_string(), + } + } + /// Helper function for making an out of bounds error + pub fn out_of_bounds(message: &str) -> Self { + Self { + kind: EncodingErrorKind::OutOfBounds, + message: message.to_string(), + } + } + /// Helper function for making an invalid data error + pub fn invalid_data(message: &str) -> Self { + Self { + kind: EncodingErrorKind::InvalidData, + message: message.to_string(), + } + } + /// Helper function for making an invalid data error + pub fn external(message: &str) -> Self { + Self { + kind: EncodingErrorKind::External, + message: message.to_string(), + } + } +} + +impl fmt::Display for EncodingError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let prefix = match self.kind { + EncodingErrorKind::OutOfBounds => "Compact encoding failed, out of bounds", + EncodingErrorKind::Overflow => "Compact encoding failed, overflow", + EncodingErrorKind::InvalidData => "Compact encoding failed, invalid data", + EncodingErrorKind::External => { + "An external error caused a compact encoding operation to fail" + } + }; + write!(f, "{}: {}", prefix, self.message,) + } +} + +impl From for std::io::Error { + fn from(e: EncodingError) -> Self { + match e.kind { + EncodingErrorKind::InvalidData => { + std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{e}")) + } + _ => std::io::Error::new(std::io::ErrorKind::Other, format!("{e}")), + } + } +} diff --git a/src/fixedwidth.rs b/src/fixedwidth.rs new file mode 100644 index 0000000..4ed4819 --- /dev/null +++ b/src/fixedwidth.rs @@ -0,0 +1,164 @@ +//! Allow encoding of unsigned ints in a fixed width way, instead of the default variable width. +//! +//! Why? Because the default [`CompactEncoding`] implementation for unsigned integers uses a +//! variable width encoding. However sometimes want them encoded with a fixed width, +//! [`FixedWidthEncoding`] lets us do this. To fixed width encode an unsigned integrer simply call +//! [`FixedWidthEncoding::as_fixed_width`] on it. Like this: +//! ``` +//! # use compact_encoding::EncodingError; +//! use compact_encoding::{to_encoded_bytes, FixedWidthEncoding}; +//! let buff = to_encoded_bytes!(42u32.as_fixed_width()); +//! assert_eq!(buff, [42, 0, 0, 0].into()); +//! // vs variable width +//! let buff = to_encoded_bytes!(42u32); +//! assert_eq!(buff, [42].into()); +//! # Ok::<(), Box>(()) +//! ``` +//! +//! Likewise when decoding decoding from a fixed width encoded buffer you use +//! [`FixedWidthUint::decode`] which will decode to the underlying unsigned integer type. +//! So: `FixedWidthUint::decode(buffer) -> u32`. +//! Note that we also provide type aliases to make this more ergonomic: +//! `FixedWidthU64 = FixedWidthUint]); +//! assert_eq!(decoded, 42); // NOT! FixedWidthUint(42_u32) +//! +//! assert_eq!(map_decode!(&buff, [FixedWidthU32]).0 .0, 42); // or using the alias +//! # Ok::<(), Box>(()) +//! ``` + +use crate::{ + decode_u32, decode_u64, encode_u32, encode_u64, CompactEncoding, EncodingError, U32_SIZE, + U64_SIZE, +}; + +/// Implents functionality needed to encode unisegned integrer in a fixed width way with +/// [`CompactEncoding`] +pub trait FixedWidthEncoding { + /// The type we decode to + // TODO could we just use T? + type Decode; + /// The size in bytes required to encode `self`. + fn fw_encoded_size(&self) -> Result; + + /// Encode `self` into `buffer` returning the remainder of `buffer`. + fn fw_encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError>; + + /// Decode a value from the given `buffer` of the type specified by the `Decode` type parameter + /// (which defaults to `Self`). Returns the decoded value and remaining undecoded bytes. + fn fw_decode(buffer: &[u8]) -> Result<(Self::Decode, &[u8]), EncodingError> + where + Self: Sized; + + /// Get a uint in a form that encodes to a fixed width + fn as_fixed_width(&self) -> FixedWidthUint { + FixedWidthUint(self) + } +} + +/// A fixed width encodable unsigned integer +#[derive(Debug)] +pub struct FixedWidthUint<'a, T: FixedWidthEncoding + ?Sized>(&'a T); + +impl CompactEncoding for FixedWidthUint<'_, T> { + fn encoded_size(&self) -> Result { + self.0.fw_encoded_size() + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + self.0.fw_encode(buffer) + } + + fn decode(buffer: &[u8]) -> Result<(T::Decode, &[u8]), EncodingError> + where + Self: Sized, + { + ::fw_decode(buffer) + } +} + +impl FixedWidthEncoding for u32 { + type Decode = u32; + + fn fw_encoded_size(&self) -> Result { + Ok(U32_SIZE) + } + + fn fw_encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_u32(*self, buffer) + } + + fn fw_decode(buffer: &[u8]) -> Result<(Self::Decode, &[u8]), EncodingError> + where + Self: Sized, + { + decode_u32(buffer) + } +} +impl FixedWidthEncoding for u64 { + type Decode = u64; + + fn fw_encoded_size(&self) -> Result { + Ok(U64_SIZE) + } + + fn fw_encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_u64(*self, buffer) + } + + fn fw_decode(buffer: &[u8]) -> Result<(Self::Decode, &[u8]), EncodingError> + where + Self: Sized, + { + decode_u64(buffer) + } +} + +/// A wrapper around [`u32`] to let us encoded/decode to/from a fixed width +pub type FixedWidthU32<'a> = FixedWidthUint<'a, u32>; +/// A wrapper around [`u64`] to let us encoded/decode to/from a fixed width +pub type FixedWidthU64<'a> = FixedWidthUint<'a, u64>; +#[cfg(test)] +mod test { + use crate::{map_decode, to_encoded_bytes}; + + use super::*; + + #[test] + fn fixed_width_u32() -> Result<(), EncodingError> { + let x = 42u32; + let fixed_buff = to_encoded_bytes!(x.as_fixed_width()); + let var_buff = to_encoded_bytes!(x); + assert_eq!(fixed_buff, [42_u8, 0, 0, 0].into()); + assert_eq!(var_buff, [42_u8].into()); + + let ((fixed_dec,), rest) = map_decode!(&fixed_buff, [FixedWidthU32]); + assert!(rest.is_empty()); + assert_eq!(fixed_dec, x); + + let ((var_dec,), rest) = map_decode!(&var_buff, [u32]); + assert!(rest.is_empty()); + assert_eq!(var_dec, x); + Ok(()) + } + + #[test] + fn fixed_width_u64() -> Result<(), EncodingError> { + let x = 42u64; + let fixed_buff = to_encoded_bytes!(x.as_fixed_width()); + let var_buff = to_encoded_bytes!(x); + assert_eq!(fixed_buff, [42, 0, 0, 0, 0, 0, 0, 0].into()); + assert_eq!(var_buff, [42].into()); + + let ((fixed_dec,), rest) = map_decode!(&fixed_buff, [FixedWidthU64]); + assert!(rest.is_empty()); + assert_eq!(fixed_dec, x); + Ok(()) + } +} diff --git a/src/generic.rs b/src/generic.rs deleted file mode 100644 index a3b3a99..0000000 --- a/src/generic.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! Generic compact encodings - -use super::{CompactEncoding, EncodingError, State}; - -impl CompactEncoding for State { - fn preencode(&mut self, value: &String) -> Result { - self.preencode_str(value) - } - - fn encode(&mut self, value: &String, buffer: &mut [u8]) -> Result { - self.encode_str(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result { - self.decode_string(buffer) - } -} - -impl CompactEncoding for State { - fn preencode(&mut self, _: &u8) -> Result { - self.add_end(1) - } - - fn encode(&mut self, value: &u8, buffer: &mut [u8]) -> Result { - buffer[self.start()] = *value; - self.add_start(1) - } - - fn decode(&mut self, buffer: &[u8]) -> Result { - let value = buffer[self.start()]; - self.add_start(1)?; - Ok(value) - } -} - -impl CompactEncoding for State { - fn preencode(&mut self, value: &u32) -> Result { - self.preencode_uint_var(value) - } - - fn encode(&mut self, value: &u32, buffer: &mut [u8]) -> Result { - self.encode_u32_var(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result { - self.decode_u32_var(buffer) - } -} - -impl CompactEncoding for State { - fn preencode(&mut self, value: &u64) -> Result { - self.preencode_uint_var(value) - } - - fn encode(&mut self, value: &u64, buffer: &mut [u8]) -> Result { - self.encode_u64_var(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result { - self.decode_u64_var(buffer) - } -} - -impl CompactEncoding for State { - fn preencode(&mut self, value: &usize) -> Result { - self.preencode_usize_var(value) - } - - fn encode(&mut self, value: &usize, buffer: &mut [u8]) -> Result { - self.encode_usize_var(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result { - self.decode_usize_var(buffer) - } -} - -impl CompactEncoding> for State { - fn preencode(&mut self, value: &Box<[u8]>) -> Result { - self.preencode_buffer(value) - } - - fn encode(&mut self, value: &Box<[u8]>, buffer: &mut [u8]) -> Result { - self.encode_buffer(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result, EncodingError> { - self.decode_buffer(buffer) - } -} - -impl CompactEncoding> for State { - fn preencode(&mut self, value: &Vec) -> Result { - self.preencode_buffer_vec(value) - } - - fn encode(&mut self, value: &Vec, buffer: &mut [u8]) -> Result { - self.encode_buffer(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result, EncodingError> { - self.decode_buffer_vec(buffer) - } -} - -impl CompactEncoding> for State { - fn preencode(&mut self, value: &Vec) -> Result { - self.preencode_u32_array(value) - } - - fn encode(&mut self, value: &Vec, buffer: &mut [u8]) -> Result { - self.encode_u32_array(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result, EncodingError> { - self.decode_u32_array(buffer) - } -} - -impl CompactEncoding> for State { - fn preencode(&mut self, value: &Vec) -> Result { - self.preencode_string_array(value) - } - - fn encode(&mut self, value: &Vec, buffer: &mut [u8]) -> Result { - self.encode_string_array(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result, EncodingError> { - self.decode_string_array(buffer) - } -} - -impl CompactEncoding> for State { - fn preencode(&mut self, value: &Vec<[u8; 32]>) -> Result { - self.preencode_fixed_32_array(value) - } - - fn encode(&mut self, value: &Vec<[u8; 32]>, buffer: &mut [u8]) -> Result { - self.encode_fixed_32_array(value, buffer) - } - - fn decode(&mut self, buffer: &[u8]) -> Result, EncodingError> { - self.decode_fixed_32_array(buffer) - } -} diff --git a/src/lib.rs b/src/lib.rs index ee2e0ad..e57eda6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,148 +1,1143 @@ #![forbid(unsafe_code, missing_docs)] #![cfg_attr(test, deny(warnings))] -#![doc(test(attr(deny(warnings))))] //! # Series of compact encoding schemes for building small and fast parsers and serializers //! //! Binary compatible with the -//! [original Javascript compact-encoding library](https://github.com/compact-encoding/compact-encoding/). +//! [original JavaScript compact-encoding library](https://github.com/compact-encoding/compact-encoding/). //! //! ## Usage //! -//! ### Basic +//! The simplest way to encoded and decode a some data is using the [`to_encoded_bytes`] and +//! [`map_decode`] macros: +//! ``` +//! use compact_encoding::{map_decode, to_encoded_bytes}; +//! +//! let number = 41_u32; +//! let word = "hi"; //! -//! Using only the types implemented here (replace `unwrap()` with proper -//! handling of [EncodingError]): +//! let encoded_buffer = to_encoded_bytes!(number, word); +//! let ((number_dec, word_dec), remaining_buffer) = map_decode!(&encoded_buffer, [u32, String]); //! +//! assert!(remaining_buffer.is_empty()); +//! assert_eq!(number_dec, number); +//! assert_eq!(word_dec, word); +//! # Ok::<(), Box>(()) //! ``` -//! use compact_encoding::{CompactEncoding, State}; +//! ### Manual encoding and decoding //! -//! // Start with an empty state -//! let mut enc_state = State::new(); +//! When more fine-grained control of encoding and decoding is needed you manually do each step of +//! encoding and decoding like in the following example, where we want to use a fixed width +//! encoding for `number` (instead of the default variable width encoding). It shows how to +//! manually calculate the needed buffer size, create the buffer, encode data, and decode it. +//! ``` +//! use compact_encoding::{CompactEncoding, FixedWidthEncoding, FixedWidthU32}; //! //! let number = 41_u32; -//! let str = "hi".to_string(); +//! let word = "hi"; //! -//! // Use preencode to figure out how big a buffer is needed -//! enc_state.preencode(&number).unwrap(); -//! enc_state.preencode(&str).unwrap(); +//! // Use `encoded_size` to figure out how big a buffer should be +//! let size = number.as_fixed_width().encoded_size()? + word.encoded_size()?; //! -//! // Create buffer of pre-encoded size -//! let mut buffer = enc_state.create_buffer(); -//! assert_eq!(buffer.len(), 1 + 1 + 2); +//! // Create a buffer with the calculated size +//! let mut buffer = vec![0; size]; +//! assert_eq!(buffer.len(), 4 + 1 + 2); //! //! // Then actually encode the values -//! enc_state.encode(&number, &mut buffer).unwrap(); -//! enc_state.encode(&str, &mut buffer).unwrap(); -//! assert_eq!(buffer.to_vec(), vec![41_u8, 2_u8, b'h', b'i']); -//! -//! // On the decoding end, create a state from byte buffer -//! let mut dec_state = State::from_buffer(&buffer); -//! let number_dec: u32 = dec_state.decode(&buffer).unwrap(); -//! let str_dec: String = dec_state.decode(&buffer).unwrap(); +//! let mut remaining_buffer = number.as_fixed_width().encode(&mut buffer)?; +//! remaining_buffer = word.encode(remaining_buffer)?; +//! assert!(remaining_buffer.is_empty()); +//! assert_eq!(buffer.to_vec(), vec![41_u8, 0, 0, 0, 2_u8, b'h', b'i']); +//! +//! // `buffer` now contains all the encoded data, and we can decode from it +//! let (number_dec, remaining_buffer) = FixedWidthU32::decode(&buffer)?; +//! let (word_dec, remaining_buffer) = String::decode(remaining_buffer)?; +//! assert!(remaining_buffer.is_empty()); //! assert_eq!(number_dec, number); -//! assert_eq!(str_dec, str); +//! assert_eq!(word_dec, word); +//! # Ok::<(), Box>(()) //! ``` //! -//! ### Custom -//! -//! If you want to encode your own structs directly, you can do that -//! by implementing [CompactEncoding] yourself (replace `unwrap()` with proper -//! handling of [EncodingError]): +//! ### Implementing CompactEncoding for custom types //! +//! Here we demonstrate how to implement [`CompactEncoding`] for a custom struct. //! ``` -//! use compact_encoding::{CompactEncoding, EncodingError, State}; +//! use compact_encoding::{ +//! map_decode, map_encode, sum_encoded_size, to_encoded_bytes, CompactEncoding, EncodingError, +//! }; //! //! #[derive(Debug, PartialEq)] //! struct MyStruct { -//! my_flag_1: bool, -//! my_flag_2: bool, -//! my_values: Vec<[u8; 32]>, +//! some_flag: bool, +//! values: Option>, +//! other: String, +//! stuff: u64, //! } //! -//! impl CompactEncoding for State { -//! fn preencode(&mut self, value: &MyStruct) -> Result { -//! self.add_end(1)?; // flags -//! if !value.my_values.is_empty() { -//! self.preencode(&value.my_values)?; -//! } -//! Ok(self.end()) +//! impl CompactEncoding for MyStruct { +//! fn encoded_size(&self) -> Result { +//! Ok(1 /* flags */ + { +//! /* handle option values */ +//! if let Some(values) = &self.values { +//! values.encoded_size()? +//! } else { +//! 0 +//! } +//! } + sum_encoded_size!(&self.other, &self.stuff)) //! } //! -//! fn encode(&mut self, value: &MyStruct, buffer: &mut [u8]) -> Result { +//! fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { //! let mut flags: u8 = 0; -//! if value.my_flag_1 { +//! if self.some_flag { //! flags |= 1; //! } -//! if value.my_flag_2 { +//! if self.values.is_some() { //! flags |= 2; //! } -//! if !value.my_values.is_empty() { -//! flags |= 4; +//! let mut rest = flags.encode(buffer)?; +//! if let Some(values) = &self.values { +//! rest = values.encode(rest)?; //! } -//! self.encode(&flags, buffer)?; -//! if !value.my_values.is_empty() { -//! self.encode(&value.my_values, buffer)?; -//! } -//! Ok(self.start()) +//! Ok(map_encode!(rest, self.other, self.stuff)) //! } //! -//! fn decode(&mut self, buffer: &[u8]) -> Result { -//! let flags: u8 = self.decode(buffer)?; -//! let my_flag_1: bool = flags & 1 != 0; -//! let my_flag_2: bool = flags & 2 != 0; -//! let my_values: Vec<[u8; 32]> = if flags & 4 != 0 { -//! self.decode(buffer)? -//! } else { -//! vec![] -//! }; -//! Ok(MyStruct { -//! my_flag_1, -//! my_flag_2, -//! my_values -//! }) +//! fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> { +//! let (flags, rest) = u8::decode(buffer)?; +//! let some_flag: bool = flags & 1 != 0; +//! let (values, rest) = if flags & 2 != 0 { +//! let (vec, rest) = >::decode(rest)?; +//! (Some(vec), rest) +//! } else { +//! (None, rest) +//! }; +//! let ((other, stuff), rest) = map_decode!(rest, [String, u64]); +//! Ok(( +//! Self { +//! some_flag, +//! values, +//! other, +//! stuff, +//! }, +//! rest, +//! )) //! } //! } //! //! // Test values -//! let empty = MyStruct { -//! my_flag_1: false, -//! my_flag_2: true, -//! my_values: vec![] +//! let foo = MyStruct { +//! some_flag: false, +//! values: None, +//! other: "hi".to_string(), +//! stuff: 42, //! }; -//! let non_empty = MyStruct { -//! my_flag_1: true, -//! my_flag_2: false, -//! my_values: vec![[1; 32], [2; 32]] +//! +//! let bar = MyStruct { +//! some_flag: true, +//! values: Some(vec![[1; 32], [2; 32]]), +//! other: "yo".to_string(), +//! stuff: 0, //! }; //! -//! // Start with an empty state -//! let mut enc_state = State::new(); -//! enc_state.preencode(&empty).unwrap(); -//! enc_state.preencode(&non_empty).unwrap(); -//! let mut buffer = enc_state.create_buffer(); +//! // Encode `foo` and `bar` to a buffer +//! let buffer = to_encoded_bytes!(&foo, &bar); //! //! // With the above use of a flags byte, the empty value encodes to only one byte -//! assert_eq!(buffer.len(), 1 + 1 + 1 + 2 * 32); -//! -//! // Then actually encode the values -//! enc_state.encode(&empty, &mut buffer).unwrap(); -//! enc_state.encode(&non_empty, &mut buffer).unwrap(); -//! -//! // On the decoding end, create a state from byte buffer -//! let mut dec_state = State::from_buffer(&buffer); +//! assert_eq!( +//! buffer.len(), +//! // flags + string + u64 +//! (1 + 3 + 1) + +//! // "" + (values.len().encoded_size() + (values.len() * <[u8;32]>::encoded_size()) + "" +//! (1 + (1 + (2 * 32)) + 3 + 1) +//! ); //! //! // And decode directly to your own struct -//! let empty_dec: MyStruct = dec_state.decode(&buffer).unwrap(); -//! let non_empty_dec: MyStruct = dec_state.decode(&buffer).unwrap(); -//! assert_eq!(empty_dec, empty); -//! assert_eq!(non_empty_dec, non_empty); +//! let (foo_dec, rest) = MyStruct::decode(&buffer)?; +//! let (bar_dec, rest) = MyStruct::decode(&rest)?; +//! // Ensure all bytes were used +//! assert!(rest.is_empty()); +//! assert_eq!(foo_dec, foo); +//! assert_eq!(bar_dec, bar); +//! # Ok::<(), Box>(()) //! ``` -//! -//! **NB**: This only works if you don't export your struct out of your crate. -//! If you export the struct, orphan rule will require you to -//! implement a wrapper for [State], e.g. `struct MyState(State);` and implement -//! [CompactEncoding] for the wrapper struct instead. -pub mod generic; -pub mod types; -pub use types::{CompactEncoding, EncodingError, EncodingErrorKind, State}; +mod error; +mod fixedwidth; +pub use fixedwidth::{FixedWidthEncoding, FixedWidthU32, FixedWidthU64, FixedWidthUint}; +use std::{ + any::type_name, + net::{Ipv4Addr, Ipv6Addr}, +}; + +pub use crate::error::{EncodingError, EncodingErrorKind}; + +/// indicates a variable width unsigned integer fits in u16 +pub const U16_SIGNIFIER: u8 = 0xfd; +/// indicates a variable width unsigned integer fits in u32 +pub const U32_SIGNIFIER: u8 = 0xfe; +/// indicates a variable width unsigned integer fits in u64 +pub const U64_SIGNIFIER: u8 = 0xff; + +const U16_SIZE: usize = 2; +const U32_SIZE: usize = 4; +const U64_SIZE: usize = 8; + +/// A trait for building small and fast parsers and serializers. +pub trait CompactEncoding { + /// The size in bytes required to encode `self`. + fn encoded_size(&self) -> Result; + + /// Encode `self` into `buffer` returning the remainder of `buffer`. + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError>; + + /// Decode a value from the given `buffer` of the type specified by the `Decode` type parameter + /// (which defaults to `Self`). Returns the decoded value and remaining undecoded bytes. + fn decode(buffer: &[u8]) -> Result<(Decode, &[u8]), EncodingError> + where + Decode: Sized; + + /// Encode `self` into a `Vec`. This is just a helper method for creating a buffer and + /// encoding to it in one step. + /// ``` + /// # use std::net::Ipv4Addr; + /// # use compact_encoding::CompactEncoding; + /// let foo: Ipv4Addr = "0.0.0.0".parse()?; + /// let mut buff = vec![0; foo.encoded_size()?]; + /// foo.encode(&mut buff)?; + /// # Ok::<(), Box>(()) + /// ``` + fn to_encoded_bytes(&self) -> Result, EncodingError> { + let mut buff = self.create_buffer()?; + self.encode(&mut buff)?; + Ok(buff) + } + /// Create an empty buffer of the correct size for encoding `self` to. This is just a helper + /// method for: encoding to it in one step. + /// ``` + /// # use std::net::Ipv4Addr; + /// # use compact_encoding::CompactEncoding; + /// let foo: Ipv4Addr = "0.0.0.0".parse()?; + /// vec![0; foo.encoded_size()?]; + /// # Ok::<(), Box>(()) + /// ``` + fn create_buffer(&self) -> Result, EncodingError> { + Ok(vec![0; self.encoded_size()?].into_boxed_slice()) + } + + /// Like [`CompactEncoding::encode`] but also return the number of bytes encoded. + fn encode_with_len<'a>( + &self, + buffer: &'a mut [u8], + ) -> Result<(&'a mut [u8], usize), EncodingError> { + let before_len = buffer.len(); + let rest = self.encode(buffer)?; + let num_encoded_bytes = before_len - rest.len(); + Ok((rest, num_encoded_bytes)) + } + + /// Like [`CompactEncoding::decode`] but also return the number of bytes decoded. + fn decode_with_len(buffer: &[u8]) -> Result<(Decode, &[u8], usize), EncodingError> + where + Decode: Sized, + { + let (out, rest) = Self::decode(buffer)?; + Ok((out, rest, buffer.len() - rest.len())) + } +} + +/// Implement this for type `T` to have `CompactEncoding` implemented for `Vec` +pub trait VecEncodable: CompactEncoding { + /// Calculate the resulting size in bytes of `vec` + fn vec_encoded_size(vec: &[Self]) -> Result + where + Self: Sized; + + /// Encode `vec` to `buffer` + fn vec_encode<'a>(vec: &[Self], buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> + where + Self: Sized, + { + encode_vec(vec, buffer) + } + + /// Decode [`Vec`] from buffer + fn vec_decode(buffer: &[u8]) -> Result<(Vec, &[u8]), EncodingError> + where + Self: Sized, + { + decode_vec(buffer) + } +} + +// NB: we DO want &Box<..> because we want the trait to work for boxed things, hence clippy::allow +#[allow(clippy::borrowed_box)] +/// Define this trait for `T` to get `impl Box<[T]> for CompactEncoding` +pub trait BoxedSliceEncodable: CompactEncoding { + /// The encoded size in bytes + fn boxed_slice_encoded_size(boxed: &Box<[Self]>) -> Result + where + Self: Sized; + + /// Encode `Box<[Self]>` to the buffer and return the remainder of the buffer + fn boxed_slice_encode<'a>( + vec: &Box<[Self]>, + buffer: &'a mut [u8], + ) -> Result<&'a mut [u8], EncodingError> + where + Self: Sized, + { + encode_vec(vec, buffer) + } + + /// Decode [`Box<[Self]>`] from buffer + fn boxed_slice_decode(buffer: &[u8]) -> Result<(Box<[Self]>, &[u8]), EncodingError> + where + Self: Sized, + { + let (result, rest) = decode_vec(buffer)?; + Ok((result.into_boxed_slice(), rest)) + } +} + +#[macro_export] +/// Given a list of [`CompactEncoding`] things, sum the result of calling +/// [`CompactEncoding::encoded_size`] on all of them. +/// Note this is macro is useful when your arguments have differing types. +/// ``` +/// # use crate::compact_encoding::{sum_encoded_size, CompactEncoding}; +/// # use std::net::Ipv4Addr; +/// let foo: Ipv4Addr = "0.0.0.0".parse()?; +/// let bar = 42u64; +/// let qux = "hello?"; +/// let result = sum_encoded_size!(foo, bar, qux); +/// assert_eq!(result, 12); +/// # Ok::<(), Box>(()) +/// ``` +/// If you want to use this within a non-result context you can do +/// ``` +/// # use crate::compact_encoding::{sum_encoded_size, CompactEncoding, EncodingError}; +/// let bar = 42u64; +/// let result = (|| Ok::(sum_encoded_size!(bar)))().unwrap(); +/// assert_eq!(result, 1); +/// ``` +macro_rules! sum_encoded_size { + ($($val:expr),+) => {{ + 0 + $( + + $val.encoded_size()? + )* + }} +} + +#[macro_export] +/// Given a list of [`CompactEncoding`] things, create a zeroed buffer of the correct size for encoding. +/// Note this is macro is useful when your arguments have differing types. +/// ``` +/// # use crate::compact_encoding::{create_buffer, CompactEncoding}; +/// # use std::net::Ipv4Addr; +/// let foo: Ipv4Addr = "0.0.0.0".parse()?; +/// let bar = 42u64; +/// let qux = "hello?"; +/// let buff = create_buffer!(foo, bar, qux); +/// assert_eq!(buff.len(), 12); +/// # Ok::<(), Box>(()) +/// ``` +macro_rules! create_buffer { + ($($val:expr),+) => {{ + let len = ( + 0 + $( + + $val.encoded_size()? + )* + ); + vec![0; len].into_boxed_slice() + }} +} + +#[macro_export] +/// Given a buffer and a list of [`CompactEncoding`] things, encode the arguments to the buffer. +/// Note this is macro is useful when your arguments have differing types. +/// ``` +/// # use crate::compact_encoding::{create_buffer, map_encode, CompactEncoding}; +/// let num = 42u64; +/// let word = "yo"; +/// let mut buff = create_buffer!(num, word); +/// let result = map_encode!(&mut buff, num, word); +/// assert!(result.is_empty()); +/// assert_eq!(&*buff, &[42, 2, b'y', b'o']); +/// # Ok::<(), Box>(()) +/// ``` +macro_rules! map_encode { + ($buffer:expr$(,)*) => { + $buffer + }; + // Base case: single field + ($buffer:expr, $field:expr) => { + $field.encode($buffer)? + }; + // Recursive case: first field + rest + ($buffer:expr, $first:expr, $($rest:expr),+) => {{ + let rest = $first.encode($buffer)?; + map_encode!(rest, $($rest),+) + }}; +} + +#[macro_export] +/// Given a list of [`CompactEncoding`] things, encode the arguments to the buffer. +/// Note this is macro is useful when your arguments have differing types. +/// ``` +/// # use crate::compact_encoding::to_encoded_bytes; +/// let result = to_encoded_bytes!(42u64, "yo"); +/// assert_eq!(&*result, &[42, 2, 121, 111]); +/// # Ok::<(), Box>(()) +/// ``` +macro_rules! to_encoded_bytes { + ($($val:expr),*) => {{ + use $crate::{map_encode, create_buffer, CompactEncoding}; + let mut buffer = create_buffer!($($val),*); + map_encode!(&mut buffer, $($val),*); + buffer + }} +} + +#[macro_export] +/// Decode a buffer to the list of types provided, returning the remaining buffer. +/// It takes as arguments: `(&buffer, [type1, type2, type3, ...])` +/// And returns: `((decoded_type1, decoded_type2, ...), remaining_buffer)` +/// ``` +/// # use crate::compact_encoding::{to_encoded_bytes, map_decode}; +/// let buffer = to_encoded_bytes!(42u64, "yo"); +/// let ((number, word), remaining_buffer) = map_decode!(&buffer, [u64, String]); +/// assert!(remaining_buffer.is_empty()); +/// assert_eq!(number, 42u64); +/// assert_eq!(word, "yo"); +/// # Ok::<(), Box>(()) +/// ``` +macro_rules! map_decode { + ($buffer:expr, [ + $($field_type:ty),* $(,)? + ]) => {{ + use $crate::CompactEncoding; + let mut current_buffer: &[u8] = $buffer; + + // Decode each type into `result_tuple` + let result_tuple = ( + $( + match <$field_type>::decode(¤t_buffer)? { + (value, new_buf) => { + current_buffer = new_buf; + value + } + }, + )* + ); + (result_tuple, current_buffer) + }}; +} + +/// helper for mapping the first element of a two eleent tuple +macro_rules! map_first { + ($res:expr, $f:expr) => {{ + let (one, two) = $res; + let mapped = $f(one)?; + (mapped, two) + }}; +} + +/// Split a slice in two at `mid`. Returns encoding error when `mid` is out of bounds. +pub fn get_slices_checked(buffer: &[u8], mid: usize) -> Result<(&[u8], &[u8]), EncodingError> { + buffer.split_at_checked(mid).ok_or_else(|| { + EncodingError::out_of_bounds(&format!( + "Could not split slice at [{mid}] slice.len() = [{}]", + buffer.len() + )) + }) +} + +/// Split a mutable slice into two mutable slices around `mid`. +/// Returns encoding error when `mid` is out of bounds. +pub fn get_slices_mut_checked( + buffer: &mut [u8], + mid: usize, +) -> Result<(&mut [u8], &mut [u8]), EncodingError> { + let len = buffer.len(); + buffer.split_at_mut_checked(mid).ok_or_else(|| { + EncodingError::out_of_bounds(&format!( + "Could not split mut slice at [{mid}] slice.len() = [{len}]" + )) + }) +} + +/// Get a slice as an array of size `N`. Errors when `slice.len() != N`. +pub fn as_array(buffer: &[u8]) -> Result<&[u8; N], EncodingError> { + let blen = buffer.len(); + if blen != N { + return Err(EncodingError::out_of_bounds(&format!( + "Could get a [{N}] byte array from a slice of length [{blen}]" + ))); + } + Ok(buffer.split_first_chunk::().expect("checked above").0) +} + +/// Get a slice as a mutable array of size `N`. Errors when `slice.len() != N`. +pub fn as_array_mut(buffer: &mut [u8]) -> Result<&mut [u8; N], EncodingError> { + let blen = buffer.len(); + if blen != N { + return Err(EncodingError::out_of_bounds(&format!( + "Could get a [{N}] byte array from a slice of length [{blen}]" + ))); + } + Ok(buffer + .split_first_chunk_mut::() + .expect("checked above") + .0) +} + +/// Write `source` to `buffer` and return the remainder of `buffer`. +/// Errors when `N < buffer.len()` +pub fn write_array<'a, const N: usize>( + source: &[u8; N], + buffer: &'a mut [u8], +) -> std::result::Result<&'a mut [u8], EncodingError> { + let blen = buffer.len(); + let Some((dest, rest)) = buffer.split_first_chunk_mut::() else { + return Err(EncodingError::out_of_bounds(&format!( + "Could not write [{}] bytes to buffer of length [{}]", + N, blen + ))); + }; + dest.copy_from_slice(source); + Ok(rest) +} + +/// split the first `N` bytes of `buffer` off and return them +pub fn take_array( + buffer: &[u8], +) -> std::result::Result<([u8; N], &[u8]), EncodingError> { + let Some((out, rest)) = buffer.split_first_chunk::() else { + return Err(EncodingError::out_of_bounds(&format!( + "Could not write [{}] bytes to buffer of length [{}]", + N, + buffer.len() + ))); + }; + Ok((*out, rest)) +} +/// split the first `N` bytes of `buffer` off and return them +pub fn take_array_mut( + buffer: &mut [u8], +) -> std::result::Result<(&mut [u8; N], &mut [u8]), EncodingError> { + let blen = buffer.len(); + let Some((out, rest)) = buffer.split_first_chunk_mut::() else { + return Err(EncodingError::out_of_bounds(&format!( + "Could not write [{}] bytes to buffer of length [{blen}]", + N, + ))); + }; + Ok((out, rest)) +} + +/// write `source` to `buffer` and return remaining buffer +pub fn write_slice<'a>(source: &[u8], buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + let mid = source.len(); + let (dest, rest) = get_slices_mut_checked(buffer, mid)?; + dest.copy_from_slice(source); + Ok(rest) +} + +/// Helper to convert a vec to an array, and fail with an encoding error when needed +pub fn bytes_fixed_from_vec(value: &[u8]) -> Result<[u8; N], EncodingError> { + <[u8; N]>::try_from(value).map_err(|e| { + EncodingError::invalid_data(&format!( + "Could not covert slice with length [{}] to array of length [{}]. Error: [{e}]", + value.len(), + N + )) + }) +} + +fn encoded_size_str(value: &str) -> Result { + Ok(encoded_size_usize(value.len()) + value.len()) +} + +/// The number of bytes required to encode this number. Note this is always variable width. +pub fn encoded_size_usize(val: usize) -> usize { + if val < U16_SIGNIFIER.into() { + 1 + } else if val <= 0xffff { + 3 + } else if val <= 0xffffffff { + 5 + } else { + 9 + } +} + +/// The number of bytes required to encode this number. +/// We only need this for u64 because all other uints can be converted to usize reliably. +pub fn encoded_size_var_u64(val: u64) -> usize { + if val < U16_SIGNIFIER.into() { + 1 + } else if val <= 0xffff { + 3 + } else if val <= 0xffffffff { + 5 + } else { + 9 + } +} + +/// Write `uint` to the start of `buffer` and return the remaining part of `buffer`. +pub fn encode_var_u64(uint: u64, buffer: &mut [u8]) -> Result<&mut [u8], EncodingError> { + if uint < U16_SIGNIFIER.into() { + encode_u8(uint as u8, buffer) + } else if uint <= 0xffff { + let rest = write_array(&[U16_SIGNIFIER], buffer)?; + encode_u16(uint as u16, rest) + } else if uint <= 0xffffffff { + let rest = write_array(&[U32_SIGNIFIER], buffer)?; + encode_u32(uint as u32, rest) + } else { + let rest = write_array(&[U64_SIGNIFIER], buffer)?; + encode_u64(uint, rest) + } +} + +/// Decode a `usize` from `buffer` and return the remaining bytes. +/// This will fail, when we are decoding a `usize` on a usize = u32 machine for data that was originally encoded on a `usize = u64` machine whenever the value is over `u32::MAX`. +pub fn decode_usize(buffer: &[u8]) -> Result<(usize, &[u8]), EncodingError> { + let ([first], rest) = take_array::<1>(buffer)?; + Ok(match first { + x if x < U16_SIGNIFIER => (x.into(), rest), + U16_SIGNIFIER => map_first!(decode_u16(rest)?, |x: u16| Ok(x.into())), + U32_SIGNIFIER => { + map_first!(decode_u32(rest)?, |val| usize::try_from(val).map_err( + |_| EncodingError::overflow("Could not convert u32 to usize") + )) + } + _ => { + map_first!(decode_u64(rest)?, |val| usize::try_from(val).map_err( + |_| EncodingError::overflow("Could not convert u64 to usize") + )) + } + }) +} + +/// Encoded a fixed sized array to a buffer, return the remainder of the buffer. +/// Errors when `value.len() > buffer.len()`; +/// ``` +/// # use compact_encoding::encode_bytes_fixed; +/// let mut buffer = vec![0; 3]; +/// let rest = encode_bytes_fixed(&[4, 2], &mut buffer)?; +/// assert_eq!(rest, &[0]); +/// assert_eq!(buffer, &[4, 2, 0]); +/// # Ok::<(), Box>(()) +/// ``` +pub fn encode_bytes_fixed<'a, const N: usize>( + value: &[u8; N], + buffer: &'a mut [u8], +) -> Result<&'a mut [u8], EncodingError> { + write_array(value, buffer) +} + +/// Decode a fixed sized array from a buffer. Return the array and the remainder of the buffer. +/// Errors when `buffer.len() < N`; +/// ``` +/// # use compact_encoding::decode_bytes_fixed; +/// let mut buffer = vec![1, 2, 3]; +/// let (arr, rest) = decode_bytes_fixed::<2>(&mut buffer)?; +/// assert_eq!(arr, [1, 2]); +/// assert_eq!(rest, &[3]); +/// # Ok::<(), Box>(()) +/// ``` +pub fn decode_bytes_fixed( + buffer: &[u8], +) -> Result<([u8; N], &[u8]), EncodingError> { + take_array(buffer) + //write_array(value, buffer) +} + +fn decode_u16(buffer: &[u8]) -> Result<(u16, &[u8]), EncodingError> { + let (data, rest) = take_array::<2>(buffer)?; + Ok((u16::from_le_bytes(data), rest)) +} +fn decode_u32(buffer: &[u8]) -> Result<(u32, &[u8]), EncodingError> { + let (data, rest) = take_array::<4>(buffer)?; + Ok((u32::from_le_bytes(data), rest)) +} +fn decode_u64(buffer: &[u8]) -> Result<(u64, &[u8]), EncodingError> { + let (data, rest) = take_array::<8>(buffer)?; + Ok((u64::from_le_bytes(data), rest)) +} + +fn decode_u32_var(buffer: &[u8]) -> Result<(u32, &[u8]), EncodingError> { + let ([first], rest) = take_array::<1>(buffer)?; + Ok(match first { + x if x < U16_SIGNIFIER => (x.into(), rest), + U16_SIGNIFIER => { + let (val, rest) = decode_u16(rest)?; + (val.into(), rest) + } + _ => decode_u32(rest)?, + }) +} + +fn decode_u64_var(buffer: &[u8]) -> Result<(u64, &[u8]), EncodingError> { + let ([first], rest) = take_array::<1>(buffer)?; + Ok(match first { + x if x < U16_SIGNIFIER => (x.into(), rest), + U16_SIGNIFIER => map_first!(decode_u16(rest)?, |x: u16| Ok(x.into())), + U32_SIGNIFIER => map_first!(decode_u32(rest)?, |x: u32| Ok(x.into())), + _ => decode_u64(rest)?, + }) +} + +fn decode_buffer_vec(buffer: &[u8]) -> Result<(Vec, &[u8]), EncodingError> { + let (n_bytes, rest) = decode_usize(buffer)?; + let (out, rest) = get_slices_checked(rest, n_bytes)?; + Ok((out.to_vec(), rest)) +} + +fn decode_string(buffer: &[u8]) -> Result<(String, &[u8]), EncodingError> { + let (len, rest) = decode_usize(buffer)?; + let (str_buff, rest) = get_slices_checked(rest, len)?; + let out = String::from_utf8(str_buff.to_vec()) + .map_err(|e| EncodingError::invalid_data(&format!("String is invalid UTF-8, {e}")))?; + Ok((out, rest)) +} + +fn encode_u8(val: u8, buffer: &mut [u8]) -> Result<&mut [u8], EncodingError> { + write_array(&val.to_le_bytes(), buffer) +} +fn encode_u16(val: u16, buffer: &mut [u8]) -> Result<&mut [u8], EncodingError> { + write_array(&val.to_le_bytes(), buffer) +} +fn encode_u32(val: u32, buffer: &mut [u8]) -> Result<&mut [u8], EncodingError> { + write_array(&val.to_le_bytes(), buffer) +} +fn encode_u64(val: u64, buffer: &mut [u8]) -> Result<&mut [u8], EncodingError> { + write_array(&val.to_le_bytes(), buffer) +} + +fn encode_usize_var<'a>( + value: &usize, + buffer: &'a mut [u8], +) -> Result<&'a mut [u8], EncodingError> { + if *value < U16_SIGNIFIER.into() { + encode_u8(*value as u8, buffer) + } else if *value <= 0xffff { + encode_u16(*value as u16, write_array(&[U16_SIGNIFIER], buffer)?) + } else if *value <= 0xffffffff { + let value = u32::try_from(*value).map_err(|e| { + EncodingError::overflow(&format!( + "count not covert usize [{value}] to u32. Error: [{e}]" + )) + })?; + encode_u32(value, write_array(&[U32_SIGNIFIER], buffer)?) + } else { + let value = u64::try_from(*value).map_err(|e| { + EncodingError::overflow(&format!( + "count not covert usize [{value}] to u64. Error: [{e}]" + )) + })?; + encode_u64(value, write_array(&[U64_SIGNIFIER], buffer)?) + } +} + +fn encode_str<'a>(value: &str, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + let rest = encode_usize_var(&value.len(), buffer)?; + write_slice(value.as_bytes(), rest) +} + +fn encode_buffer<'a>(value: &[u8], buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + let rest = encode_usize_var(&value.len(), buffer)?; + write_slice(value, rest) +} + +impl CompactEncoding for [u8; N] { + fn encoded_size(&self) -> Result { + Ok(N) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + write_array(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + take_array(buffer) + } +} + +impl CompactEncoding for u8 { + fn encoded_size(&self) -> Result { + Ok(1) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + write_array(&[*self], buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + let ([out], rest) = take_array::<1>(buffer)?; + Ok((out, rest)) + } +} + +impl CompactEncoding for u16 { + fn encoded_size(&self) -> Result { + Ok(U16_SIZE) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_u16(*self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + decode_u16(buffer) + } +} + +// NB: we want u32 encoded and decoded as variable sized uint +impl CompactEncoding for u32 { + fn encoded_size(&self) -> Result { + Ok(encoded_size_usize(*self as usize)) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_usize_var(&(*self as usize), buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + decode_u32_var(buffer) + } +} +impl CompactEncoding for u64 { + fn encoded_size(&self) -> Result { + Ok(encoded_size_var_u64(*self)) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_var_u64(*self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + decode_u64_var(buffer) + } +} + +impl CompactEncoding for String { + fn encoded_size(&self) -> Result { + encoded_size_str(self) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_str(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + decode_string(buffer) + } +} + +impl CompactEncoding for str { + fn encoded_size(&self) -> Result { + encoded_size_str(self) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_str(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(String, &[u8]), EncodingError> { + decode_string(buffer) + } +} + +impl CompactEncoding for Vec { + fn encoded_size(&self) -> Result { + let mut out = encoded_size_usize(self.len()); + for s in self { + out += s.encoded_size()?; + } + Ok(out) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + let mut rest = encode_usize_var(&self.len(), buffer)?; + for s in self { + rest = s.encode(rest)?; + } + Ok(rest) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + let (len, mut rest) = decode_usize(buffer)?; + let mut out = Vec::with_capacity(len); + for _ in 0..len { + let result = String::decode(rest)?; + out.push(result.0); + rest = result.1; + } + Ok((out, rest)) + } +} + +impl CompactEncoding for Vec { + fn encoded_size(&self) -> Result { + Ok(encoded_size_usize(self.len()) + self.len()) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + encode_buffer(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + decode_buffer_vec(buffer) + } +} + +impl CompactEncoding for Ipv4Addr { + fn encoded_size(&self) -> std::result::Result { + Ok(U32_SIZE) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> std::result::Result<&'a mut [u8], EncodingError> { + let Some((dest, rest)) = buffer.split_first_chunk_mut::<4>() else { + return Err(EncodingError::out_of_bounds(&format!( + "Colud not encode {}, not enough room in buffer", + type_name::() + ))); + }; + dest.copy_from_slice(&self.octets()); + Ok(rest) + } + + fn decode(buffer: &[u8]) -> std::result::Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + let Some((dest, rest)) = buffer.split_first_chunk::<4>() else { + return Err(EncodingError::out_of_bounds(&format!( + "Colud not decode {}, buffer not big enough", + type_name::() + ))); + }; + Ok((Ipv4Addr::from(*dest), rest)) + } +} +impl CompactEncoding for Ipv6Addr { + fn encoded_size(&self) -> std::result::Result { + Ok(4) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> std::result::Result<&'a mut [u8], EncodingError> { + let Some((dest, rest)) = buffer.split_first_chunk_mut::<16>() else { + return Err(EncodingError::out_of_bounds(&format!( + "Colud not encode {}, not enough room in buffer", + type_name::() + ))); + }; + dest.copy_from_slice(&self.octets()); + Ok(rest) + } + + fn decode(buffer: &[u8]) -> std::result::Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + let Some((dest, rest)) = buffer.split_first_chunk::<16>() else { + return Err(EncodingError::out_of_bounds(&format!( + "Colud not decode {}, buffer not big enough", + type_name::() + ))); + }; + Ok((Ipv6Addr::from(*dest), rest)) + } +} + +fn encode_vec<'a, T: CompactEncoding + Sized>( + vec: &[T], + buffer: &'a mut [u8], +) -> Result<&'a mut [u8], EncodingError> { + let mut rest = encode_usize_var(&vec.len(), buffer)?; + for x in vec { + rest = ::encode(x, rest)?; + } + Ok(rest) +} + +fn decode_vec(buffer: &[u8]) -> Result<(Vec, &[u8]), EncodingError> { + let (len, mut rest) = decode_usize(buffer)?; + let mut out = Vec::with_capacity(len); + for _ in 0..len { + let res = ::decode(rest)?; + out.push(res.0); + rest = res.1; + } + Ok((out, rest)) +} + +impl CompactEncoding for Vec { + fn encoded_size(&self) -> Result { + T::vec_encoded_size(self) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + ::vec_encode(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + ::vec_decode(buffer) + } +} + +impl VecEncodable for u32 { + fn vec_encoded_size(vec: &[Self]) -> Result + where + Self: Sized, + { + Ok(encoded_size_usize(vec.len()) + (vec.len() * 4)) + } + /// Encode `vec` to `buffer` + fn vec_encode<'a>(vec: &[Self], buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> + where + Self: Sized, + { + let mut rest = encode_usize_var(&vec.len(), buffer)?; + for x in vec { + rest = encode_u32(*x, rest)?; + } + Ok(rest) + } + + /// Decode [`Vec`] from buffer + fn vec_decode(buffer: &[u8]) -> Result<(Vec, &[u8]), EncodingError> + where + Self: Sized, + { + let (len, mut rest) = decode_usize(buffer)?; + let mut out = Vec::with_capacity(len); + + for _ in 0..len { + let result = decode_u32(rest)?; + out.push(result.0); + rest = result.1; + } + Ok((out, rest)) + } +} + +impl VecEncodable for [u8; N] { + fn vec_encoded_size(vec: &[Self]) -> Result + where + Self: Sized, + { + Ok(encoded_size_usize(vec.len()) + (vec.len() * N)) + } +} + +impl BoxedSliceEncodable for u8 { + fn boxed_slice_encoded_size(boxed: &Box<[Self]>) -> Result + where + Self: Sized, + { + Ok(encoded_size_usize(boxed.len()) + boxed.len()) + } + + fn boxed_slice_encode<'a>( + boxed: &Box<[Self]>, + buffer: &'a mut [u8], + ) -> Result<&'a mut [u8], EncodingError> + where + Self: Sized, + { + let rest = encode_usize_var(&boxed.len(), buffer)?; + write_slice(boxed, rest) + } + + fn boxed_slice_decode(buffer: &[u8]) -> Result<(Box<[Self]>, &[u8]), EncodingError> + where + Self: Sized, + { + let (len, rest) = decode_usize(buffer)?; + let (out, rest) = get_slices_checked(rest, len)?; + Ok((out.into(), rest)) + } +} + +impl CompactEncoding for Box<[T]> { + fn encoded_size(&self) -> Result { + T::boxed_slice_encoded_size(self) + } + + fn encode<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], EncodingError> { + ::boxed_slice_encode(self, buffer) + } + + fn decode(buffer: &[u8]) -> Result<(Self, &[u8]), EncodingError> + where + Self: Sized, + { + ::boxed_slice_decode(buffer) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn decode_buff_vec() -> Result<(), EncodingError> { + let buf = &[1, 1]; + let (a, b) = decode_buffer_vec(buf)?; + assert_eq!(a, &[1]); + assert_eq!(b, &[]); + Ok(()) + } + macro_rules! check_usize_var_enc_dec { + ($size:expr, $value:expr) => { + let mut buffer = vec![0; encoded_size_usize($value)]; + assert_eq!(buffer.len(), $size); + let remaining = encode_usize_var(&$value, &mut buffer)?; + assert!(remaining.is_empty()); + let (result, rest) = decode_usize(&buffer)?; + assert!(rest.is_empty()); + assert_eq!(result, $value); + }; + } + + #[test] + fn usize_var_enc_dec() -> Result<(), EncodingError> { + check_usize_var_enc_dec!(1, 42); + check_usize_var_enc_dec!(1 + 2, 256); + check_usize_var_enc_dec!(1 + 4, 65536); + check_usize_var_enc_dec!(1 + 8, 4294967296); + + Ok(()) + } +} diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 68714ec..0000000 --- a/src/types.rs +++ /dev/null @@ -1,790 +0,0 @@ -//! Basic types of compact_encoding. -use std::convert::TryFrom; -use std::fmt; -use std::ops::Range; - -const U16_SIGNIFIER: u8 = 0xfd; -const U32_SIGNIFIER: u8 = 0xfe; -const U64_SIGNIFIER: u8 = 0xff; - -/// Specific type [EncodingError] -#[derive(fmt::Debug)] -pub enum EncodingErrorKind { - /// Encoding or decoding did not stay between [State] `start` and `end`. - OutOfBounds, - /// Buffer data overflowed type during encoding or decoding. - Overflow, - /// Buffer contained invalid data during decoding. - InvalidData, -} - -/// Encoding/decoding error. -#[derive(fmt::Debug)] -pub struct EncodingError { - /// Specific type of error - pub kind: EncodingErrorKind, - /// Message for the error - pub message: String, -} - -impl EncodingError { - /// Create EncodingError - pub fn new(kind: EncodingErrorKind, message: &str) -> Self { - Self { - kind, - message: message.to_string(), - } - } -} - -impl fmt::Display for EncodingError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let prefix = match self.kind { - EncodingErrorKind::OutOfBounds => "Compact encoding failed, out of bounds", - EncodingErrorKind::Overflow => "Compact encoding failed, overflow", - EncodingErrorKind::InvalidData => "Compact encoding failed, invalid data", - }; - write!(f, "{}: {}", prefix, self.message) - } -} - -impl From for std::io::Error { - fn from(e: EncodingError) -> Self { - match e.kind { - EncodingErrorKind::InvalidData => { - std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{e}")) - } - _ => std::io::Error::new(std::io::ErrorKind::Other, format!("{e}")), - } - } -} - -/// State. -#[derive(Debug, Clone)] -pub struct State { - /// Start position - start: usize, - /// End position - end: usize, -} - -impl Default for State { - /// Create empty state - fn default() -> Self { - Self::new() - } -} - -impl State { - /// Create empty state - pub fn new() -> State { - State::new_with_start_and_end(0, 0) - } - - /// Create a state and buffer with an already known size. - /// With this, you can/must skip the preencode step. - pub fn new_with_size(size: usize) -> (State, Box<[u8]>) { - ( - State::new_with_start_and_end(0, size), - vec![0; size].into_boxed_slice(), - ) - } - - /// Create a state with a start and end already known. - pub fn new_with_start_and_end(start: usize, end: usize) -> State { - State { start, end } - } - - /// Create a state from existing buffer. - pub fn from_buffer(buffer: &[u8]) -> State { - State::new_with_start_and_end(0, buffer.len()) - } - - /// Start value - pub fn start(&self) -> usize { - self.start - } - - /// Set start value - pub fn set_start(&mut self, value: usize) -> Result<(), EncodingError> { - if value > self.end { - return Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!("Value exceeded state.end: {} > {}", value, self.end), - )); - } - self.start = value; - Ok(()) - } - - /// End value - pub fn end(&self) -> usize { - self.end - } - - /// Set end value - pub fn set_end(&mut self, value: usize) { - self.end = value; - } - - /// Add to start handling overflow and out of bounds. - pub fn add_start(&mut self, increment: usize) -> Result { - self.start = self.start.checked_add(increment).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "State.start overflowed: {} + {} > {}", - self.start, - increment, - usize::MAX - ), - ) - })?; - if self.start > self.end { - Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!( - "State.start exceeded state.end: {} > {}", - self.start, self.end - ), - )) - } else { - Ok(self.start) - } - } - - /// Add to end handling overflow - pub fn add_end(&mut self, increment: usize) -> Result { - self.end = self.end.checked_add(increment).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "State.end overflowed: {} + {} > {}", - self.end, - increment, - usize::MAX - ), - ) - })?; - Ok(self.end) - } - - /// After calling preencode(), this allocates the right size buffer to the heap. - /// Follow this with the same number of encode() steps to fill the created buffer. - pub fn create_buffer(&self) -> Box<[u8]> { - vec![0; self.end].into_boxed_slice() - } - - /// Safely set single byte to buffer at state.start and then increment state.start, returning - /// new state.start. - pub fn set_byte_to_buffer( - &mut self, - value: u8, - buffer: &mut [u8], - ) -> Result { - if buffer.len() <= self.start { - Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!( - "Length of buffer {} too small to fit single byte", - buffer.len() - ), - )) - } else { - buffer[self.start] = value; - self.add_start(1) - } - } - - /// Safely set byte slice to buffer at state.start and then increment state.start with slice - /// length, returning new state.start. - pub fn set_slice_to_buffer( - &mut self, - value: &[u8], - buffer: &mut [u8], - ) -> Result { - self.set_slice_to_buffer_fixed(value, buffer, value.len()) - } - - /// Safely set byte slice of fixed len to buffer at state.start and then increment state.start with slice - /// length, returning new state.start. - pub fn set_slice_to_buffer_fixed( - &mut self, - value: &[u8], - buffer: &mut [u8], - size: usize, - ) -> Result { - if value.len() < size { - return Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!( - "Length of value {} too small to fit fixed size {}", - value.len(), - size - ), - )); - } - let value_end = size.checked_add(self.start).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "Value end overflowed: {} + {} > {}", - size, - self.start, - usize::MAX - ), - ) - })?; - if buffer.len() < value_end { - Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!( - "Length of buffer {} too small to fit slice of length {}", - buffer.len(), - size - ), - )) - } else { - buffer[self.start..value_end].copy_from_slice(value); - self.add_start(size) - } - } - - /// Validate `size` can be decoded from `buffer`, return current start. - pub fn validate(&mut self, size: usize, buffer: &[u8]) -> Result, EncodingError> { - let value_end = size.checked_add(self.start).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "Value end overflowed during validate: {} + {} > {}", - size, - self.start, - usize::MAX - ), - ) - })?; - - if buffer.len() < value_end { - Err(EncodingError::new( - EncodingErrorKind::Overflow, - &format!("Buffer length {} too small for size {}", buffer.len(), size,), - )) - } else { - Ok(self.start..value_end) - } - } - - /// Preencode a string slice - pub fn preencode_str(&mut self, value: &str) -> Result { - self.preencode_usize_var(&value.len())?; - self.add_end(value.len()) - } - - /// Encode a string slice - pub fn encode_str(&mut self, value: &str, buffer: &mut [u8]) -> Result { - let len = value.len(); - self.encode_usize_var(&len, buffer)?; - self.set_slice_to_buffer(value.as_bytes(), buffer) - } - - /// Decode a String - pub fn decode_string(&mut self, buffer: &[u8]) -> Result { - let len = self.decode_usize_var(buffer)?; - let range = self.validate(len, buffer)?; - let value = std::str::from_utf8(&buffer[range]).map_err(|err| { - EncodingError::new( - EncodingErrorKind::InvalidData, - &format!("String is invalid UTF-8, {err}"), - ) - })?; - self.add_start(len)?; - Ok(value.to_string()) - } - - /// Preencode a variable length usigned int - pub fn preencode_uint_var + Ord>( - &mut self, - uint: &T, - ) -> Result { - let increment: usize = if *uint < T::from(U16_SIGNIFIER.into()) { - 1 - } else if *uint <= T::from(0xffff) { - 3 - } else if *uint <= T::from(0xffffffff) { - 5 - } else { - 9 - }; - self.add_end(increment) - } - - /// Decode a fixed length u8 - pub fn decode_u8(&mut self, buffer: &[u8]) -> Result { - self.validate(1, buffer)?; - let value: u8 = buffer[self.start]; - self.add_start(1)?; - Ok(value) - } - - /// Decode a fixed length u16 - pub fn decode_u16(&mut self, buffer: &[u8]) -> Result { - self.validate(2, buffer)?; - let value: u16 = (buffer[self.start] as u16) | ((buffer[self.start + 1] as u16) << 8); - self.add_start(2)?; - Ok(value) - } - - /// Encode a variable length u32 - pub fn encode_u32_var( - &mut self, - value: &u32, - buffer: &mut [u8], - ) -> Result { - if *value < U16_SIGNIFIER.into() { - let bytes = value.to_le_bytes(); - self.set_byte_to_buffer(bytes[0], buffer) - } else if *value <= 0xffff { - self.set_byte_to_buffer(U16_SIGNIFIER, buffer)?; - self.encode_uint16_bytes(&value.to_le_bytes(), buffer) - } else { - self.set_byte_to_buffer(U32_SIGNIFIER, buffer)?; - self.encode_uint32_bytes(&value.to_le_bytes(), buffer) - } - } - - /// Encode u32 to 4 LE bytes. - pub fn encode_u32(&mut self, uint: u32, buffer: &mut [u8]) -> Result { - self.encode_uint32_bytes(&uint.to_le_bytes(), buffer) - } - - /// Decode a variable length u32 - #[allow(clippy::comparison_chain)] - pub fn decode_u32_var(&mut self, buffer: &[u8]) -> Result { - self.validate(1, buffer)?; - let first = buffer[self.start]; - self.add_start(1)?; - if first < U16_SIGNIFIER { - Ok(first.into()) - } else if first == U16_SIGNIFIER { - Ok(self.decode_u16(buffer)?.into()) - } else { - self.decode_u32(buffer) - } - } - - /// Decode a fixed length u32 - pub fn decode_u32(&mut self, buffer: &[u8]) -> Result { - self.validate(4, buffer)?; - let value: u32 = (buffer[self.start] as u32) - | ((buffer[self.start + 1] as u32) << 8) - | ((buffer[self.start + 2] as u32) << 16) - | ((buffer[self.start + 3] as u32) << 24); - self.add_start(4)?; - Ok(value) - } - - /// Encode a variable length u64 - pub fn encode_u64_var( - &mut self, - value: &u64, - buffer: &mut [u8], - ) -> Result { - if *value < U16_SIGNIFIER.into() { - let bytes = value.to_le_bytes(); - self.set_byte_to_buffer(bytes[0], buffer) - } else if *value <= 0xffff { - self.set_byte_to_buffer(U16_SIGNIFIER, buffer)?; - self.encode_uint16_bytes(&value.to_le_bytes(), buffer) - } else if *value <= 0xffffffff { - self.set_byte_to_buffer(U32_SIGNIFIER, buffer)?; - self.encode_uint32_bytes(&value.to_le_bytes(), buffer) - } else { - self.set_byte_to_buffer(U64_SIGNIFIER, buffer)?; - self.encode_uint64_bytes(&value.to_le_bytes(), buffer) - } - } - - /// Encode u64 to 8 LE bytes. - pub fn encode_u64(&mut self, uint: u64, buffer: &mut [u8]) -> Result { - self.encode_uint64_bytes(&uint.to_le_bytes(), buffer) - } - - /// Decode a variable length u64 - pub fn decode_u64_var(&mut self, buffer: &[u8]) -> Result { - self.validate(1, buffer)?; - let first = buffer[self.start]; - self.add_start(1)?; - if first < U16_SIGNIFIER { - Ok(first.into()) - } else if first == U16_SIGNIFIER { - Ok(self.decode_u16(buffer)?.into()) - } else if first == U32_SIGNIFIER { - Ok(self.decode_u32(buffer)?.into()) - } else { - self.decode_u64(buffer) - } - } - - /// Decode a fixed length u64 - pub fn decode_u64(&mut self, buffer: &[u8]) -> Result { - self.validate(8, buffer)?; - let value: u64 = (buffer[self.start] as u64) - | ((buffer[self.start + 1] as u64) << 8) - | ((buffer[self.start + 2] as u64) << 16) - | ((buffer[self.start + 3] as u64) << 24) - | ((buffer[self.start + 4] as u64) << 32) - | ((buffer[self.start + 5] as u64) << 40) - | ((buffer[self.start + 6] as u64) << 48) - | ((buffer[self.start + 7] as u64) << 56); - self.add_start(8)?; - Ok(value) - } - - /// Preencode a byte buffer - pub fn preencode_buffer(&mut self, value: &[u8]) -> Result { - let len = value.len(); - self.preencode_usize_var(&len)?; - self.add_end(len) - } - - /// Preencode a vector byte buffer - pub fn preencode_buffer_vec(&mut self, value: &Vec) -> Result { - let len = value.len(); - self.preencode_usize_var(&len)?; - self.add_end(len) - } - - /// Encode a byte buffer - pub fn encode_buffer( - &mut self, - value: &[u8], - buffer: &mut [u8], - ) -> Result { - let len = value.len(); - self.encode_usize_var(&len, buffer)?; - self.set_slice_to_buffer(value, buffer) - } - - /// Decode a byte buffer - pub fn decode_buffer(&mut self, buffer: &[u8]) -> Result, EncodingError> { - Ok(self.decode_buffer_vec(buffer)?.into_boxed_slice()) - } - - /// Decode a vector byte buffer - pub fn decode_buffer_vec(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let len = self.decode_usize_var(buffer)?; - let range = self.validate(len, buffer)?; - let value = buffer[range].to_vec(); - self.add_start(value.len())?; - Ok(value) - } - - /// Preencode a raw byte buffer. Only possible to use if this is the last value - /// of the State. - pub fn preencode_raw_buffer(&mut self, value: &Vec) -> Result { - self.add_end(value.len()) - } - - /// Encode a raw byte buffer. Only possible to use if this is the last value - /// of the State. - pub fn encode_raw_buffer( - &mut self, - value: &[u8], - buffer: &mut [u8], - ) -> Result { - self.set_slice_to_buffer(value, buffer) - } - - /// Decode a raw byte buffer. Only possible to use if this is the last value - /// of the State. - pub fn decode_raw_buffer(&mut self, buffer: &[u8]) -> Result, EncodingError> { - if self.start >= self.end { - return Err(EncodingError::new( - EncodingErrorKind::OutOfBounds, - &format!("State.start {} >= state.end {}", self.start, self.end), - )); - } - let range = self.validate(self.end - self.start, buffer)?; - let value = buffer[range].to_vec(); - self.start = self.end; - Ok(value) - } - - /// Preencode a fixed 16 byte buffer - pub fn preencode_fixed_16(&mut self) -> Result { - self.add_end(16) - } - - /// Encode a fixed 16 byte buffer - pub fn encode_fixed_16( - &mut self, - value: &[u8], - buffer: &mut [u8], - ) -> Result { - self.set_slice_to_buffer_fixed(value, buffer, 16) - } - - /// Decode a fixed 16 byte buffer - pub fn decode_fixed_16(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let range = self.validate(16, buffer)?; - let value = buffer[range].to_vec().into_boxed_slice(); - self.add_start(16)?; - Ok(value) - } - - /// Preencode a fixed 32 byte buffer - pub fn preencode_fixed_32(&mut self) -> Result { - self.add_end(32) - } - - /// Encode a fixed 32 byte buffer - pub fn encode_fixed_32( - &mut self, - value: &[u8], - buffer: &mut [u8], - ) -> Result { - self.set_slice_to_buffer_fixed(value, buffer, 32) - } - - /// Decode a fixed 32 byte buffer - pub fn decode_fixed_32(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let range = self.validate(32, buffer)?; - let value = buffer[range].to_vec().into_boxed_slice(); - self.add_start(32)?; - Ok(value) - } - - /// Preencode a string array - pub fn preencode_string_array(&mut self, value: &Vec) -> Result { - let len = value.len(); - self.preencode_usize_var(&len)?; - for string_value in value.iter() { - self.preencode_str(string_value)?; - } - Ok(self.end) - } - - /// Encode a String array - pub fn encode_string_array( - &mut self, - value: &Vec, - buffer: &mut [u8], - ) -> Result { - let len = value.len(); - self.encode_usize_var(&len, buffer)?; - for string_value in value { - self.encode_str(string_value, buffer)?; - } - Ok(self.end) - } - - /// Decode a String array - pub fn decode_string_array(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let len = self.decode_usize_var(buffer)?; - let mut value = Vec::with_capacity(len); - for _ in 0..len { - value.push(self.decode_string(buffer)?); - } - Ok(value) - } - - /// Preencode an u32 array - pub fn preencode_u32_array(&mut self, value: &Vec) -> Result { - let len = value.len(); - self.preencode_usize_var(&len)?; - let total_len = len.checked_mul(4).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "Vec total length overflowed: {} * 4 > {}", - len, - usize::MAX - ), - ) - })?; - self.add_end(total_len) - } - - /// Encode an u32 array - pub fn encode_u32_array( - &mut self, - value: &Vec, - buffer: &mut [u8], - ) -> Result { - let len = value.len(); - self.encode_usize_var(&len, buffer)?; - for entry in value { - self.encode_u32(*entry, buffer)?; - } - Ok(self.start()) - } - - /// Decode an u32 array - pub fn decode_u32_array(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let len = self.decode_usize_var(buffer)?; - let mut value: Vec = Vec::with_capacity(len); - for _ in 0..len { - value.push(self.decode_u32(buffer)?); - } - Ok(value) - } - - /// Preencode a fixed 32 byte value array - pub fn preencode_fixed_32_array( - &mut self, - value: &Vec<[u8; 32]>, - ) -> Result { - let len = value.len(); - self.preencode(&len)?; - let size = len.checked_mul(32).ok_or_else(|| { - EncodingError::new( - EncodingErrorKind::Overflow, - &format!( - "Vec<[u8; 32]> byte size overflowed: {} * 32 > {}", - len, - usize::MAX - ), - ) - })?; - self.add_end(size)?; - Ok(self.end()) - } - - /// Encode a fixed 32 byte value array - pub fn encode_fixed_32_array( - &mut self, - value: &Vec<[u8; 32]>, - buffer: &mut [u8], - ) -> Result { - self.encode(&value.len(), buffer)?; - for entry in value { - self.set_slice_to_buffer_fixed(entry, buffer, 32)?; - } - Ok(self.start()) - } - - /// Decode a fixed 32 byte value array - pub fn decode_fixed_32_array(&mut self, buffer: &[u8]) -> Result, EncodingError> { - let len: usize = self.decode(buffer)?; - let mut entries: Vec<[u8; 32]> = Vec::with_capacity(len); - for _ in 0..len { - let range = self.validate(32, buffer)?; - entries.push(buffer[range].try_into().map_err(|err| { - EncodingError::new( - EncodingErrorKind::InvalidData, - &format!("Could not convert byte slice to [u8; 32], {err}"), - ) - })?); - self.add_start(32)?; - } - Ok(entries) - } - - /// Preencode a variable length usize - pub fn preencode_usize_var(&mut self, value: &usize) -> Result { - // This repeats the logic from above that works for u8 -> u64, but sadly not usize - let increment: usize = if *value < U16_SIGNIFIER.into() { - 1 - } else if *value <= 0xffff { - 3 - } else if *value <= 0xffffffff { - 5 - } else { - 9 - }; - self.add_end(increment) - } - - /// Encode a variable length usize - pub fn encode_usize_var( - &mut self, - value: &usize, - buffer: &mut [u8], - ) -> Result { - if *value < U16_SIGNIFIER.into() { - let bytes = value.to_le_bytes(); - self.set_byte_to_buffer(bytes[0], buffer) - } else if *value <= 0xffff { - self.set_byte_to_buffer(U16_SIGNIFIER, buffer)?; - self.encode_uint16_bytes(&value.to_le_bytes(), buffer) - } else if *value <= 0xffffffff { - self.set_byte_to_buffer(U32_SIGNIFIER, buffer)?; - self.encode_uint32_bytes(&value.to_le_bytes(), buffer) - } else { - self.set_byte_to_buffer(U64_SIGNIFIER, buffer)?; - self.encode_uint64_bytes(&value.to_le_bytes(), buffer) - } - } - - /// Decode a variable length usize. - pub fn decode_usize_var(&mut self, buffer: &[u8]) -> Result { - self.validate(1, buffer)?; - let first = buffer[self.start]; - self.add_start(1)?; - // NB: the from_le_bytes needs a [u8; 2] and that can't be efficiently - // created from a byte slice. - if first < U16_SIGNIFIER { - Ok(first.into()) - } else if first == U16_SIGNIFIER { - Ok(self.decode_u16(buffer)?.into()) - } else if first == U32_SIGNIFIER { - usize::try_from(self.decode_u32(buffer)?).map_err(|_| { - EncodingError::new( - EncodingErrorKind::Overflow, - "Attempted converting to a 32 bit usize on below 32 bit system", - ) - }) - } else { - usize::try_from(self.decode_u64(buffer)?).map_err(|_| { - EncodingError::new( - EncodingErrorKind::Overflow, - "Attempted converting to a 64 bit usize on below 64 bit system", - ) - }) - } - } - - /// Encode a 2 byte unsigned integer. NB: assumes `bytes` buffer large enough, hence not public! - fn encode_uint16_bytes( - &mut self, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result { - self.set_slice_to_buffer(&bytes[..2], buffer) - } - - /// Encode a 4 byte unsigned integer. NB: assumes `bytes` buffer large enough, hence not public! - fn encode_uint32_bytes( - &mut self, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result { - self.encode_uint16_bytes(bytes, buffer)?; - self.set_slice_to_buffer(&bytes[2..4], buffer) - } - - /// Encode an 8 byte unsigned integer. NB: assumes `bytes` buffer large enough, hence not public! - fn encode_uint64_bytes( - &mut self, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result { - self.encode_uint32_bytes(bytes, buffer)?; - self.set_slice_to_buffer(&bytes[4..8], buffer) - } -} - -/// Compact Encoding -pub trait CompactEncoding -where - T: fmt::Debug, -{ - /// Preencode - fn preencode(&mut self, value: &T) -> Result; - - /// Encode - fn encode(&mut self, value: &T, buffer: &mut [u8]) -> Result; - - /// Decode - fn decode(&mut self, buffer: &[u8]) -> Result; -} diff --git a/tests/encodable.rs b/tests/encodable.rs new file mode 100644 index 0000000..caefa88 --- /dev/null +++ b/tests/encodable.rs @@ -0,0 +1,204 @@ +use compact_encoding::{create_buffer, map_decode, map_encode, CompactEncoding, EncodingError}; + +// The max value for 1 byte length is 252 +const MAX_ONE_BYTE_UINT: u8 = 252; + +// The min value for 2 byte length is 253 +const MIN_TWO_BYTE_UINT: u8 = 253; + +#[test] +fn cenc_basic() -> Result<(), EncodingError> { + let str_value_1 = "foo"; + let str_value_2 = (0..MAX_ONE_BYTE_UINT).map(|_| "X").collect::(); + let u32_value_3: u32 = u32::MAX; + let u32_value_4: u32 = 0xF0E1D2C3; + + let mut buff = create_buffer!(str_value_1, str_value_2, u32_value_3, u32_value_4); + assert_eq!(buff.len(), 1 + 3 + 1 + 252 + 1 + 4 + 1 + 4); + + let rest = map_encode!( + &mut buff, + str_value_1, + str_value_2, + u32_value_3, + u32_value_4 + ); + assert!(rest.is_empty()); + let (result, remaning_buff) = map_decode!(&buff, [String, String, u32, u32]); + assert!(remaning_buff.is_empty()); + + assert_eq!(result.0, str_value_1); + assert_eq!(result.1, str_value_2); + assert_eq!(result.2, u32_value_3); + assert_eq!(result.3, u32_value_4); + Ok(()) +} + +#[test] +fn cenc_string_long() -> Result<(), EncodingError> { + let value = (0..MIN_TWO_BYTE_UINT).map(|_| "X").collect::(); + assert_eq!(value.len(), 253); + let mut buffer = create_buffer!(value); + assert_eq!(buffer.len(), 1 + 2 + 253); + + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + + let ((result,), rest) = map_decode!(&buffer, [String]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_u32_as_u16() -> Result<(), EncodingError> { + let value: u32 = u16::MAX.into(); + let mut buffer = create_buffer!(value); + // 1 byte for u16 signifier, 2 bytes for length + assert_eq!(buffer.len(), 1 + 2); + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + + let ((result,), rest) = map_decode!(&buffer, [u32]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_u32_as_u8() -> Result<(), EncodingError> { + let value: u32 = MAX_ONE_BYTE_UINT.into(); + let mut buffer = create_buffer!(value); + // 1 byte for data + assert_eq!(buffer.len(), 1); + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + + let ((result,), rest) = map_decode!(&buffer, [u32]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_u64() -> Result<(), EncodingError> { + let value: u64 = 0xF0E1D2C3B4A59687; + let mut buffer = create_buffer!(value); + // 1 byte for u64 signifier, 8 bytes for length + assert_eq!(buffer.len(), 1 + 8); + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + let ((result,), rest) = map_decode!(&buffer, [u64]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_u64_as_u32() -> Result<(), EncodingError> { + let value: u64 = u32::MAX.into(); + let mut buffer = create_buffer!(value); + // 1 byte for u32 signifier, 4 bytes for length + assert_eq!(buffer.len(), 1 + 4); + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + let ((result,), rest) = map_decode!(&buffer, [u64]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_buffer() -> Result<(), EncodingError> { + let buf_value_1 = vec![0xFF, 0x00].into_boxed_slice(); + let buf_value_2 = vec![0xEE, 0x11, 0x22].into_boxed_slice(); + + let mut buffer = create_buffer!(buf_value_1, buf_value_2); + // 1 byte for length, 2 bytes for data + // 1 byte for length, 3 bytes for data + assert_eq!(buffer.len(), 1 + 2 + 1 + 3); + let rest = map_encode!(&mut buffer, buf_value_1, buf_value_2); + assert!(rest.is_empty()); + let (result, rest) = map_decode!(&buffer, [Box<[u8]>, Box<[u8]>]); + assert!(rest.is_empty()); + assert_eq!(result.0, buf_value_1); + assert_eq!(result.1, buf_value_2); + Ok(()) +} + +#[test] +fn cenc_vec() -> Result<(), EncodingError> { + let buf_value_1: Vec = vec![0xFF, 0x00]; + let buf_value_2: Vec = vec![0xFFFFFFFF, 0x11223344, 0x99887766]; + + let mut buffer = create_buffer!(buf_value_1, buf_value_2); + // 1 byte for length, 2 bytes for data + // 1 byte for length, 4*3 bytes for data + assert_eq!(buffer.len(), 1 + 2 + 1 + 12); + + let rest = map_encode!(&mut buffer, buf_value_1, buf_value_2); + assert!(rest.is_empty()); + let (result, rest) = map_decode!(&buffer, [Vec, Vec]); + assert!(rest.is_empty()); + assert_eq!(result.0, buf_value_1); + assert_eq!(result.1, buf_value_2); + Ok(()) +} + +#[test] +fn cenc_string_array() -> Result<(), EncodingError> { + let value = vec!["first".to_string(), "second".to_string()]; + let mut buffer = create_buffer!(value); + // 1 byte for array length, + // 1 byte for string length, 5 bytes for string, + // 1 byte for string length, 6 bytes for string + assert_eq!(buffer.len(), 1 + 1 + 5 + 1 + 6); + let rest = map_encode!(&mut buffer, value); + assert!(rest.is_empty()); + let ((result,), rest) = map_decode!(&buffer, [Vec]); + assert!(rest.is_empty()); + assert_eq!(result, value); + Ok(()) +} + +#[test] +fn cenc_fixed_and_raw() -> Result<(), EncodingError> { + let buf_value_1: [u8; 16] = [0xEE; 16]; + let buf_value_2: [u8; 32] = [0xFF; 32]; + let buf_value_3: [u8; 3] = [0xFF, 0x11, 0x99]; + + let mut buffer = create_buffer!(buf_value_1, buf_value_2, buf_value_3); + // 1 byte for length, 2 bytes for data + // 1 byte for length, 4*3 bytes for data + assert_eq!(buffer.len(), 16 + 32 + 3); + + let rest = map_encode!(&mut buffer, buf_value_1, buf_value_2, buf_value_3); + assert!(rest.is_empty()); + let (result, rest) = map_decode!(&buffer, [[u8; 16], [u8; 32], [u8; 3]]); + assert!(rest.is_empty()); + assert_eq!(result.0, buf_value_1); + assert_eq!(result.1, buf_value_2); + assert_eq!(result.2, buf_value_3); + Ok(()) +} + +#[test] +fn cenc_32_byte_array() -> Result<(), EncodingError> { + let empty_array: Vec<[u8; 32]> = vec![]; + let one_array: Vec<[u8; 32]> = vec![[0; 32]]; + let many_array: Vec<[u8; 32]> = vec![[1; 32], [2; 32], [3; 32]]; + let expected_size = 1 + 1 + 32 + 1 + (3 * 32); + + let mut buffer = create_buffer!(empty_array, one_array, many_array); + assert_eq!(buffer.len(), expected_size); + + let rest = map_encode!(&mut buffer, empty_array, one_array, many_array); + assert!(rest.is_empty()); + + let (result, rest) = map_decode!(&buffer, [Vec<[u8; 32]>, Vec<[u8; 32]>, Vec<[u8;32]>]); + assert!(rest.is_empty()); + assert_eq!(result.0, empty_array); + assert_eq!(result.1, one_array); + assert_eq!(result.2, many_array); + Ok(()) +} diff --git a/tests/generic.rs b/tests/generic.rs deleted file mode 100644 index d1228c6..0000000 --- a/tests/generic.rs +++ /dev/null @@ -1,228 +0,0 @@ -use compact_encoding::{CompactEncoding, EncodingError, State}; - -// The max value for 1 byte length is 252 -const MAX_ONE_BYTE_UINT: u8 = 252; - -// The min value for 2 byte length is 253 -const MIN_TWO_BYTE_UINT: u8 = 253; - -#[test] -fn cenc_basic() -> Result<(), EncodingError> { - let str_value_1 = "foo"; - let str_value_2 = (0..MAX_ONE_BYTE_UINT).map(|_| "X").collect::(); - let u32_value_3: u32 = u32::MAX; - let u32_value_4: u32 = 0xF0E1D2C3; - - let mut enc_state = State::new(); - enc_state.preencode_str(str_value_1)?; - enc_state.preencode(&str_value_2)?; - enc_state.preencode(&u32_value_3)?; - enc_state.preencode(&u32_value_4)?; - let mut buffer = enc_state.create_buffer(); - // Strings: 1 byte for length, 3/252 bytes for content - // u32: 1 byte for u32 signifier, 4 bytes for data - assert_eq!(buffer.len(), 1 + 3 + 1 + 252 + 1 + 4 + 1 + 4); - enc_state.encode_str(str_value_1, &mut buffer)?; - enc_state.encode(&str_value_2, &mut buffer)?; - enc_state.encode(&u32_value_3, &mut buffer)?; - enc_state.encode(&u32_value_4, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let str_value_1_ret: String = dec_state.decode(&buffer)?; - assert_eq!(str_value_1, str_value_1_ret); - let str_value_2_ret: String = dec_state.decode(&buffer)?; - assert_eq!(str_value_2, str_value_2_ret); - let u32_value_3_ret: u32 = dec_state.decode(&buffer)?; - assert_eq!(u32_value_3, u32_value_3_ret); - let u32_value_4_ret: u32 = dec_state.decode(&buffer)?; - assert_eq!(u32_value_4, u32_value_4_ret); - Ok(()) -} - -#[test] -fn cenc_string_long() -> Result<(), EncodingError> { - let str_value = (0..MIN_TWO_BYTE_UINT).map(|_| "X").collect::(); - assert_eq!(str_value.len(), 253); - let mut enc_state = State::new(); - enc_state.preencode(&str_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for u16 signifier, 2 bytes for length, 256 bytes for data - assert_eq!(buffer.len(), 1 + 2 + 253); - enc_state.encode(&str_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let str_value_ret: String = dec_state.decode(&buffer)?; - assert_eq!(str_value, str_value_ret); - Ok(()) -} - -#[test] -fn cenc_u32_as_u16() -> Result<(), EncodingError> { - let u32_value: u32 = u16::MAX.into(); - let mut enc_state = State::new(); - enc_state.preencode(&u32_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for u16 signifier, 2 bytes for length - assert_eq!(buffer.len(), 1 + 2); - enc_state.encode(&u32_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let u32_value_ret: u32 = dec_state.decode(&buffer)?; - assert_eq!(u32_value, u32_value_ret); - Ok(()) -} - -#[test] -fn cenc_u32_as_u8() -> Result<(), EncodingError> { - let u32_value: u32 = MAX_ONE_BYTE_UINT.into(); - let mut enc_state = State::new(); - enc_state.preencode(&u32_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for data - assert_eq!(buffer.len(), 1); - enc_state.encode(&u32_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let u32_value_ret: u32 = dec_state.decode(&buffer)?; - assert_eq!(u32_value, u32_value_ret); - Ok(()) -} - -#[test] -fn cenc_u64() -> Result<(), EncodingError> { - let u64_value: u64 = 0xF0E1D2C3B4A59687; - let mut enc_state = State::new(); - enc_state.preencode(&u64_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for u64 signifier, 8 bytes for length - assert_eq!(buffer.len(), 1 + 8); - enc_state.encode(&u64_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let u64_value_ret: u64 = dec_state.decode(&buffer)?; - assert_eq!(u64_value, u64_value_ret); - Ok(()) -} - -#[test] -fn cenc_u64_as_u32() -> Result<(), EncodingError> { - let u64_value: u64 = u32::MAX.into(); - let mut enc_state = State::new(); - enc_state.preencode(&u64_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for u32 signifier, 4 bytes for length - assert_eq!(buffer.len(), 1 + 4); - enc_state.encode(&u64_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let u64_value_ret: u64 = dec_state.decode(&buffer)?; - assert_eq!(u64_value, u64_value_ret); - Ok(()) -} - -#[test] -fn cenc_buffer() -> Result<(), EncodingError> { - let buf_value_1 = vec![0xFF, 0x00].into_boxed_slice(); - let buf_value_2 = vec![0xEE, 0x11, 0x22].into_boxed_slice(); - let mut enc_state = State::new(); - enc_state.preencode(&buf_value_1)?; - enc_state.preencode(&buf_value_2)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for length, 2 bytes for data - // 1 byte for length, 3 bytes for data - assert_eq!(buffer.len(), 1 + 2 + 1 + 3); - enc_state.encode(&buf_value_1, &mut buffer)?; - enc_state.encode(&buf_value_2, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let buf_value_1_ret: Box<[u8]> = dec_state.decode(&buffer)?; - let buf_value_2_ret: Box<[u8]> = dec_state.decode(&buffer)?; - assert_eq!(buf_value_1, buf_value_1_ret); - assert_eq!(buf_value_2, buf_value_2_ret); - - Ok(()) -} - -#[test] -fn cenc_vec() -> Result<(), EncodingError> { - let buf_value_1: Vec = vec![0xFF, 0x00]; - let buf_value_2: Vec = vec![0xFFFFFFFF, 0x11223344, 0x99887766]; - let mut enc_state = State::new(); - enc_state.preencode(&buf_value_1)?; - enc_state.preencode(&buf_value_2)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for length, 2 bytes for data - // 1 byte for length, 4*3 bytes for data - assert_eq!(buffer.len(), 1 + 2 + 1 + 12); - enc_state.encode(&buf_value_1, &mut buffer)?; - enc_state.encode(&buf_value_2, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let buf_value_1_ret: Vec = dec_state.decode(&buffer)?; - let buf_value_2_ret: Vec = dec_state.decode(&buffer)?; - assert_eq!(buf_value_1, buf_value_1_ret); - assert_eq!(buf_value_2, buf_value_2_ret); - Ok(()) -} - -#[test] -fn cenc_string_array() -> Result<(), EncodingError> { - let string_array_value = vec!["first".to_string(), "second".to_string()]; - let mut enc_state = State::new(); - enc_state.preencode(&string_array_value)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for array length, - // 1 byte for string length, 5 bytes for string, - // 1 byte for string length, 6 bytes for string - assert_eq!(buffer.len(), 1 + 1 + 5 + 1 + 6); - enc_state.encode(&string_array_value, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let string_array_value_ret: Vec = dec_state.decode(&buffer)?; - assert_eq!(string_array_value, string_array_value_ret); - Ok(()) -} - -#[test] -fn cenc_fixed_and_raw() -> Result<(), EncodingError> { - let buf_value_1: Vec = vec![0xEE; 16]; - let buf_value_2: Vec = vec![0xFF; 32]; - let buf_value_3: Vec = vec![0xFF, 0x11, 0x99]; - let mut enc_state = State::new(); - enc_state.preencode_fixed_16()?; - enc_state.preencode_fixed_32()?; - enc_state.preencode_raw_buffer(&buf_value_3)?; - let mut buffer = enc_state.create_buffer(); - // 16 + 32 bytes for data - // 3 bytes for data - assert_eq!(buffer.len(), 16 + 32 + 3); - enc_state.encode_fixed_16(&buf_value_1, &mut buffer)?; - enc_state.encode_fixed_32(&buf_value_2, &mut buffer)?; - enc_state.encode_raw_buffer(&buf_value_3, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let buf_value_1_ret: Vec = dec_state.decode_fixed_16(&buffer)?.to_vec(); - let buf_value_2_ret: Vec = dec_state.decode_fixed_32(&buffer)?.to_vec(); - let buf_value_3_ret: Vec = dec_state.decode_raw_buffer(&buffer)?; - assert_eq!(buf_value_1, buf_value_1_ret); - assert_eq!(buf_value_2, buf_value_2_ret); - assert_eq!(buf_value_3, buf_value_3_ret); - Ok(()) -} - -#[test] -fn cenc_32_byte_array() -> Result<(), EncodingError> { - let empty_array: Vec<[u8; 32]> = vec![]; - let one_array: Vec<[u8; 32]> = vec![[0; 32]]; - let many_array: Vec<[u8; 32]> = vec![[1; 32], [2; 32], [3; 32]]; - let mut enc_state = State::new(); - - enc_state.preencode(&empty_array)?; - enc_state.preencode(&one_array)?; - enc_state.preencode(&many_array)?; - let mut buffer = enc_state.create_buffer(); - // 1 byte for array length, - // 32 bytes for content - assert_eq!(buffer.len(), 1 + 1 + 32 + 1 + 3 * 32); - enc_state.encode(&empty_array, &mut buffer)?; - enc_state.encode(&one_array, &mut buffer)?; - enc_state.encode(&many_array, &mut buffer)?; - let mut dec_state = State::from_buffer(&buffer); - let empty_array_ret: Vec<[u8; 32]> = dec_state.decode(&buffer)?; - let one_array_ret: Vec<[u8; 32]> = dec_state.decode(&buffer)?; - let many_array_ret: Vec<[u8; 32]> = dec_state.decode(&buffer)?; - assert_eq!(empty_array, empty_array_ret); - assert_eq!(one_array, one_array_ret); - assert_eq!(many_array, many_array_ret); - Ok(()) -}