Added config options for endian and int_encoding, added full coverage for all basic integer types

This commit is contained in:
Victor Koenders 2021-09-22 10:40:27 +02:00
parent 78cb27f782
commit ffb565c405
6 changed files with 221 additions and 24 deletions

View File

@ -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<Self> {
BigEndian { _pd: PhantomData }
}
fn with_little_endian(self) -> LittleEndian<Self> {
LittleEndian { _pd: PhantomData }
}
fn with_variable_int_encoding(self) -> Varint<Self> {
Varint { _pd: PhantomData }
}
fn with_fixed_int_encoding(self) -> Fixint<Self> {
Fixint { _pd: PhantomData }
}
}
impl<T: InternalConfig> 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<u64> = None;
const ALLOW_TRAILING: bool = true;
}
#[derive(Copy, Clone)]
pub struct BigEndian<C: Config> {
_pd: PhantomData<C>,
}
impl<C: InternalConfig> InternalConfig for BigEndian<C> {
const ENDIAN: Endian = Endian::Big;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
}
#[derive(Copy, Clone)]
pub struct LittleEndian<C: Config> {
_pd: PhantomData<C>,
}
impl<C: InternalConfig> InternalConfig for LittleEndian<C> {
const ENDIAN: Endian = Endian::Little;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
}
#[derive(Copy, Clone)]
pub struct Fixint<C: Config> {
_pd: PhantomData<C>,
}
impl<C: InternalConfig> InternalConfig for Fixint<C> {
const ENDIAN: Endian = C::ENDIAN;
const INT_ENCODING: IntEncoding = IntEncoding::Fixed;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
}
#[derive(Copy, Clone)]
pub struct Varint<C: Config> {
_pd: PhantomData<C>,
}
impl<C: InternalConfig> InternalConfig for Varint<C> {
const ENDIAN: Endian = C::ENDIAN;
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
const LIMIT: Option<u64> = 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<u64> = None;
const ALLOW_TRAILING: bool = true;
pub trait InternalConfig: Copy + Clone {
const ENDIAN: Endian;
const INT_ENCODING: IntEncoding;
const LIMIT: Option<u64>;
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<u64> = C::LIMIT;

View File

@ -11,7 +11,7 @@ pub struct Decoder<R, C: Config> {
}
impl<'de, R: Reader<'de>, C: Config> Decoder<R, C> {
pub fn new(reader: R) -> Decoder<R, C> {
pub fn new(reader: R, _config: C) -> Decoder<R, C> {
Decoder {
reader,
config: PhantomData,

View File

@ -73,6 +73,24 @@ impl Decodable for isize {
}
}
impl Decodable for f32 {
fn decode<D: Decode>(mut decoder: D) -> Result<Self, DecodeError> {
decoder.decode_f32()
}
}
impl Decodable for f64 {
fn decode<D: Decode>(mut decoder: D) -> Result<Self, DecodeError> {
decoder.decode_f64()
}
}
impl<const N: usize> Decodable for [u8; N] {
fn decode<D: Decode>(mut decoder: D) -> Result<Self, DecodeError> {
decoder.decode_array()
}
}
impl<'a, T> Decode for &'a mut T
where
T: Decode,

View File

@ -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<E: enc::Encodeable>(
val: E,
dst: &mut [u8],
) -> Result<usize, error::EncodeError> {
encode_into_slice_with_config(val, dst, config::Default)
}
pub fn encode_into_slice_with_config<E: enc::Encodeable, C: Config>(
val: E,
dst: &mut [u8],
_config: C,
) -> Result<usize, error::EncodeError> {
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<D: de::Decodable>(src: &mut [u8]) -> Result<D, error::DecodeError> {
decode_with_config(src, config::Default)
}
pub fn decode_with_config<D: de::Decodable, C: Config>(
src: &mut [u8],
_config: C,
) -> Result<D, error::DecodeError> {
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)
}

View File

@ -7,7 +7,19 @@ pub fn varint_decode_i16<'a, R: Reader<'a>>(
read: &mut R,
endian: Endian,
) -> Result<i16, DecodeError> {
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<i32, DecodeError> {
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<i64, DecodeError> {
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<i128, DecodeError> {
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<isize, DecodeError> {
unimplemented!()
varint_decode_i64(read, endian).map(|v| v as isize)
}

View File

@ -1,19 +1,63 @@
extern crate bincode;
use bincode::config::{self, Config};
use core::fmt::Debug;
fn the_same_with_config<V, C>(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<V>(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);
}