Turned Config::INT_ENCODING back into a const, made a ton of varint_encode functions

This commit is contained in:
Victor Koenders 2021-09-19 09:25:47 +02:00
parent 7448b7bb87
commit 723bdd312a
9 changed files with 611 additions and 149 deletions

View File

@ -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

View File

@ -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<T: InternalConfig> 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<u64> = 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<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
type IntEncoding = C::IntEncoding;
}
}

View File

@ -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<W: Writer, C: Config> {
@ -27,23 +30,63 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder<W, C> {
}
fn encode_u16(&mut self, val: u16) -> Result<(), Error> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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<W, C> {
}
fn encode_i16(&mut self, val: i16) -> Result<(), Error> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {
<C::IntEncoding as IntEncoding>::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> {

View File

@ -1,120 +0,0 @@
use crate::{config::Endian, enc::write::Writer, error::Error};
pub trait IntEncoding {
fn int_encode_u16<W: Writer>(writer: &mut W, endian: Endian, val: u16) -> Result<(), Error>;
fn int_encode_u32<W: Writer>(writer: &mut W, endian: Endian, val: u32) -> Result<(), Error>;
fn int_encode_u64<W: Writer>(writer: &mut W, endian: Endian, val: u64) -> Result<(), Error>;
fn int_encode_u128<W: Writer>(writer: &mut W, endian: Endian, val: u128) -> Result<(), Error>;
fn int_encode_usize<W: Writer>(writer: &mut W, endian: Endian, val: usize)
-> Result<(), Error>;
fn int_encode_i16<W: Writer>(writer: &mut W, endian: Endian, val: i16) -> Result<(), Error>;
fn int_encode_i32<W: Writer>(writer: &mut W, endian: Endian, val: i32) -> Result<(), Error>;
fn int_encode_i64<W: Writer>(writer: &mut W, endian: Endian, val: i64) -> Result<(), Error>;
fn int_encode_i128<W: Writer>(writer: &mut W, endian: Endian, val: i128) -> Result<(), Error>;
fn int_encode_isize<W: Writer>(writer: &mut W, endian: Endian, val: isize)
-> Result<(), Error>;
fn int_encode_f32<W: Writer>(writer: &mut W, endian: Endian, val: f32) -> Result<(), Error>;
fn int_encode_f64<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(
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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(
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<W: Writer>(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<W: Writer>(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()),
}
}
}

View File

@ -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<E: enc::Encodeable>(
val: E,

View File

@ -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;

View File

@ -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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(
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<W: Writer>(
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
}

View File

@ -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<W: Writer>(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<W: Writer>(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<W: Writer>(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<W: Writer>(
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<W: Writer>(
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());
}
}

View File

@ -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]);
}