From 723bdd312aebe73ab9324557337c2608c99db030 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 09:25:47 +0200 Subject: [PATCH] Turned Config::INT_ENCODING back into a const, made a ton of varint_encode functions --- docs/spec.md | 10 +- src/config.rs | 20 +- src/enc/encoder.rs | 121 +++++++++-- src/int_encoding.rs | 120 ----------- src/lib.rs | 2 +- src/varint_encoding/mod.rs | 17 ++ src/varint_encoding/signed.rs | 95 ++++++++ src/varint_encoding/unsigned.rs | 371 ++++++++++++++++++++++++++++++++ tests/derive.rs | 4 +- 9 files changed, 611 insertions(+), 149 deletions(-) delete mode 100644 src/int_encoding.rs create mode 100644 src/varint_encoding/mod.rs create mode 100644 src/varint_encoding/signed.rs create mode 100644 src/varint_encoding/unsigned.rs diff --git a/docs/spec.md b/docs/spec.md index ed23380..fb24e24 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -4,6 +4,10 @@ Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123 +## Endian + +By default `bincode` will serialize values in little endian encoding. This can be overwritten in the `Config`. + ## Basic types Boolean types are encoded with 1 byte for each boolean type, with `0` being `false`, `1` being true. Whilst deserilizing every other value will throw an error. @@ -23,10 +27,10 @@ assert_eq!(encoded.as_slice(), &[ ``` ## IntEncoding -Bincode currently supports 2 different types of `IntEncoding`: +Bincode currently supports 2 different types of `IntEncoding`. With the default config, `VarintEncoding` is selected. ### VarintEncoding -Encoding an unsigned integer v (of any type excepting u8) works as follows: +Encoding an unsigned integer v (of any type excepting u8/i8) works as follows: 1. If `u < 251`, encode it as a single byte with that value. 1. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`. @@ -34,6 +38,8 @@ Encoding an unsigned integer v (of any type excepting u8) works as follows: 1. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`. 1. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a u128 with value `u`. +`usize` is being encoded/decoded as a `u64` and `isize` is being encoded/decoded as a `i64`. + See the documentation of [VarintEncoding](https://docs.rs/bincode/latest/bincode/config/struct.VarintEncoding.html) for more information. ### FixintEncoding diff --git a/src/config.rs b/src/config.rs index 31f90d1..751146b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,26 +1,19 @@ -use crate::int_encoding::FixintEncoding; - pub(crate) use self::internal::*; pub trait Config: InternalConfig + Sized {} pub struct Default; -impl InternalConfig for Default { - type IntEncoding = FixintEncoding; -} +impl InternalConfig for Default {} impl Config for T {} mod internal { - use crate::int_encoding::IntEncoding; - pub trait InternalConfig { const ENDIAN: Endian = Endian::Little; + const INT_ENCODING: IntEncoding = IntEncoding::Variable; const LIMIT: Option = None; const ALLOW_TRAILING: bool = true; - - type IntEncoding: IntEncoding; } #[derive(PartialEq, Eq)] @@ -29,11 +22,16 @@ mod internal { Big, } + #[derive(PartialEq, Eq)] + pub enum IntEncoding { + Fixed, + Variable, + } + impl<'a, C: InternalConfig> InternalConfig for &'a mut C { const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; - - type IntEncoding = C::IntEncoding; } } diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 6f7ea95..0fede26 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,6 +1,9 @@ use super::write::Writer; use super::Encode; -use crate::{config::Config, error::Error, int_encoding::IntEncoding}; +use crate::{ + config::{Config, Endian, IntEncoding}, + error::Error, +}; use core::marker::PhantomData; pub struct Encoder { @@ -27,23 +30,63 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_u16(&mut self, val: u16) -> Result<(), Error> { - ::int_encode_u16(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_u16(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_u32(&mut self, val: u32) -> Result<(), Error> { - ::int_encode_u32(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_u32(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_u64(&mut self, val: u64) -> Result<(), Error> { - ::int_encode_u64(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_u64(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_u128(&mut self, val: u128) -> Result<(), Error> { - ::int_encode_u128(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_u128(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_usize(&mut self, val: usize) -> Result<(), Error> { - ::int_encode_usize(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_usize(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_i8(&mut self, val: i8) -> Result<(), Error> { @@ -51,31 +94,83 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_i16(&mut self, val: i16) -> Result<(), Error> { - ::int_encode_i16(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_i16(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_i32(&mut self, val: i32) -> Result<(), Error> { - ::int_encode_i32(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_i32(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_i64(&mut self, val: i64) -> Result<(), Error> { - ::int_encode_i64(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_i64(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_i128(&mut self, val: i128) -> Result<(), Error> { - ::int_encode_i128(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_i128(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_isize(&mut self, val: isize) -> Result<(), Error> { - ::int_encode_isize(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint_encoding::varint_encode_isize(&mut self.writer, C::ENDIAN, val) + } + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_f32(&mut self, val: f32) -> Result<(), Error> { - ::int_encode_f32(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => unimplemented!(), // crate::int_encoding::varint_encode_f32(&mut self.writer, C::ENDIAN, val), + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_f64(&mut self, val: f64) -> Result<(), Error> { - ::int_encode_f64(&mut self.writer, C::ENDIAN, val) + match C::INT_ENCODING { + IntEncoding::Variable => unimplemented!(), // crate::int_encoding::varint_encode_f64(&mut self.writer, C::ENDIAN, val), + IntEncoding::Fixed => match C::ENDIAN { + Endian::Big => self.writer.write(&val.to_be_bytes()), + Endian::Little => self.writer.write(&val.to_le_bytes()), + }, + } } fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { diff --git a/src/int_encoding.rs b/src/int_encoding.rs deleted file mode 100644 index ba6622e..0000000 --- a/src/int_encoding.rs +++ /dev/null @@ -1,120 +0,0 @@ -use crate::{config::Endian, enc::write::Writer, error::Error}; - -pub trait IntEncoding { - fn int_encode_u16(writer: &mut W, endian: Endian, val: u16) -> Result<(), Error>; - fn int_encode_u32(writer: &mut W, endian: Endian, val: u32) -> Result<(), Error>; - fn int_encode_u64(writer: &mut W, endian: Endian, val: u64) -> Result<(), Error>; - fn int_encode_u128(writer: &mut W, endian: Endian, val: u128) -> Result<(), Error>; - fn int_encode_usize(writer: &mut W, endian: Endian, val: usize) - -> Result<(), Error>; - - fn int_encode_i16(writer: &mut W, endian: Endian, val: i16) -> Result<(), Error>; - fn int_encode_i32(writer: &mut W, endian: Endian, val: i32) -> Result<(), Error>; - fn int_encode_i64(writer: &mut W, endian: Endian, val: i64) -> Result<(), Error>; - fn int_encode_i128(writer: &mut W, endian: Endian, val: i128) -> Result<(), Error>; - fn int_encode_isize(writer: &mut W, endian: Endian, val: isize) - -> Result<(), Error>; - - fn int_encode_f32(writer: &mut W, endian: Endian, val: f32) -> Result<(), Error>; - fn int_encode_f64(writer: &mut W, endian: Endian, val: f64) -> Result<(), Error>; -} - -#[derive(Copy, Clone)] -pub struct VarintEncoding; - -#[derive(Copy, Clone)] -pub struct FixintEncoding; - -impl IntEncoding for FixintEncoding { - fn int_encode_u16(writer: &mut W, endian: Endian, val: u16) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_u32(writer: &mut W, endian: Endian, val: u32) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_u64(writer: &mut W, endian: Endian, val: u64) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_u128(writer: &mut W, endian: Endian, val: u128) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_usize( - writer: &mut W, - endian: Endian, - val: usize, - ) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_i16(writer: &mut W, endian: Endian, val: i16) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_i32(writer: &mut W, endian: Endian, val: i32) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_i64(writer: &mut W, endian: Endian, val: i64) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_i128(writer: &mut W, endian: Endian, val: i128) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_isize( - writer: &mut W, - endian: Endian, - val: isize, - ) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_f32(writer: &mut W, endian: Endian, val: f32) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } - - fn int_encode_f64(writer: &mut W, endian: Endian, val: f64) -> Result<(), Error> { - match endian { - Endian::Big => writer.write(&val.to_be_bytes()), - Endian::Little => writer.write(&val.to_le_bytes()), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 3c72acb..912f3ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ pub mod error; pub use bincode_derive::{Decodable, Encodable}; -pub(crate) mod int_encoding; +pub(crate) mod varint_encoding; pub fn encode_into_slice( val: E, diff --git a/src/varint_encoding/mod.rs b/src/varint_encoding/mod.rs new file mode 100644 index 0000000..d25f3a0 --- /dev/null +++ b/src/varint_encoding/mod.rs @@ -0,0 +1,17 @@ +mod signed; +mod unsigned; + +pub use self::signed::{ + varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64, + varint_encode_isize, +}; +pub use self::unsigned::{ + varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64, + varint_encode_usize, +}; + +pub(self) const SINGLE_BYTE_MAX: u8 = 250; +pub(self) const U16_BYTE: u8 = 251; +pub(self) const U32_BYTE: u8 = 252; +pub(self) const U64_BYTE: u8 = 253; +pub(self) const U128_BYTE: u8 = 254; diff --git a/src/varint_encoding/signed.rs b/src/varint_encoding/signed.rs new file mode 100644 index 0000000..b41f190 --- /dev/null +++ b/src/varint_encoding/signed.rs @@ -0,0 +1,95 @@ +use super::{varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64}; +use crate::{config::Endian, enc::write::Writer, error::Error}; + +pub fn varint_encode_i16(writer: &mut W, endian: Endian, val: i16) -> Result<(), Error> { + varint_encode_u16( + writer, + endian, + if val < 0 { + // let's avoid the edge case of i16::min_value() + // !n is equal to `-n - 1`, so this is: + // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1 + !(val as u16) * 2 + 1 + } else { + (val as u16) * 2 + }, + ) +} + +pub fn varint_encode_i32(writer: &mut W, endian: Endian, val: i32) -> Result<(), Error> { + varint_encode_u32( + writer, + endian, + if val < 0 { + // let's avoid the edge case of i32::min_value() + // !n is equal to `-n - 1`, so this is: + // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1 + !(val as u32) * 2 + 1 + } else { + (val as u32) * 2 + }, + ) +} + +pub fn varint_encode_i64(writer: &mut W, endian: Endian, val: i64) -> Result<(), Error> { + varint_encode_u64( + writer, + endian, + if val < 0 { + // let's avoid the edge case of i64::min_value() + // !n is equal to `-n - 1`, so this is: + // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1 + !(val as u64) * 2 + 1 + } else { + (val as u64) * 2 + }, + ) +} + +pub fn varint_encode_i128( + writer: &mut W, + endian: Endian, + val: i128, +) -> Result<(), Error> { + varint_encode_u128( + writer, + endian, + if val < 0 { + // let's avoid the edge case of i128::min_value() + // !n is equal to `-n - 1`, so this is: + // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1 + !(val as u128) * 2 + 1 + } else { + (val as u128) * 2 + }, + ) +} + +pub fn varint_encode_isize( + writer: &mut W, + endian: Endian, + val: isize, +) -> Result<(), Error> { + // isize is being encoded as a i64 + varint_encode_i64(writer, endian, val as i64) +} + +#[test] +fn test_encode_i16() { + // TODO +} + +#[test] +fn test_encode_i32() { + // TODO +} + +#[test] +fn test_encode_i64() { + // TODO +} + +#[test] +fn test_encode_i128() { + // TODO +} diff --git a/src/varint_encoding/unsigned.rs b/src/varint_encoding/unsigned.rs new file mode 100644 index 0000000..99ba53f --- /dev/null +++ b/src/varint_encoding/unsigned.rs @@ -0,0 +1,371 @@ +use super::{SINGLE_BYTE_MAX, U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE}; +use crate::{config::Endian, enc::write::Writer, error::Error}; + +pub fn varint_encode_u16(writer: &mut W, endian: Endian, val: u16) -> Result<(), Error> { + if val <= SINGLE_BYTE_MAX as _ { + writer.write(&[val as u8]) + } else { + writer.write(&[U16_BYTE])?; + match endian { + Endian::Big => writer.write(&val.to_be_bytes()), + Endian::Little => writer.write(&val.to_le_bytes()), + } + } +} + +pub fn varint_encode_u32(writer: &mut W, endian: Endian, val: u32) -> Result<(), Error> { + if val <= SINGLE_BYTE_MAX as _ { + writer.write(&[val as u8]) + } else if val <= u16::MAX as _ { + writer.write(&[U16_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u16).to_be_bytes()), + Endian::Little => writer.write(&(val as u16).to_le_bytes()), + } + } else { + writer.write(&[U32_BYTE])?; + match endian { + Endian::Big => writer.write(&val.to_be_bytes()), + Endian::Little => writer.write(&val.to_le_bytes()), + } + } +} + +pub fn varint_encode_u64(writer: &mut W, endian: Endian, val: u64) -> Result<(), Error> { + if val <= SINGLE_BYTE_MAX as _ { + writer.write(&[val as u8]) + } else if val <= u16::MAX as _ { + writer.write(&[U16_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u16).to_be_bytes()), + Endian::Little => writer.write(&(val as u16).to_le_bytes()), + } + } else if val <= u32::MAX as _ { + writer.write(&[U32_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u32).to_be_bytes()), + Endian::Little => writer.write(&(val as u32).to_le_bytes()), + } + } else { + writer.write(&[U64_BYTE])?; + match endian { + Endian::Big => writer.write(&val.to_be_bytes()), + Endian::Little => writer.write(&val.to_le_bytes()), + } + } +} + +pub fn varint_encode_u128( + writer: &mut W, + endian: Endian, + val: u128, +) -> Result<(), Error> { + if val <= SINGLE_BYTE_MAX as _ { + writer.write(&[val as u8]) + } else if val <= u16::MAX as _ { + writer.write(&[U16_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u16).to_be_bytes()), + Endian::Little => writer.write(&(val as u16).to_le_bytes()), + } + } else if val <= u32::MAX as _ { + writer.write(&[U32_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u32).to_be_bytes()), + Endian::Little => writer.write(&(val as u32).to_le_bytes()), + } + } else if val <= u64::MAX as _ { + writer.write(&[U64_BYTE])?; + match endian { + Endian::Big => writer.write(&(val as u64).to_be_bytes()), + Endian::Little => writer.write(&(val as u64).to_le_bytes()), + } + } else { + writer.write(&[U128_BYTE])?; + match endian { + Endian::Big => writer.write(&val.to_be_bytes()), + Endian::Little => writer.write(&val.to_le_bytes()), + } + } +} + +pub fn varint_encode_usize( + writer: &mut W, + endian: Endian, + val: usize, +) -> Result<(), Error> { + // usize is being encoded as a u64 + varint_encode_u64(writer, endian, val as u64) +} + +#[test] +fn test_encode_u16() { + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + + // these should all encode to a single byte + for i in 0u16..=SINGLE_BYTE_MAX as u16 { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u16(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u16, i); + + // Assert endianness doesn't matter + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u16(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u16, i); + } + + // these values should encode in 3 bytes (leading byte + 2 bytes) + // Values chosen at random, add new cases as needed + for i in [ + SINGLE_BYTE_MAX as u16 + 1, + 300, + 500, + 700, + 888, + 1234, + u16::MAX, + ] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u16(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &i.to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u16(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &i.to_le_bytes()); + } +} + +#[test] +fn test_encode_u32() { + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + + // these should all encode to a single byte + for i in 0u32..=SINGLE_BYTE_MAX as u32 { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u32, i); + + // Assert endianness doesn't matter + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u32, i); + } + + // these values should encode in 3 bytes (leading byte + 2 bytes) + // Values chosen at random, add new cases as needed + for i in [ + SINGLE_BYTE_MAX as u32 + 1, + 300, + 500, + 700, + 888, + 1234, + u16::MAX as u32, + ] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes()); + } + + // these values should encode in 5 bytes (leading byte + 4 bytes) + // Values chosen at random, add new cases as needed + for i in [u16::MAX as u32 + 1, 100_000, 1_000_000, u32::MAX] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &i.to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u32(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &i.to_le_bytes()); + } +} + +#[test] +fn test_encode_u64() { + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + + // these should all encode to a single byte + for i in 0u64..=SINGLE_BYTE_MAX as u64 { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u64, i); + + // Assert endianness doesn't matter + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u64, i); + } + + // these values should encode in 3 bytes (leading byte + 2 bytes) + // Values chosen at random, add new cases as needed + for i in [ + SINGLE_BYTE_MAX as u64 + 1, + 300, + 500, + 700, + 888, + 1234, + u16::MAX as u64, + ] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes()); + } + + // these values should encode in 5 bytes (leading byte + 4 bytes) + // Values chosen at random, add new cases as needed + for i in [u16::MAX as u64 + 1, 100_000, 1_000_000, u32::MAX as u64] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &(i as u32).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &(i as u32).to_le_bytes()); + } + + // these values should encode in 9 bytes (leading byte + 8 bytes) + // Values chosen at random, add new cases as needed + for i in [u32::MAX as u64 + 1, 500_0000_000, u64::MAX] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 9); + assert_eq!(buffer[0], U64_BYTE); + assert_eq!(&buffer[1..9], &i.to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u64(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 9); + assert_eq!(buffer[0], U64_BYTE); + assert_eq!(&buffer[1..9], &i.to_le_bytes()); + } +} + +#[test] +fn test_encode_u128() { + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + + // these should all encode to a single byte + for i in 0u128..=SINGLE_BYTE_MAX as u128 { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u128, i); + + // Assert endianness doesn't matter + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 1); + assert_eq!(buffer[0] as u128, i); + } + + // these values should encode in 3 bytes (leading byte + 2 bytes) + // Values chosen at random, add new cases as needed + for i in [ + SINGLE_BYTE_MAX as u128 + 1, + 300, + 500, + 700, + 888, + 1234, + u16::MAX as u128, + ] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 3); + assert_eq!(buffer[0], U16_BYTE); + assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes()); + } + + // these values should encode in 5 bytes (leading byte + 4 bytes) + // Values chosen at random, add new cases as needed + for i in [u16::MAX as u128 + 1, 100_000, 1_000_000, u32::MAX as u128] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &(i as u32).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 5); + assert_eq!(buffer[0], U32_BYTE); + assert_eq!(&buffer[1..5], &(i as u32).to_le_bytes()); + } + + // these values should encode in 9 bytes (leading byte + 8 bytes) + // Values chosen at random, add new cases as needed + for i in [u32::MAX as u128 + 1, 500_0000_000, u64::MAX as u128] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 9); + assert_eq!(buffer[0], U64_BYTE); + assert_eq!(&buffer[1..9], &(i as u64).to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 9); + assert_eq!(buffer[0], U64_BYTE); + assert_eq!(&buffer[1..9], &(i as u64).to_le_bytes()); + } + + // these values should encode in 17 bytes (leading byte + 16 bytes) + // Values chosen at random, add new cases as needed + for i in [u64::MAX as u128 + 1, u128::MAX] { + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Big, i).unwrap(); + assert_eq!(writer.bytes_written(), 17); + assert_eq!(buffer[0], U128_BYTE); + assert_eq!(&buffer[1..17], &i.to_be_bytes()); + + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_u128(&mut writer, Endian::Little, i).unwrap(); + assert_eq!(writer.bytes_written(), 17); + assert_eq!(buffer[0], U128_BYTE); + assert_eq!(&buffer[1..17], &i.to_le_bytes()); + } +} diff --git a/tests/derive.rs b/tests/derive.rs index 35a5e8b..4aa0156 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -14,6 +14,6 @@ fn test_encodable() { }; let mut slice = [0u8; 1024]; let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); - assert_eq!(bytes_written, 9); - assert_eq!(&slice[..bytes_written], &[5, 0, 0, 0, 10, 0, 0, 0, 20]); + assert_eq!(bytes_written, 3); + assert_eq!(&slice[..bytes_written], &[10, 10, 20]); }