From ffb565c4058aa45d65907670b34cd4227193c262 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Wed, 22 Sep 2021 10:40:27 +0200 Subject: [PATCH] Added config options for endian and int_encoding, added full coverage for all basic integer types --- src/config.rs | 93 ++++++++++++++++++++++++++++++++----- src/de/decoder.rs | 2 +- src/de/impls.rs | 18 +++++++ src/lib.rs | 20 +++++++- src/varint/decode_signed.rs | 58 +++++++++++++++++++++-- tests/test.rs | 54 +++++++++++++++++++-- 6 files changed, 221 insertions(+), 24 deletions(-) diff --git a/src/config.rs b/src/config.rs index 751146b..e768ed0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,19 +1,87 @@ pub(crate) use self::internal::*; +use std::marker::PhantomData; -pub trait Config: InternalConfig + Sized {} - -pub struct Default; - -impl InternalConfig for Default {} +pub trait Config: InternalConfig + Copy + Clone + Sized { + fn with_big_endian(self) -> BigEndian { + BigEndian { _pd: PhantomData } + } + fn with_little_endian(self) -> LittleEndian { + LittleEndian { _pd: PhantomData } + } + fn with_variable_int_encoding(self) -> Varint { + Varint { _pd: PhantomData } + } + fn with_fixed_int_encoding(self) -> Fixint { + Fixint { _pd: PhantomData } + } +} impl Config for T {} +#[derive(Copy, Clone)] +pub struct Default; + +impl InternalConfig for Default { + const ENDIAN: Endian = Endian::Little; + const INT_ENCODING: IntEncoding = IntEncoding::Variable; + const LIMIT: Option = None; + const ALLOW_TRAILING: bool = true; +} + +#[derive(Copy, Clone)] +pub struct BigEndian { + _pd: PhantomData, +} + +impl InternalConfig for BigEndian { + const ENDIAN: Endian = Endian::Big; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +} + +#[derive(Copy, Clone)] +pub struct LittleEndian { + _pd: PhantomData, +} + +impl InternalConfig for LittleEndian { + const ENDIAN: Endian = Endian::Little; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +} + +#[derive(Copy, Clone)] +pub struct Fixint { + _pd: PhantomData, +} + +impl InternalConfig for Fixint { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = IntEncoding::Fixed; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +} + +#[derive(Copy, Clone)] +pub struct Varint { + _pd: PhantomData, +} + +impl InternalConfig for Varint { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = IntEncoding::Variable; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +} + mod internal { - pub trait InternalConfig { - const ENDIAN: Endian = Endian::Little; - const INT_ENCODING: IntEncoding = IntEncoding::Variable; - const LIMIT: Option = None; - const ALLOW_TRAILING: bool = true; + pub trait InternalConfig: Copy + Clone { + const ENDIAN: Endian; + const INT_ENCODING: IntEncoding; + const LIMIT: Option; + const ALLOW_TRAILING: bool; } #[derive(PartialEq, Eq)] @@ -28,7 +96,10 @@ mod internal { Variable, } - impl<'a, C: InternalConfig> InternalConfig for &'a mut C { + impl<'a, C: InternalConfig> InternalConfig for &'a mut C + where + &'a mut C: Copy + Clone, + { const ENDIAN: Endian = C::ENDIAN; const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; diff --git a/src/de/decoder.rs b/src/de/decoder.rs index f94592c..7d04156 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -11,7 +11,7 @@ pub struct Decoder { } impl<'de, R: Reader<'de>, C: Config> Decoder { - pub fn new(reader: R) -> Decoder { + pub fn new(reader: R, _config: C) -> Decoder { Decoder { reader, config: PhantomData, diff --git a/src/de/impls.rs b/src/de/impls.rs index 4360cfd..ce5a08c 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -73,6 +73,24 @@ impl Decodable for isize { } } +impl Decodable for f32 { + fn decode(mut decoder: D) -> Result { + decoder.decode_f32() + } +} + +impl Decodable for f64 { + fn decode(mut decoder: D) -> Result { + decoder.decode_f64() + } +} + +impl Decodable for [u8; N] { + fn decode(mut decoder: D) -> Result { + decoder.decode_array() + } +} + impl<'a, T> Decode for &'a mut T where T: Decode, diff --git a/src/lib.rs b/src/lib.rs index 522f73c..38c0f95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,21 +21,37 @@ pub mod enc; pub mod error; pub use bincode_derive::{Decodable, Encodable}; +use config::Config; pub(crate) mod varint; pub fn encode_into_slice( val: E, dst: &mut [u8], +) -> Result { + encode_into_slice_with_config(val, dst, config::Default) +} + +pub fn encode_into_slice_with_config( + val: E, + dst: &mut [u8], + _config: C, ) -> Result { let writer = enc::write::SliceWriter::new(dst); - let mut encoder = enc::Encoder::<_, config::Default>::new(writer); + let mut encoder = enc::Encoder::<_, C>::new(writer); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written()) } pub fn decode(src: &mut [u8]) -> Result { + decode_with_config(src, config::Default) +} + +pub fn decode_with_config( + src: &mut [u8], + _config: C, +) -> Result { let reader = de::read::SliceReader::new(src); - let mut decoder = de::Decoder::<_, config::Default>::new(reader); + let mut decoder = de::Decoder::<_, C>::new(reader, _config); D::decode(&mut decoder) } diff --git a/src/varint/decode_signed.rs b/src/varint/decode_signed.rs index cc14951..1eae254 100644 --- a/src/varint/decode_signed.rs +++ b/src/varint/decode_signed.rs @@ -7,7 +7,19 @@ pub fn varint_decode_i16<'a, R: Reader<'a>>( read: &mut R, endian: Endian, ) -> Result { - unimplemented!() + let n = super::varint_decode_u16(read, endian)?; + Ok(if n % 2 == 0 { + // positive number + (n / 2) as _ + } else { + // negative number + // !m * 2 + 1 = n + // !m * 2 = n - 1 + // !m = (n - 1) / 2 + // m = !((n - 1) / 2) + // since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2) + !(n / 2) as _ + }) } #[allow(dead_code)] @@ -15,7 +27,19 @@ pub fn varint_decode_i32<'a, R: Reader<'a>>( read: &mut R, endian: Endian, ) -> Result { - unimplemented!() + let n = super::varint_decode_u32(read, endian)?; + Ok(if n % 2 == 0 { + // positive number + (n / 2) as _ + } else { + // negative number + // !m * 2 + 1 = n + // !m * 2 = n - 1 + // !m = (n - 1) / 2 + // m = !((n - 1) / 2) + // since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2) + !(n / 2) as _ + }) } #[allow(dead_code)] @@ -23,7 +47,19 @@ pub fn varint_decode_i64<'a, R: Reader<'a>>( read: &mut R, endian: Endian, ) -> Result { - unimplemented!() + let n = super::varint_decode_u64(read, endian)?; + Ok(if n % 2 == 0 { + // positive number + (n / 2) as _ + } else { + // negative number + // !m * 2 + 1 = n + // !m * 2 = n - 1 + // !m = (n - 1) / 2 + // m = !((n - 1) / 2) + // since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2) + !(n / 2) as _ + }) } #[allow(dead_code)] @@ -31,7 +67,19 @@ pub fn varint_decode_i128<'a, R: Reader<'a>>( read: &mut R, endian: Endian, ) -> Result { - unimplemented!() + let n = super::varint_decode_u128(read, endian)?; + Ok(if n % 2 == 0 { + // positive number + (n / 2) as _ + } else { + // negative number + // !m * 2 + 1 = n + // !m * 2 = n - 1 + // !m = (n - 1) / 2 + // m = !((n - 1) / 2) + // since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2) + !(n / 2) as _ + }) } #[allow(dead_code)] @@ -39,5 +87,5 @@ pub fn varint_decode_isize<'a, R: Reader<'a>>( read: &mut R, endian: Endian, ) -> Result { - unimplemented!() + varint_decode_i64(read, endian).map(|v| v as isize) } diff --git a/tests/test.rs b/tests/test.rs index db65476..2664ec1 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,19 +1,63 @@ extern crate bincode; +use bincode::config::{self, Config}; use core::fmt::Debug; +fn the_same_with_config(element: V, config: C) +where + V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + C: Config, +{ + let mut buffer = [0u8; 32]; + bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); + + assert_eq!(element, decoded); +} fn the_same(element: V) where V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, { - let mut buffer = [0u8; 32]; - bincode::encode_into_slice(element.clone(), &mut buffer).unwrap(); - let decoded: V = bincode::decode(&mut buffer).unwrap(); - - assert_eq!(element, decoded); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_fixed_int_encoding(), + ); + the_same_with_config( + element.clone(), + config::Default.with_big_endian().with_fixed_int_encoding(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_variable_int_encoding(), + ); + the_same_with_config( + element, + config::Default + .with_big_endian() + .with_variable_int_encoding(), + ); } #[test] fn test_numbers() { + the_same(5u8); + the_same(5u16); the_same(5u32); + the_same(5u64); + the_same(5u128); + the_same(5usize); + + the_same(5i8); + the_same(5i16); + the_same(5i32); + the_same(5i64); + the_same(5i128); + the_same(5isize); + + the_same(5.0f32); + the_same(5.0f64); }