From e160c73acbcb6a1cc39915acb0cd3e9aaa089e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Sat, 19 Jun 2021 19:31:34 +0200 Subject: [PATCH 01/80] a fresh new start --- Cargo.toml | 15 +- examples/basic.rs | 27 -- src/config.rs | 37 ++ src/config/endian.rs | 29 -- src/config/int.rs | 718 -------------------------------- src/config/limit.rs | 49 --- src/config/mod.rs | 405 ------------------- src/config/trailing.rs | 37 -- src/de.rs | 96 +++++ src/de/mod.rs | 514 ----------------------- src/de/read.rs | 201 --------- src/error.rs | 98 +---- src/int_encoding.rs | 8 + src/internal.rs | 123 ------ src/lib.rs | 128 +----- src/ser.rs | 77 ++++ src/ser/mod.rs | 770 ----------------------------------- tests/test.rs | 898 +---------------------------------------- 18 files changed, 248 insertions(+), 3982 deletions(-) delete mode 100644 examples/basic.rs create mode 100644 src/config.rs delete mode 100644 src/config/endian.rs delete mode 100644 src/config/int.rs delete mode 100644 src/config/limit.rs delete mode 100644 src/config/mod.rs delete mode 100644 src/config/trailing.rs create mode 100644 src/de.rs delete mode 100644 src/de/mod.rs delete mode 100644 src/de/read.rs create mode 100644 src/int_encoding.rs delete mode 100644 src/internal.rs create mode 100644 src/ser.rs delete mode 100644 src/ser/mod.rs diff --git a/Cargo.toml b/Cargo.toml index f92aa65..8d21054 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bincode" version = "2.0.0-dev" # remember to update html_root_url -authors = ["Ty Overby ", "Francesco Mazzoli ", "David Tolnay ", "Zoey Riordan "] -exclude = ["logo.png", "examples/*", ".gitignore", ".travis.yml"] +authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan "] +exclude = ["logo.png", "examples/*", ".gitignore", ".github/"] publish = true @@ -13,13 +13,6 @@ categories = ["encoding", "network-programming"] keywords = ["binary", "encode", "decode", "serialize", "deserialize"] license = "MIT" -description = "A binary serialization / deserialization strategy that uses Serde for transforming structs into bytes and vice versa!" +description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!" -edition = "2018" -[dependencies] -byteorder = "1.3.0" -serde = "1.0.63" - -[dev-dependencies] -serde_bytes = "0.11" -serde_derive = "1.0.27" +edition = "2018" \ No newline at end of file diff --git a/examples/basic.rs b/examples/basic.rs deleted file mode 100644 index 4b46307..0000000 --- a/examples/basic.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[macro_use] -extern crate serde_derive; -extern crate bincode; - -use bincode::{deserialize, serialize}; - -#[derive(Serialize, Deserialize, PartialEq, Debug)] -struct Entity { - x: f32, - y: f32, -} - -#[derive(Serialize, Deserialize, PartialEq, Debug)] -struct World(Vec); - -fn main() { - let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]); - - let encoded: Vec = serialize(&world).unwrap(); - - // 8 bytes for the length of the vector (usize), 4 bytes per float. - assert_eq!(encoded.len(), 8 + 4 * 4); - - let decoded: World = deserialize(&encoded[..]).unwrap(); - - assert_eq!(world, decoded); -} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..751146b --- /dev/null +++ b/src/config.rs @@ -0,0 +1,37 @@ +pub(crate) use self::internal::*; + +pub trait Config: InternalConfig + Sized {} + +pub struct Default; + +impl InternalConfig for Default {} + +impl Config for T {} + +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; + } + + #[derive(PartialEq, Eq)] + pub enum Endian { + Little, + 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; + } +} diff --git a/src/config/endian.rs b/src/config/endian.rs deleted file mode 100644 index 4d924bf..0000000 --- a/src/config/endian.rs +++ /dev/null @@ -1,29 +0,0 @@ -use byteorder::{self, ByteOrder}; - -pub trait BincodeByteOrder { - type Endian: ByteOrder + 'static; -} - -/// Little-endian byte ordering. -#[derive(Copy, Clone)] -pub struct LittleEndian; - -/// Big-endian byte ordering. -#[derive(Copy, Clone)] -pub struct BigEndian; - -/// The native byte ordering of the current system. -#[derive(Copy, Clone)] -pub struct NativeEndian; - -impl BincodeByteOrder for LittleEndian { - type Endian = byteorder::LittleEndian; -} - -impl BincodeByteOrder for BigEndian { - type Endian = byteorder::BigEndian; -} - -impl BincodeByteOrder for NativeEndian { - type Endian = byteorder::NativeEndian; -} diff --git a/src/config/int.rs b/src/config/int.rs deleted file mode 100644 index 729881c..0000000 --- a/src/config/int.rs +++ /dev/null @@ -1,718 +0,0 @@ -use std::io::Write; -use std::mem::size_of; - -use super::Options; -use crate::de::read::BincodeRead; -use crate::error::{ErrorKind, Result}; - -pub trait IntEncoding { - /// Gets the size (in bytes) that a value would be serialized to. - fn u16_size(n: u16) -> u64; - /// Gets the size (in bytes) that a value would be serialized to. - fn u32_size(n: u32) -> u64; - /// Gets the size (in bytes) that a value would be serialized to. - fn u64_size(n: u64) -> u64; - - /// Gets the size (in bytes) that a value would be serialized to. - fn i16_size(n: i16) -> u64; - /// Gets the size (in bytes) that a value would be serialized to. - fn i32_size(n: i32) -> u64; - /// Gets the size (in bytes) that a value would be serialized to. - fn i64_size(n: i64) -> u64; - - #[inline(always)] - fn len_size(len: usize) -> u64 { - Self::u64_size(len as u64) - } - - /// Serializes a sequence length. - #[inline(always)] - fn serialize_len( - ser: &mut crate::ser::Serializer, - len: usize, - ) -> Result<()> { - Self::serialize_u64(ser, len as u64) - } - - fn serialize_u16( - ser: &mut crate::ser::Serializer, - val: u16, - ) -> Result<()>; - - fn serialize_u32( - ser: &mut crate::ser::Serializer, - val: u32, - ) -> Result<()>; - - fn serialize_u64( - ser: &mut crate::ser::Serializer, - val: u64, - ) -> Result<()>; - - fn serialize_i16( - ser: &mut crate::ser::Serializer, - val: i16, - ) -> Result<()>; - - fn serialize_i32( - ser: &mut crate::ser::Serializer, - val: i32, - ) -> Result<()>; - - fn serialize_i64( - ser: &mut crate::ser::Serializer, - val: i64, - ) -> Result<()>; - - /// Deserializes a sequence length. - #[inline(always)] - fn deserialize_len<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result { - Self::deserialize_u64(de).and_then(cast_u64_to_usize) - } - - fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result; - - serde_if_integer128! { - fn u128_size(v: u128) -> u64; - fn i128_size(v: i128) -> u64; - fn serialize_u128( - ser: &mut crate::Serializer, - val: u128, - ) -> Result<()>; - fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result; - fn serialize_i128( - ser: &mut crate::Serializer, - val: i128, - ) -> Result<()>; - fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result; - } -} - -/// Fixed-size integer encoding. -/// -/// * Fixed size integers are encoded directly -/// * Enum discriminants are encoded as u32 -/// * Lengths and usize are encoded as u64 -#[derive(Copy, Clone)] -pub struct FixintEncoding; - -/// Variable-size integer encoding (excepting [ui]8). -/// -/// Encoding an unsigned integer v (of any type excepting u8) works as follows: -/// -/// 1. If `u < 251`, encode it as a single byte with that value. -/// 2. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`. -/// 3. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`. -/// 4. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`. -/// 5. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a -/// u128 with value `u`. -/// -/// Then, for signed integers, we first convert to unsigned using the zigzag algorithm, -/// and then encode them as we do for unsigned integers generally. The reason we use this -/// algorithm is that it encodes those values which are close to zero in less bytes; the -/// obvious algorithm, where we encode the cast values, gives a very large encoding for all -/// negative values. -/// -/// The zigzag algorithm is defined as follows: -/// -/// ```ignore -/// fn zigzag(v: Signed) -> Unsigned { -/// match v { -/// 0 => 0, -/// v if v < 0 => |v| * 2 - 1 -/// v if v > 0 => v * 2 -/// } -/// } -/// ``` -/// -/// And works such that: -/// -/// ```ignore -/// assert_eq!(zigzag(0), 0); -/// assert_eq!(zigzag(-1), 1); -/// assert_eq!(zigzag(1), 2); -/// assert_eq!(zigzag(-2), 3); -/// assert_eq!(zigzag(2), 4); -/// assert_eq!(zigzag(i64::min_value()), u64::max_value()); -/// ``` -/// -/// Note that u256 and the like are unsupported by this format; if and when they are added to the -/// language, they may be supported via the extension point given by the 255 byte. -#[derive(Copy, Clone)] -pub struct VarintEncoding; - -const SINGLE_BYTE_MAX: u8 = 250; -const U16_BYTE: u8 = 251; -const U32_BYTE: u8 = 252; -const U64_BYTE: u8 = 253; -const U128_BYTE: u8 = 254; -const DESERIALIZE_EXTENSION_POINT_ERR: &str = r#" -Byte 255 is treated as an extension point; it should not be encoding anything. -Do you have a mismatched bincode version or configuration? -"#; - -impl VarintEncoding { - fn varint_size(n: u64) -> u64 { - if n <= SINGLE_BYTE_MAX as u64 { - 1 - } else if n <= u16::max_value() as u64 { - (1 + size_of::()) as u64 - } else if n <= u32::max_value() as u64 { - (1 + size_of::()) as u64 - } else { - (1 + size_of::()) as u64 - } - } - - #[inline(always)] - fn zigzag_encode(n: i64) -> u64 { - if n < 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 - !(n as u64) * 2 + 1 - } else { - (n as u64) * 2 - } - } - - #[inline(always)] - fn zigzag_decode(n: u64) -> i64 { - if n % 2 == 0 { - // positive number - (n / 2) as i64 - } 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 i64 - } - } - - fn serialize_varint( - ser: &mut crate::ser::Serializer, - n: u64, - ) -> Result<()> { - if n <= SINGLE_BYTE_MAX as u64 { - ser.serialize_byte(n as u8) - } else if n <= u16::max_value() as u64 { - ser.serialize_byte(U16_BYTE)?; - ser.serialize_literal_u16(n as u16) - } else if n <= u32::max_value() as u64 { - ser.serialize_byte(U32_BYTE)?; - ser.serialize_literal_u32(n as u32) - } else { - ser.serialize_byte(U64_BYTE)?; - ser.serialize_literal_u64(n as u64) - } - } - - fn deserialize_varint<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result { - #[allow(ellipsis_inclusive_range_patterns)] - match de.deserialize_byte()? { - byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u64), - U16_BYTE => Ok(de.deserialize_literal_u16()? as u64), - U32_BYTE => Ok(de.deserialize_literal_u32()? as u64), - U64_BYTE => de.deserialize_literal_u64(), - U128_BYTE => Err(Box::new(ErrorKind::Custom( - "Invalid value (u128 range): you may have a version or configuration disagreement?" - .to_string(), - ))), - _ => Err(Box::new(ErrorKind::Custom( - DESERIALIZE_EXTENSION_POINT_ERR.to_string(), - ))), - } - } - - serde_if_integer128! { - // see zigzag_encode and zigzag_decode for implementation comments - #[inline(always)] - fn zigzag128_encode(n: i128) -> u128 { - if n < 0 { - !(n as u128) * 2 + 1 - } else { - (n as u128) * 2 - } - } - #[inline(always)] - fn zigzag128_decode(n: u128) -> i128 { - if n % 2 == 0 { - (n / 2) as i128 - } else { - !(n / 2) as i128 - } - } - - fn varint128_size(n: u128) -> u64 { - if n <= SINGLE_BYTE_MAX as u128 { - 1 - } else if n <= u16::max_value() as u128 { - (1 + size_of::()) as u64 - } else if n <= u32::max_value() as u128 { - (1 + size_of::()) as u64 - } else if n <= u64::max_value() as u128 { - (1 + size_of::()) as u64 - } else { - (1 + size_of::()) as u64 - } - } - - fn serialize_varint128( - ser: &mut crate::ser::Serializer, - n: u128, - ) -> Result<()> { - if n <= SINGLE_BYTE_MAX as u128 { - ser.serialize_byte(n as u8) - } else if n <= u16::max_value() as u128 { - ser.serialize_byte(U16_BYTE)?; - ser.serialize_literal_u16(n as u16) - } else if n <= u32::max_value() as u128 { - ser.serialize_byte(U32_BYTE)?; - ser.serialize_literal_u32(n as u32) - } else if n <= u64::max_value() as u128 { - ser.serialize_byte(U64_BYTE)?; - ser.serialize_literal_u64(n as u64) - } else { - ser.serialize_byte(U128_BYTE)?; - ser.serialize_literal_u128(n) - } - } - - fn deserialize_varint128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::de::Deserializer, - ) -> Result { - #[allow(ellipsis_inclusive_range_patterns)] - match de.deserialize_byte()? { - byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u128), - U16_BYTE => Ok(de.deserialize_literal_u16()? as u128), - U32_BYTE => Ok(de.deserialize_literal_u32()? as u128), - U64_BYTE => Ok(de.deserialize_literal_u64()? as u128), - U128_BYTE => de.deserialize_literal_u128(), - _ => Err(Box::new(ErrorKind::Custom(DESERIALIZE_EXTENSION_POINT_ERR.to_string()))), - } - } - } -} - -impl IntEncoding for FixintEncoding { - #[inline(always)] - fn u16_size(_: u16) -> u64 { - size_of::() as u64 - } - #[inline(always)] - fn u32_size(_: u32) -> u64 { - size_of::() as u64 - } - #[inline(always)] - fn u64_size(_: u64) -> u64 { - size_of::() as u64 - } - - #[inline(always)] - fn i16_size(_: i16) -> u64 { - size_of::() as u64 - } - #[inline(always)] - fn i32_size(_: i32) -> u64 { - size_of::() as u64 - } - #[inline(always)] - fn i64_size(_: i64) -> u64 { - size_of::() as u64 - } - - #[inline(always)] - fn serialize_u16( - ser: &mut crate::Serializer, - val: u16, - ) -> Result<()> { - ser.serialize_literal_u16(val) - } - #[inline(always)] - fn serialize_u32( - ser: &mut crate::Serializer, - val: u32, - ) -> Result<()> { - ser.serialize_literal_u32(val) - } - #[inline(always)] - fn serialize_u64( - ser: &mut crate::Serializer, - val: u64, - ) -> Result<()> { - ser.serialize_literal_u64(val) - } - - #[inline(always)] - fn serialize_i16( - ser: &mut crate::Serializer, - val: i16, - ) -> Result<()> { - ser.serialize_literal_u16(val as u16) - } - #[inline(always)] - fn serialize_i32( - ser: &mut crate::Serializer, - val: i32, - ) -> Result<()> { - ser.serialize_literal_u32(val as u32) - } - #[inline(always)] - fn serialize_i64( - ser: &mut crate::Serializer, - val: i64, - ) -> Result<()> { - ser.serialize_literal_u64(val as u64) - } - - #[inline(always)] - fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - de.deserialize_literal_u16() - } - #[inline(always)] - fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - de.deserialize_literal_u32() - } - #[inline(always)] - fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - de.deserialize_literal_u64() - } - - #[inline(always)] - fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Ok(de.deserialize_literal_u16()? as i16) - } - #[inline(always)] - fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Ok(de.deserialize_literal_u32()? as i32) - } - #[inline(always)] - fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Ok(de.deserialize_literal_u64()? as i64) - } - - serde_if_integer128! { - #[inline(always)] - fn u128_size(_: u128) -> u64{ - size_of::() as u64 - } - #[inline(always)] - fn i128_size(_: i128) -> u64{ - size_of::() as u64 - } - - #[inline(always)] - fn serialize_u128( - ser: &mut crate::Serializer, - val: u128, - ) -> Result<()> { - ser.serialize_literal_u128(val) - } - #[inline(always)] - fn serialize_i128( - ser: &mut crate::Serializer, - val: i128, - ) -> Result<()> { - ser.serialize_literal_u128(val as u128) - } - #[inline(always)] - fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - de.deserialize_literal_u128() - } - #[inline(always)] - fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Ok(de.deserialize_literal_u128()? as i128) - } - } -} - -impl IntEncoding for VarintEncoding { - #[inline(always)] - fn u16_size(n: u16) -> u64 { - Self::varint_size(n as u64) - } - #[inline(always)] - fn u32_size(n: u32) -> u64 { - Self::varint_size(n as u64) - } - #[inline(always)] - fn u64_size(n: u64) -> u64 { - Self::varint_size(n) - } - - #[inline(always)] - fn i16_size(n: i16) -> u64 { - Self::varint_size(Self::zigzag_encode(n as i64)) - } - #[inline(always)] - fn i32_size(n: i32) -> u64 { - Self::varint_size(Self::zigzag_encode(n as i64)) - } - #[inline(always)] - fn i64_size(n: i64) -> u64 { - Self::varint_size(Self::zigzag_encode(n)) - } - - #[inline(always)] - fn serialize_u16( - ser: &mut crate::Serializer, - val: u16, - ) -> Result<()> { - Self::serialize_varint(ser, val as u64) - } - #[inline(always)] - fn serialize_u32( - ser: &mut crate::Serializer, - val: u32, - ) -> Result<()> { - Self::serialize_varint(ser, val as u64) - } - #[inline(always)] - fn serialize_u64( - ser: &mut crate::Serializer, - val: u64, - ) -> Result<()> { - Self::serialize_varint(ser, val) - } - - #[inline(always)] - fn serialize_i16( - ser: &mut crate::Serializer, - val: i16, - ) -> Result<()> { - Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) - } - #[inline(always)] - fn serialize_i32( - ser: &mut crate::Serializer, - val: i32, - ) -> Result<()> { - Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) - } - #[inline(always)] - fn serialize_i64( - ser: &mut crate::Serializer, - val: i64, - ) -> Result<()> { - Self::serialize_varint(ser, Self::zigzag_encode(val)) - } - - #[inline(always)] - fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de).and_then(cast_u64_to_u16) - } - #[inline(always)] - fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de).and_then(cast_u64_to_u32) - } - #[inline(always)] - fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de) - } - - #[inline(always)] - fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de) - .map(Self::zigzag_decode) - .and_then(cast_i64_to_i16) - } - #[inline(always)] - fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de) - .map(Self::zigzag_decode) - .and_then(cast_i64_to_i32) - } - #[inline(always)] - fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint(de).map(Self::zigzag_decode) - } - - serde_if_integer128! { - #[inline(always)] - fn u128_size(n: u128) -> u64 { - Self::varint128_size(n) - } - #[inline(always)] - fn i128_size(n: i128) -> u64 { - Self::varint128_size(Self::zigzag128_encode(n)) - } - #[inline(always)] - fn serialize_u128( - ser: &mut crate::Serializer, - val: u128, - ) -> Result<()> { - Self::serialize_varint128(ser, val) - } - #[inline(always)] - fn serialize_i128( - ser: &mut crate::Serializer, - val: i128, - ) -> Result<()> { - Self::serialize_varint128(ser, Self::zigzag128_encode(val)) - } - #[inline(always)] - fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint128(de) - } - #[inline(always)] - fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( - de: &mut crate::Deserializer, - ) -> Result { - Self::deserialize_varint128(de).map(Self::zigzag128_decode) - } - } -} - -fn cast_u64_to_usize(n: u64) -> Result { - if n <= usize::max_value() as u64 { - Ok(n as usize) - } else { - Err(Box::new(ErrorKind::Custom(format!( - "Invalid size {}: sizes must fit in a usize (0 to {})", - n, - usize::max_value() - )))) - } -} -fn cast_u64_to_u32(n: u64) -> Result { - if n <= u32::max_value() as u64 { - Ok(n as u32) - } else { - Err(Box::new(ErrorKind::Custom(format!( - "Invalid u32 {}: you may have a version disagreement?", - n, - )))) - } -} -fn cast_u64_to_u16(n: u64) -> Result { - if n <= u16::max_value() as u64 { - Ok(n as u16) - } else { - Err(Box::new(ErrorKind::Custom(format!( - "Invalid u16 {}: you may have a version disagreement?", - n, - )))) - } -} - -fn cast_i64_to_i32(n: i64) -> Result { - if n <= i32::max_value() as i64 && n >= i32::min_value() as i64 { - Ok(n as i32) - } else { - Err(Box::new(ErrorKind::Custom(format!( - "Invalid i32 {}: you may have a version disagreement?", - n, - )))) - } -} - -fn cast_i64_to_i16(n: i64) -> Result { - if n <= i16::max_value() as i64 && n >= i16::min_value() as i64 { - Ok(n as i16) - } else { - Err(Box::new(ErrorKind::Custom(format!( - "Invalid i16 {}: you may have a version disagreement?", - n, - )))) - } -} - -#[cfg(test)] -mod test { - use super::VarintEncoding; - - #[test] - fn test_zigzag_encode() { - let zigzag = VarintEncoding::zigzag_encode; - - assert_eq!(zigzag(0), 0); - for x in 1..512 { - assert_eq!(zigzag(x), (x as u64) * 2); - assert_eq!(zigzag(-x), (x as u64) * 2 - 1); - } - } - - #[test] - fn test_zigzag_decode() { - // zigzag' - let zigzagp = VarintEncoding::zigzag_decode; - for x in (0..512).map(|x| x * 2) { - assert_eq!(zigzagp(x), x as i64 / 2); - assert_eq!(zigzagp(x + 1), -(x as i64) / 2 - 1); - } - } - - #[test] - fn test_zigzag_edge_cases() { - let (zigzag, zigzagp) = (VarintEncoding::zigzag_encode, VarintEncoding::zigzag_decode); - - assert_eq!(zigzag(i64::max_value()), u64::max_value() - 1); - assert_eq!(zigzag(i64::min_value()), u64::max_value()); - - assert_eq!(zigzagp(u64::max_value() - 1), i64::max_value()); - assert_eq!(zigzagp(u64::max_value()), i64::min_value()); - } -} diff --git a/src/config/limit.rs b/src/config/limit.rs deleted file mode 100644 index 93ad251..0000000 --- a/src/config/limit.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::error::{ErrorKind, Result}; - -/// A trait for stopping serialization and deserialization when a certain limit has been reached. -pub trait SizeLimit { - /// Tells the SizeLimit that a certain number of bytes has been - /// read or written. Returns Err if the limit has been exceeded. - fn add(&mut self, n: u64) -> Result<()>; - /// Returns the hard limit (if one exists) - fn limit(&self) -> Option; -} - -/// A SizeLimit that restricts serialized or deserialized messages from -/// exceeding a certain byte length. -#[derive(Copy, Clone)] -pub struct Bounded(pub u64); - -/// A SizeLimit without a limit! -/// Use this if you don't care about the size of encoded or decoded messages. -#[derive(Copy, Clone)] -pub struct Infinite; - -impl SizeLimit for Bounded { - #[inline(always)] - fn add(&mut self, n: u64) -> Result<()> { - if self.0 >= n { - self.0 -= n; - Ok(()) - } else { - Err(Box::new(ErrorKind::SizeLimit)) - } - } - - #[inline(always)] - fn limit(&self) -> Option { - Some(self.0) - } -} - -impl SizeLimit for Infinite { - #[inline(always)] - fn add(&mut self, _: u64) -> Result<()> { - Ok(()) - } - - #[inline(always)] - fn limit(&self) -> Option { - None - } -} diff --git a/src/config/mod.rs b/src/config/mod.rs deleted file mode 100644 index e4bc4a5..0000000 --- a/src/config/mod.rs +++ /dev/null @@ -1,405 +0,0 @@ -//! `bincode` uses a Builder-pattern to configure the Serializers and Deserializers in this -//! crate. This means that if you need to customize the behavior of `bincode`, you should create an -//! instance of the `DefaultOptions` struct: -//! -//! ```rust -//! use bincode::Options; -//! let my_options = bincode::DefaultOptions::new(); -//! ``` -//! -//! # Options Struct vs bincode functions -//! -//! Due to historical reasons, the default options used by the `serialize()` and `deserialize()` -//! family of functions are different than the default options created by the `DefaultOptions` struct: -//! -//! | | Byte limit | Endianness | Int Encoding | Trailing Behavior | -//! |----------|------------|------------|--------------|-------------------| -//! | struct | Unlimited | Little | Varint | Reject | -//! | function | Unlimited | Little | Fixint | Allow | -//! -//! This means that if you want to use the `Serialize` / `Deserialize` structs with the same -//! settings as the functions, you should adjust the `DefaultOptions` struct like so: -//! -//! ```rust -//! use bincode::Options; -//! let my_options = bincode::DefaultOptions::new() -//! .with_fixint_encoding() -//! .allow_trailing_bytes(); -//! ``` - -use crate::de::read::BincodeRead; -use crate::error::Result; -use std::io::{Read, Write}; -use std::marker::PhantomData; - -pub(crate) use self::endian::BincodeByteOrder; -pub(crate) use self::int::IntEncoding; -pub(crate) use self::internal::*; -pub(crate) use self::limit::SizeLimit; -pub(crate) use self::trailing::TrailingBytes; - -pub use self::endian::{BigEndian, LittleEndian, NativeEndian}; -pub use self::int::{FixintEncoding, VarintEncoding}; -pub use self::limit::{Bounded, Infinite}; -pub use self::trailing::{AllowTrailing, RejectTrailing}; - -mod endian; -mod int; -mod limit; -mod trailing; - -/// The default options for bincode serialization/deserialization. -/// -/// ### Defaults -/// By default bincode will use little-endian encoding for multi-byte integers, and will not -/// limit the number of serialized/deserialized bytes. -/// -/// ### Configuring `DefaultOptions` -/// -/// `DefaultOptions` implements the [Options] trait, which means it exposes functions to change the behavior of bincode. -/// -/// For example, if you wanted to limit the bincode deserializer to 1 kilobyte of user input: -/// -/// ```rust -/// use bincode::Options; -/// let my_options = bincode::DefaultOptions::new().with_limit(1024); -/// ``` -/// -/// ### DefaultOptions struct vs. functions -/// -/// The default configuration used by this struct is not the same as that used by the bincode -/// helper functions in the root of this crate. See the -/// [config](index.html#options-struct-vs-bincode-functions) module for more details -#[derive(Copy, Clone)] -pub struct DefaultOptions(Infinite); - -impl DefaultOptions { - /// Get a default configuration object. - /// - /// ### Default Configuration: - /// - /// | Byte limit | Endianness | Int Encoding | Trailing Behavior | - /// |------------|------------|--------------|-------------------| - /// | Unlimited | Little | Varint | Reject | - pub fn new() -> DefaultOptions { - DefaultOptions(Infinite) - } -} - -impl Default for DefaultOptions { - fn default() -> Self { - Self::new() - } -} - -impl InternalOptions for DefaultOptions { - type Limit = Infinite; - type Endian = LittleEndian; - type IntEncoding = VarintEncoding; - type Trailing = RejectTrailing; - - #[inline(always)] - fn limit(&mut self) -> &mut Infinite { - &mut self.0 - } -} - -/// A configuration builder trait whose options Bincode will use -/// while serializing and deserializing. -/// -/// ### Options -/// Endianness: The endianness with which multi-byte integers will be read/written. *default: little endian* -/// -/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited* -/// -/// Int Encoding: The encoding used for numbers, enum discriminants, and lengths. *default: varint* -/// -/// Trailing Behavior: The behavior when there are trailing bytes left over in a slice after deserialization. *default: reject* -/// -/// ### Byte Limit Details -/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode -/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long. -/// -/// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any -/// serialization that goes over the limit. -pub trait Options: InternalOptions + Sized { - /// Sets the byte limit to be unlimited. - /// This is the default. - fn with_no_limit(self) -> WithOtherLimit { - WithOtherLimit::new(self, Infinite) - } - - /// Sets the byte limit to `limit`. - fn with_limit(self, limit: u64) -> WithOtherLimit { - WithOtherLimit::new(self, Bounded(limit)) - } - - /// Sets the endianness to little-endian - /// This is the default. - fn with_little_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } - - /// Sets the endianness to big-endian - fn with_big_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } - - /// Sets the endianness to the the machine-native endianness - fn with_native_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } - - /// Sets the integer encoding to varint - fn with_varint_encoding(self) -> WithOtherIntEncoding { - WithOtherIntEncoding::new(self) - } - - /// Sets the integer encoding to be fixed - fn with_fixint_encoding(self) -> WithOtherIntEncoding { - WithOtherIntEncoding::new(self) - } - - /// Sets the deserializer to reject trailing bytes - fn reject_trailing_bytes(self) -> WithOtherTrailing { - WithOtherTrailing::new(self) - } - - /// Sets the deserializer to allow trailing bytes - fn allow_trailing_bytes(self) -> WithOtherTrailing { - WithOtherTrailing::new(self) - } - - /// Serializes a serializable object into a `Vec` of bytes using this configuration - #[inline(always)] - fn serialize(self, t: &S) -> Result> { - crate::internal::serialize(t, self) - } - - /// Returns the size that an object would be if serialized using Bincode with this configuration - #[inline(always)] - fn serialized_size(self, t: &T) -> Result { - crate::internal::serialized_size(t, self) - } - - /// Serializes an object directly into a `Writer` using this configuration - /// - /// If the serialization would take more bytes than allowed by the size limit, an error - /// is returned and *no bytes* will be written into the `Writer` - #[inline(always)] - fn serialize_into(self, w: W, t: &T) -> Result<()> { - crate::internal::serialize_into(w, t, self) - } - - /// Deserializes a slice of bytes into an instance of `T` using this configuration - #[inline(always)] - fn deserialize<'a, T: serde::Deserialize<'a>>(self, bytes: &'a [u8]) -> Result { - crate::internal::deserialize(bytes, self) - } - - /// TODO: document - #[doc(hidden)] - #[inline(always)] - fn deserialize_in_place<'a, R, T>(self, reader: R, place: &mut T) -> Result<()> - where - R: BincodeRead<'a>, - T: serde::de::Deserialize<'a>, - { - crate::internal::deserialize_in_place(reader, self, place) - } - - /// Deserializes a slice of bytes with state `seed` using this configuration. - #[inline(always)] - fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>( - self, - seed: T, - bytes: &'a [u8], - ) -> Result { - crate::internal::deserialize_seed(seed, bytes, self) - } - - /// Deserializes an object directly from a `Read`er using this configuration - /// - /// If this returns an `Error`, `reader` may be in an invalid state. - #[inline(always)] - fn deserialize_from(self, reader: R) -> Result { - crate::internal::deserialize_from(reader, self) - } - - /// Deserializes an object directly from a `Read`er with state `seed` using this configuration - /// - /// If this returns an `Error`, `reader` may be in an invalid state. - #[inline(always)] - fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>( - self, - seed: T, - reader: R, - ) -> Result { - crate::internal::deserialize_from_seed(seed, reader, self) - } - - /// Deserializes an object from a custom `BincodeRead`er using the default configuration. - /// It is highly recommended to use `deserialize_from` unless you need to implement - /// `BincodeRead` for performance reasons. - /// - /// If this returns an `Error`, `reader` may be in an invalid state. - #[inline(always)] - fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>( - self, - reader: R, - ) -> Result { - crate::internal::deserialize_from_custom(reader, self) - } - - /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default - /// configuration. It is highly recommended to use `deserialize_from` unless you need to - /// implement `BincodeRead` for performance reasons. - /// - /// If this returns an `Error`, `reader` may be in an invalid state. - #[inline(always)] - fn deserialize_from_custom_seed<'a, R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>>( - self, - seed: T, - reader: R, - ) -> Result { - crate::internal::deserialize_from_custom_seed(seed, reader, self) - } -} - -impl Options for T {} - -/// A configuration struct with a user-specified byte limit -#[derive(Clone, Copy)] -pub struct WithOtherLimit { - _options: O, - pub(crate) new_limit: L, -} - -/// A configuration struct with a user-specified endian order -#[derive(Clone, Copy)] -pub struct WithOtherEndian { - options: O, - _endian: PhantomData, -} - -/// A configuration struct with a user-specified length encoding -#[derive(Clone, Copy)] -pub struct WithOtherIntEncoding { - options: O, - _length: PhantomData, -} - -/// A configuration struct with a user-specified trailing bytes behavior. -#[derive(Clone, Copy)] -pub struct WithOtherTrailing { - options: O, - _trailing: PhantomData, -} - -impl WithOtherLimit { - #[inline(always)] - pub(crate) fn new(options: O, limit: L) -> WithOtherLimit { - WithOtherLimit { - _options: options, - new_limit: limit, - } - } -} - -impl WithOtherEndian { - #[inline(always)] - pub(crate) fn new(options: O) -> WithOtherEndian { - WithOtherEndian { - options, - _endian: PhantomData, - } - } -} - -impl WithOtherIntEncoding { - #[inline(always)] - pub(crate) fn new(options: O) -> WithOtherIntEncoding { - WithOtherIntEncoding { - options, - _length: PhantomData, - } - } -} - -impl WithOtherTrailing { - #[inline(always)] - pub(crate) fn new(options: O) -> WithOtherTrailing { - WithOtherTrailing { - options, - _trailing: PhantomData, - } - } -} - -impl InternalOptions for WithOtherEndian { - type Limit = O::Limit; - type Endian = E; - type IntEncoding = O::IntEncoding; - type Trailing = O::Trailing; - #[inline(always)] - fn limit(&mut self) -> &mut O::Limit { - self.options.limit() - } -} - -impl InternalOptions for WithOtherLimit { - type Limit = L; - type Endian = O::Endian; - type IntEncoding = O::IntEncoding; - type Trailing = O::Trailing; - fn limit(&mut self) -> &mut L { - &mut self.new_limit - } -} - -impl InternalOptions for WithOtherIntEncoding { - type Limit = O::Limit; - type Endian = O::Endian; - type IntEncoding = I; - type Trailing = O::Trailing; - - fn limit(&mut self) -> &mut O::Limit { - self.options.limit() - } -} - -impl InternalOptions for WithOtherTrailing { - type Limit = O::Limit; - type Endian = O::Endian; - type IntEncoding = O::IntEncoding; - type Trailing = T; - - fn limit(&mut self) -> &mut O::Limit { - self.options.limit() - } -} - -mod internal { - use super::*; - - pub trait InternalOptions { - type Limit: SizeLimit + 'static; - type Endian: BincodeByteOrder + 'static; - type IntEncoding: IntEncoding + 'static; - type Trailing: TrailingBytes + 'static; - - fn limit(&mut self) -> &mut Self::Limit; - } - - impl<'a, O: InternalOptions> InternalOptions for &'a mut O { - type Limit = O::Limit; - type Endian = O::Endian; - type IntEncoding = O::IntEncoding; - type Trailing = O::Trailing; - - #[inline(always)] - fn limit(&mut self) -> &mut Self::Limit { - (*self).limit() - } - } -} diff --git a/src/config/trailing.rs b/src/config/trailing.rs deleted file mode 100644 index e78dc19..0000000 --- a/src/config/trailing.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::de::read::SliceReader; -use crate::{ErrorKind, Result}; - -/// A trait for erroring deserialization if not all bytes were read. -pub trait TrailingBytes { - /// Checks a given slice reader to determine if deserialization used all bytes in the slice. - fn check_end(reader: &SliceReader) -> Result<()>; -} - -/// A TrailingBytes config that will allow trailing bytes in slices after deserialization. -#[derive(Copy, Clone)] -pub struct AllowTrailing; - -/// A TrailingBytes config that will cause bincode to produce an error if bytes are left over in the slice when deserialization is complete. - -#[derive(Copy, Clone)] -pub struct RejectTrailing; - -impl TrailingBytes for AllowTrailing { - #[inline(always)] - fn check_end(_reader: &SliceReader) -> Result<()> { - Ok(()) - } -} - -impl TrailingBytes for RejectTrailing { - #[inline(always)] - fn check_end(reader: &SliceReader) -> Result<()> { - if reader.is_finished() { - Ok(()) - } else { - Err(Box::new(ErrorKind::Custom( - "Slice had bytes remaining after deserialization".to_string(), - ))) - } - } -} diff --git a/src/de.rs b/src/de.rs new file mode 100644 index 0000000..ad15112 --- /dev/null +++ b/src/de.rs @@ -0,0 +1,96 @@ +use core::marker::PhantomData; + +use crate::{ + config::{Config, Endian}, + error::Error, +}; + +pub trait Reader<'storage> { + fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error>; + fn forward_read(&mut self, length: usize, visitor: F) -> Result + where + F: Fn(&'storage [u8]) -> R; +} + +pub trait Decodable: Sized { + fn decode(decoder: D) -> Result; +} + +pub trait Decode { + fn decode_u32(&mut self) -> Result; +} + +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + pub fn new(reader: R) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + + self.reader.read(bytes.as_mut())?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } +} + +impl Decodable for u32 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u32() + } +} + +pub struct SliceReader<'storage> { + slice: &'storage [u8], +} + +impl<'storage> SliceReader<'storage> { + /// Constructs a slice reader + pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { + SliceReader { slice: bytes } + } + + #[inline(always)] + fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8], Error> { + if length > self.slice.len() { + return Err(Error::UnexpectedEnd); + } + let (read_slice, remaining) = self.slice.split_at(length); + self.slice = remaining; + Ok(read_slice) + } +} + +impl<'storage> Reader<'storage> for SliceReader<'storage> { + #[inline(always)] + fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + if bytes.len() > self.slice.len() { + return Err(Error::UnexpectedEnd); + } + let (read_slice, remaining) = self.slice.split_at(bytes.len()); + bytes.copy_from_slice(read_slice); + self.slice = remaining; + + Ok(()) + } + + #[inline(always)] + fn forward_read(&mut self, length: usize, visitor: F) -> Result + where + F: Fn(&'storage [u8]) -> R, + { + Ok(visitor(self.get_byte_slice(length)?)) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs deleted file mode 100644 index f15f1ec..0000000 --- a/src/de/mod.rs +++ /dev/null @@ -1,514 +0,0 @@ -use crate::config::{BincodeByteOrder, Options}; -use std::io::Read; - -use self::read::{BincodeRead, IoReader, SliceReader}; -use crate::config::{IntEncoding, SizeLimit}; -use crate::{Error, ErrorKind, Result}; -use byteorder::ReadBytesExt; -use serde::de::Error as DeError; -use serde::de::IntoDeserializer; - -/// Specialized ways to read data into bincode. -pub mod read; - -/// A Deserializer that reads bytes from a buffer. -/// -/// This struct should rarely be used. -/// In most cases, prefer the `deserialize_from` function. -/// -/// The ByteOrder that is chosen will impact the endianness that -/// is used to read integers out of the reader. -/// -/// ```ignore -/// let d = Deserializer::new(&mut some_reader, SizeLimit::new()); -/// serde::Deserialize::deserialize(&mut deserializer); -/// let bytes_read = d.bytes_read(); -/// ``` -pub struct Deserializer { - pub(crate) reader: R, - options: O, -} - -macro_rules! impl_deserialize_literal { - ($name:ident : $ty:ty = $read:ident()) => { - #[inline] - pub(crate) fn $name(&mut self) -> Result<$ty> { - self.read_literal_type::<$ty>()?; - self.reader - .$read::<::Endian>() - .map_err(Into::into) - } - }; -} - -impl<'de, IR: Read, O: Options> Deserializer, O> { - /// Creates a new Deserializer with a given `Read`er and options. - pub fn with_reader(r: IR, options: O) -> Self { - Deserializer { - reader: IoReader::new(r), - options, - } - } -} - -impl<'de, O: Options> Deserializer, O> { - /// Creates a new Deserializer that will read from the given slice. - pub fn from_slice(slice: &'de [u8], options: O) -> Self { - Deserializer { - reader: SliceReader::new(slice), - options, - } - } -} - -impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { - /// Creates a new Deserializer with the given `BincodeRead`er - pub fn with_bincode_read(r: R, options: O) -> Deserializer { - Deserializer { reader: r, options } - } - - pub(crate) fn deserialize_byte(&mut self) -> Result { - self.read_literal_type::()?; - self.reader.read_u8().map_err(Into::into) - } - - impl_deserialize_literal! { deserialize_literal_u16 : u16 = read_u16() } - impl_deserialize_literal! { deserialize_literal_u32 : u32 = read_u32() } - impl_deserialize_literal! { deserialize_literal_u64 : u64 = read_u64() } - - serde_if_integer128! { - impl_deserialize_literal! { deserialize_literal_u128 : u128 = read_u128() } - } - - fn read_bytes(&mut self, count: u64) -> Result<()> { - self.options.limit().add(count) - } - - fn read_literal_type(&mut self) -> Result<()> { - use std::mem::size_of; - self.read_bytes(size_of::() as u64) - } - - fn read_vec(&mut self) -> Result> { - let len = O::IntEncoding::deserialize_len(self)?; - self.read_bytes(len as u64)?; - self.reader.get_byte_buffer(len) - } - - fn read_string(&mut self) -> Result { - let vec = self.read_vec()?; - String::from_utf8(vec).map_err(|e| ErrorKind::InvalidUtf8Encoding(e.utf8_error()).into()) - } -} - -macro_rules! impl_deserialize_int { - ($name:ident = $visitor_method:ident ($dser_method:ident)) => { - #[inline] - fn $name(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.$visitor_method(O::IntEncoding::$dser_method(self)?) - } - }; -} - -impl<'de, 'a, R, O> serde::Deserializer<'de> for &'a mut Deserializer -where - R: BincodeRead<'de>, - O: Options, -{ - type Error = Error; - - #[inline] - fn deserialize_any(self, _visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - Err(Box::new(ErrorKind::DeserializeAnyNotSupported)) - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - match self.deserialize_byte()? { - 1 => visitor.visit_bool(true), - 0 => visitor.visit_bool(false), - value => Err(ErrorKind::InvalidBoolEncoding(value).into()), - } - } - - impl_deserialize_int!(deserialize_u16 = visit_u16(deserialize_u16)); - impl_deserialize_int!(deserialize_u32 = visit_u32(deserialize_u32)); - impl_deserialize_int!(deserialize_u64 = visit_u64(deserialize_u64)); - impl_deserialize_int!(deserialize_i16 = visit_i16(deserialize_i16)); - impl_deserialize_int!(deserialize_i32 = visit_i32(deserialize_i32)); - impl_deserialize_int!(deserialize_i64 = visit_i64(deserialize_i64)); - - fn deserialize_f32(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - self.read_literal_type::()?; - let value = self - .reader - .read_f32::<::Endian>()?; - visitor.visit_f32(value) - } - - fn deserialize_f64(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - self.read_literal_type::()?; - let value = self - .reader - .read_f64::<::Endian>()?; - visitor.visit_f64(value) - } - - serde_if_integer128! { - impl_deserialize_int!(deserialize_u128 = visit_u128(deserialize_u128)); - impl_deserialize_int!(deserialize_i128 = visit_i128(deserialize_i128)); - } - - #[inline] - fn deserialize_u8(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_u8(self.deserialize_byte()? as u8) - } - - #[inline] - fn deserialize_i8(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_i8(self.deserialize_byte()? as i8) - } - - fn deserialize_unit(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_unit() - } - - fn deserialize_char(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - use std::str; - - let error = || ErrorKind::InvalidCharEncoding.into(); - - let mut buf = [0u8; 4]; - - // Look at the first byte to see how many bytes must be read - self.reader.read_exact(&mut buf[..1])?; - let width = utf8_char_width(buf[0]); - if width == 1 { - return visitor.visit_char(buf[0] as char); - } - if width == 0 { - return Err(error()); - } - - if self.reader.read_exact(&mut buf[1..width]).is_err() { - return Err(error()); - } - - let res = str::from_utf8(&buf[..width]) - .ok() - .and_then(|s| s.chars().next()) - .ok_or_else(error)?; - visitor.visit_char(res) - } - - fn deserialize_str(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let len = O::IntEncoding::deserialize_len(self)?; - self.read_bytes(len as u64)?; - self.reader.forward_read_str(len, visitor) - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_string(self.read_string()?) - } - - fn deserialize_bytes(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let len = O::IntEncoding::deserialize_len(self)?; - self.read_bytes(len as u64)?; - self.reader.forward_read_bytes(len, visitor) - } - - fn deserialize_byte_buf(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_byte_buf(self.read_vec()?) - } - - fn deserialize_enum( - self, - _enum: &'static str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: serde::de::Visitor<'de>, - { - impl<'de, 'a, R: 'a, O> serde::de::EnumAccess<'de> for &'a mut Deserializer - where - R: BincodeRead<'de>, - O: Options, - { - type Error = Error; - type Variant = Self; - - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> - where - V: serde::de::DeserializeSeed<'de>, - { - let idx: u32 = O::IntEncoding::deserialize_u32(self)?; - let val: Result<_> = seed.deserialize(idx.into_deserializer()); - Ok((val?, self)) - } - } - - visitor.visit_enum(self) - } - - fn deserialize_tuple(self, len: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - struct Access<'a, R: Read + 'a, O: Options + 'a> { - deserializer: &'a mut Deserializer, - len: usize, - } - - impl<'de, 'a, 'b: 'a, R: BincodeRead<'de> + 'b, O: Options> serde::de::SeqAccess<'de> - for Access<'a, R, O> - { - type Error = Error; - - fn next_element_seed(&mut self, seed: T) -> Result> - where - T: serde::de::DeserializeSeed<'de>, - { - if self.len > 0 { - self.len -= 1; - let value = - serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; - Ok(Some(value)) - } else { - Ok(None) - } - } - - fn size_hint(&self) -> Option { - Some(self.len) - } - } - - visitor.visit_seq(Access { - deserializer: self, - len, - }) - } - - fn deserialize_option(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let value: u8 = serde::de::Deserialize::deserialize(&mut *self)?; - match value { - 0 => visitor.visit_none(), - 1 => visitor.visit_some(&mut *self), - v => Err(ErrorKind::InvalidTagEncoding(v as usize).into()), - } - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let len = O::IntEncoding::deserialize_len(self)?; - - self.deserialize_tuple(len, visitor) - } - - fn deserialize_map(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - struct Access<'a, R: Read + 'a, O: Options + 'a> { - deserializer: &'a mut Deserializer, - len: usize, - } - - impl<'de, 'a, 'b: 'a, R: BincodeRead<'de> + 'b, O: Options> serde::de::MapAccess<'de> - for Access<'a, R, O> - { - type Error = Error; - - fn next_key_seed(&mut self, seed: K) -> Result> - where - K: serde::de::DeserializeSeed<'de>, - { - if self.len > 0 { - self.len -= 1; - let key = - serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; - Ok(Some(key)) - } else { - Ok(None) - } - } - - fn next_value_seed(&mut self, seed: V) -> Result - where - V: serde::de::DeserializeSeed<'de>, - { - let value = serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; - Ok(value) - } - - fn size_hint(&self) -> Option { - Some(self.len) - } - } - - let len = O::IntEncoding::deserialize_len(self)?; - - visitor.visit_map(Access { - deserializer: self, - len, - }) - } - - fn deserialize_struct( - self, - _name: &str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: serde::de::Visitor<'de>, - { - self.deserialize_tuple(fields.len(), visitor) - } - - fn deserialize_identifier(self, _visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let message = "Bincode does not support Deserializer::deserialize_identifier"; - Err(Error::custom(message)) - } - - fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_newtype_struct(self) - } - - fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - visitor.visit_unit() - } - - fn deserialize_tuple_struct( - self, - _name: &'static str, - len: usize, - visitor: V, - ) -> Result - where - V: serde::de::Visitor<'de>, - { - self.deserialize_tuple(len, visitor) - } - - fn deserialize_ignored_any(self, _visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let message = "Bincode does not support Deserializer::deserialize_ignored_any"; - Err(Error::custom(message)) - } - - fn is_human_readable(&self) -> bool { - false - } -} - -impl<'de, 'a, R, O> serde::de::VariantAccess<'de> for &'a mut Deserializer -where - R: BincodeRead<'de>, - O: Options, -{ - type Error = Error; - - fn unit_variant(self) -> Result<()> { - Ok(()) - } - - fn newtype_variant_seed(self, seed: T) -> Result - where - T: serde::de::DeserializeSeed<'de>, - { - serde::de::DeserializeSeed::deserialize(seed, self) - } - - fn tuple_variant(self, len: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - serde::de::Deserializer::deserialize_tuple(self, len, visitor) - } - - fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - serde::de::Deserializer::deserialize_tuple(self, fields.len(), visitor) - } -} -static UTF8_CHAR_WIDTH: [u8; 256] = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x7F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0x9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -// This function is a copy of core::str::utf8_char_width -fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} diff --git a/src/de/read.rs b/src/de/read.rs deleted file mode 100644 index ba0d8f6..0000000 --- a/src/de/read.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::error::Result; -use std::io; - -/// An optional Read trait for advanced Bincode usage. -/// -/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before -/// implementing a custom `BincodeRead`. -/// -/// The forward_read_* methods are necessary because some byte sources want -/// to pass a long-lived borrow to the visitor and others want to pass a -/// transient slice. -pub trait BincodeRead<'storage>: io::Read { - /// Check that the next `length` bytes are a valid string and pass - /// it on to the serde reader. - fn forward_read_str(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>; - - /// Transfer ownership of the next `length` bytes to the caller. - fn get_byte_buffer(&mut self, length: usize) -> Result>; - - /// Pass a slice of the next `length` bytes on to the serde reader. - fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>; -} - -/// A BincodeRead implementation for byte slices -pub struct SliceReader<'storage> { - slice: &'storage [u8], -} - -/// A BincodeRead implementation for `io::Read`ers -pub struct IoReader { - reader: R, - temp_buffer: Vec, -} - -impl<'storage> SliceReader<'storage> { - /// Constructs a slice reader - pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { - SliceReader { slice: bytes } - } - - #[inline(always)] - fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8]> { - if length > self.slice.len() { - return Err(SliceReader::unexpected_eof()); - } - let (read_slice, remaining) = self.slice.split_at(length); - self.slice = remaining; - Ok(read_slice) - } - - pub(crate) fn is_finished(&self) -> bool { - self.slice.is_empty() - } -} - -impl IoReader { - /// Constructs an IoReadReader - pub(crate) fn new(r: R) -> IoReader { - IoReader { - reader: r, - temp_buffer: vec![], - } - } -} - -impl<'storage> io::Read for SliceReader<'storage> { - #[inline(always)] - fn read(&mut self, out: &mut [u8]) -> io::Result { - if out.len() > self.slice.len() { - return Err(io::ErrorKind::UnexpectedEof.into()); - } - let (read_slice, remaining) = self.slice.split_at(out.len()); - out.copy_from_slice(read_slice); - self.slice = remaining; - - Ok(out.len()) - } - - #[inline(always)] - fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { - self.read(out).map(|_| ()) - } -} - -impl io::Read for IoReader { - #[inline(always)] - fn read(&mut self, out: &mut [u8]) -> io::Result { - self.reader.read(out) - } - #[inline(always)] - fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { - self.reader.read_exact(out) - } -} - -impl<'storage> SliceReader<'storage> { - #[inline(always)] - fn unexpected_eof() -> Box { - Box::new(crate::ErrorKind::Io(io::Error::new( - io::ErrorKind::UnexpectedEof, - "", - ))) - } -} - -impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { - #[inline(always)] - fn forward_read_str(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>, - { - use crate::ErrorKind; - let string = match ::std::str::from_utf8(self.get_byte_slice(length)?) { - Ok(s) => s, - Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), - }; - visitor.visit_borrowed_str(string) - } - - #[inline(always)] - fn get_byte_buffer(&mut self, length: usize) -> Result> { - self.get_byte_slice(length).map(|x| x.to_vec()) - } - - #[inline(always)] - fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>, - { - visitor.visit_borrowed_bytes(self.get_byte_slice(length)?) - } -} - -impl IoReader -where - R: io::Read, -{ - fn fill_buffer(&mut self, length: usize) -> Result<()> { - self.temp_buffer.resize(length, 0); - - self.reader.read_exact(&mut self.temp_buffer)?; - - Ok(()) - } -} - -impl<'a, R> BincodeRead<'a> for IoReader -where - R: io::Read, -{ - fn forward_read_str(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'a>, - { - self.fill_buffer(length)?; - - let string = match ::std::str::from_utf8(&self.temp_buffer[..]) { - Ok(s) => s, - Err(e) => return Err(crate::ErrorKind::InvalidUtf8Encoding(e).into()), - }; - - visitor.visit_str(string) - } - - fn get_byte_buffer(&mut self, length: usize) -> Result> { - self.fill_buffer(length)?; - Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new())) - } - - fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'a>, - { - self.fill_buffer(length)?; - visitor.visit_bytes(&self.temp_buffer[..]) - } -} - -#[cfg(test)] -mod test { - use super::IoReader; - - #[test] - fn test_fill_buffer() { - let buffer = vec![0u8; 64]; - let mut reader = IoReader::new(buffer.as_slice()); - - reader.fill_buffer(20).unwrap(); - assert_eq!(20, reader.temp_buffer.len()); - - reader.fill_buffer(30).unwrap(); - assert_eq!(30, reader.temp_buffer.len()); - - reader.fill_buffer(5).unwrap(); - assert_eq!(5, reader.temp_buffer.len()); - } -} diff --git a/src/error.rs b/src/error.rs index 8684924..2e3cc60 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,96 +1,6 @@ -use std::error::Error as StdError; -use std::fmt; -use std::io; -use std::str::Utf8Error; - -/// The result of a serialization or deserialization operation. -pub type Result = ::std::result::Result; - -/// An error that can be produced during (de)serializing. -pub type Error = Box; - -/// The kind of error that can be produced during a serialization or deserialization. -#[derive(Debug)] #[non_exhaustive] -pub enum ErrorKind { - /// If the error stems from the reader/writer that is being used - /// during (de)serialization, that error will be stored and returned here. - Io(io::Error), - /// Returned if the deserializer attempts to deserialize a string that is not valid utf8 - InvalidUtf8Encoding(Utf8Error), - /// Returned if the deserializer attempts to deserialize a bool that was - /// not encoded as either a 1 or a 0 - InvalidBoolEncoding(u8), - /// Returned if the deserializer attempts to deserialize a char that is not in the correct format. - InvalidCharEncoding, - /// Returned if the deserializer attempts to deserialize the tag of an enum that is - /// not in the expected ranges - InvalidTagEncoding(usize), - /// Serde has a deserialize_any method that lets the format hint to the - /// object which route to take in deserializing. - DeserializeAnyNotSupported, - /// If (de)serializing a message takes more than the provided size limit, this - /// error is returned. - SizeLimit, - /// Bincode can not encode sequences of unknown length (like iterators). - SequenceMustHaveLength, - /// A custom error message from Serde. - Custom(String), -} - -impl StdError for ErrorKind { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match *self { - ErrorKind::Io(ref err) => Some(err), - ErrorKind::InvalidUtf8Encoding(_) => None, - ErrorKind::InvalidBoolEncoding(_) => None, - ErrorKind::InvalidCharEncoding => None, - ErrorKind::InvalidTagEncoding(_) => None, - ErrorKind::SequenceMustHaveLength => None, - ErrorKind::DeserializeAnyNotSupported => None, - ErrorKind::SizeLimit => None, - ErrorKind::Custom(_) => None, - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - ErrorKind::Io(err).into() - } -} - -impl fmt::Display for ErrorKind { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - ErrorKind::Io(ref ioerr) => write!(fmt, "io error: {}", ioerr), - ErrorKind::InvalidUtf8Encoding(ref e) => write!(fmt, "string is not valid utf8: {}", e), - ErrorKind::InvalidBoolEncoding(b) => { - write!(fmt, "invalid u8 while decoding bool, expected 0 or 1, found {}", b) - } - ErrorKind::InvalidCharEncoding => write!(fmt, "char is not valid"), - ErrorKind::InvalidTagEncoding(tag) => { - write!(fmt, "tag for enum is not valid, found {}", tag) - } - ErrorKind::SequenceMustHaveLength => write!(fmt, "Bincode can only encode sequences and maps that have a knowable size ahead of time"), - ErrorKind::SizeLimit => write!(fmt, "the size limit has been reached"), - ErrorKind::DeserializeAnyNotSupported => write!( - fmt, - "Bincode does not support the serde::Deserializer::deserialize_any method" - ), - ErrorKind::Custom(ref s) => s.fmt(fmt), - } - } -} - -impl serde::de::Error for Error { - fn custom(desc: T) -> Error { - ErrorKind::Custom(desc.to_string()).into() - } -} - -impl serde::ser::Error for Error { - fn custom(msg: T) -> Self { - ErrorKind::Custom(msg.to_string()).into() - } +#[derive(Debug)] +pub enum Error { + InvalidIntEncoding, + UnexpectedEnd, } diff --git a/src/int_encoding.rs b/src/int_encoding.rs new file mode 100644 index 0000000..89c7005 --- /dev/null +++ b/src/int_encoding.rs @@ -0,0 +1,8 @@ +use crate::{error::Error, ser::Writer}; + +pub trait IntEncoding { + fn encode_u32(writer: &mut W, val: u32) -> Result<(), Error>; +} + +#[derive(Copy, Clone)] +pub struct FixintEncoding; diff --git a/src/internal.rs b/src/internal.rs deleted file mode 100644 index 78f7b2d..0000000 --- a/src/internal.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::io::{Read, Write}; -use std::marker::PhantomData; - -use crate::config::{Infinite, InternalOptions, Options, SizeLimit, TrailingBytes}; -use crate::de::read::BincodeRead; -use crate::Result; - -pub(crate) fn serialize_into(writer: W, value: &T, mut options: O) -> Result<()> -where - W: Write, - T: serde::Serialize, - O: InternalOptions, -{ - if options.limit().limit().is_some() { - // "compute" the size for the side-effect - // of returning Err if the bound was reached. - serialized_size(value, &mut options)?; - } - - let mut serializer = crate::ser::Serializer::<_, O>::new(writer, options); - serde::Serialize::serialize(value, &mut serializer) -} - -pub(crate) fn serialize(value: &T, mut options: O) -> Result> -where - T: serde::Serialize, - O: InternalOptions, -{ - let mut writer = { - let actual_size = serialized_size(value, &mut options)?; - Vec::with_capacity(actual_size as usize) - }; - - serialize_into(&mut writer, value, options.with_no_limit())?; - Ok(writer) -} - -pub(crate) fn serialized_size(value: &T, options: O) -> Result -where - T: serde::Serialize, -{ - let mut size_counter = crate::ser::SizeChecker { options, total: 0 }; - - let result = value.serialize(&mut size_counter); - result.map(|_| size_counter.total) -} - -pub(crate) fn deserialize_from(reader: R, options: O) -> Result -where - R: Read, - T: serde::de::DeserializeOwned, - O: InternalOptions, -{ - deserialize_from_seed(PhantomData, reader, options) -} - -pub(crate) fn deserialize_from_seed<'a, R, T, O>(seed: T, reader: R, options: O) -> Result -where - R: Read, - T: serde::de::DeserializeSeed<'a>, - O: InternalOptions, -{ - let reader = crate::de::read::IoReader::new(reader); - deserialize_from_custom_seed(seed, reader, options) -} - -pub(crate) fn deserialize_from_custom<'a, R, T, O>(reader: R, options: O) -> Result -where - R: BincodeRead<'a>, - T: serde::de::DeserializeOwned, - O: InternalOptions, -{ - deserialize_from_custom_seed(PhantomData, reader, options) -} - -pub(crate) fn deserialize_from_custom_seed<'a, R, T, O>( - seed: T, - reader: R, - options: O, -) -> Result -where - R: BincodeRead<'a>, - T: serde::de::DeserializeSeed<'a>, - O: InternalOptions, -{ - let mut deserializer = crate::de::Deserializer::<_, O>::with_bincode_read(reader, options); - seed.deserialize(&mut deserializer) -} - -pub(crate) fn deserialize_in_place<'a, R, T, O>(reader: R, options: O, place: &mut T) -> Result<()> -where - R: BincodeRead<'a>, - T: serde::de::Deserialize<'a>, - O: InternalOptions, -{ - let mut deserializer = crate::de::Deserializer::<_, _>::with_bincode_read(reader, options); - serde::Deserialize::deserialize_in_place(&mut deserializer, place) -} - -pub(crate) fn deserialize<'a, T, O>(bytes: &'a [u8], options: O) -> Result -where - T: serde::de::Deserialize<'a>, - O: InternalOptions, -{ - deserialize_seed(PhantomData, bytes, options) -} - -pub(crate) fn deserialize_seed<'a, T, O>(seed: T, bytes: &'a [u8], options: O) -> Result -where - T: serde::de::DeserializeSeed<'a>, - O: InternalOptions, -{ - let options = crate::config::WithOtherLimit::new(options, Infinite); - - let reader = crate::de::read::SliceReader::new(bytes); - let mut deserializer = crate::de::Deserializer::with_bincode_read(reader, options); - let val = seed.deserialize(&mut deserializer)?; - - match O::Trailing::check_end(&deserializer.reader) { - Ok(_) => Ok(val), - Err(err) => Err(err), - } -} diff --git a/src/lib.rs b/src/lib.rs index d767a4d..677a188 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,131 +1,35 @@ -#![deny(missing_docs)] +#![no_std] //! Bincode is a crate for encoding and decoding using a tiny binary //! serialization strategy. Using it, you can easily go from having //! an object in memory, quickly serialize it to bytes, and then //! deserialize it back just as fast! -//! -//! ### Using Basic Functions -//! -//! ```edition2018 -//! fn main() { -//! // The object that we will serialize. -//! let target: Option = Some("hello world".to_string()); -//! -//! let encoded: Vec = bincode::serialize(&target).unwrap(); -//! let decoded: Option = bincode::deserialize(&encoded[..]).unwrap(); -//! assert_eq!(target, decoded); -//! } -//! ``` -//! -//! ### 128bit numbers -//! -//! Support for `i128` and `u128` is automatically enabled on Rust toolchains -//! greater than or equal to `1.26.0` and disabled for targets which do not support it #![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] #![crate_name = "bincode"] #![crate_type = "rlib"] #![crate_type = "dylib"] -extern crate byteorder; -#[macro_use] -extern crate serde; +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; pub mod config; -/// Deserialize bincode data to a Rust data structure. pub mod de; +pub mod error; +pub mod ser; -mod error; -mod internal; -mod ser; +pub(crate) mod int_encoding; -pub use crate::config::{DefaultOptions, Options}; -pub use crate::de::read::BincodeRead; -pub use crate::de::Deserializer; -pub use crate::error::{Error, ErrorKind, Result}; -pub use crate::ser::Serializer; - -/// Get a default configuration object. -/// -/// ### Default Configuration: -/// -/// | Byte limit | Endianness | Int Encoding | Trailing Behavior | -/// |------------|------------|--------------|-------------------| -/// | Unlimited | Little | Varint | Reject | -#[inline(always)] -pub fn options() -> DefaultOptions { - DefaultOptions::new() +pub fn encode_into_slice(val: E, dst: &mut [u8]) -> Result<(), error::Error> { + let writer = ser::SliceWriter::new(dst); + let mut encoder = ser::Encoder::<_, config::Default>::new(writer); + val.encode(&mut encoder) } -/// Serializes an object directly into a `Writer` using the default configuration. -/// -/// If the serialization would take more bytes than allowed by the size limit, an error -/// is returned and *no bytes* will be written into the `Writer`. -pub fn serialize_into(writer: W, value: &T) -> Result<()> -where - W: std::io::Write, - T: serde::Serialize, -{ - DefaultOptions::new().serialize_into(writer, value) -} - -/// Serializes a serializable object into a `Vec` of bytes using the default configuration. -pub fn serialize(value: &T) -> Result> -where - T: serde::Serialize, -{ - DefaultOptions::new().serialize(value) -} - -/// Deserializes an object directly from a `Read`er using the default configuration. -/// -/// If this returns an `Error`, `reader` may be in an invalid state. -pub fn deserialize_from(reader: R) -> Result -where - R: std::io::Read, - T: serde::de::DeserializeOwned, -{ - DefaultOptions::new().deserialize_from(reader) -} - -/// Deserializes an object from a custom `BincodeRead`er using the default configuration. -/// It is highly recommended to use `deserialize_from` unless you need to implement -/// `BincodeRead` for performance reasons. -/// -/// If this returns an `Error`, `reader` may be in an invalid state. -pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result -where - R: de::read::BincodeRead<'a>, - T: serde::de::DeserializeOwned, -{ - DefaultOptions::new().deserialize_from_custom(reader) -} - -/// Only use this if you know what you're doing. -/// -/// This is part of the public API. -#[doc(hidden)] -pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()> -where - T: serde::de::Deserialize<'a>, - R: BincodeRead<'a>, -{ - DefaultOptions::new().deserialize_in_place(reader, place) -} - -/// Deserializes a slice of bytes into an instance of `T` using the default configuration. -pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result -where - T: serde::de::Deserialize<'a>, -{ - DefaultOptions::new().deserialize(bytes) -} - -/// Returns the size that an object would be if serialized using Bincode with the default configuration. -pub fn serialized_size(value: &T) -> Result -where - T: serde::Serialize, -{ - DefaultOptions::new().serialized_size(value) +pub fn decode(src: &mut [u8]) -> Result { + let reader = de::SliceReader::new(src); + let mut decoder = de::Decoder::<_, config::Default>::new(reader); + D::decode(&mut decoder) } diff --git a/src/ser.rs b/src/ser.rs new file mode 100644 index 0000000..24ca57b --- /dev/null +++ b/src/ser.rs @@ -0,0 +1,77 @@ +use core::marker::PhantomData; + +use crate::{ + config::{Config, Endian}, + error::Error, +}; + +pub trait Writer { + fn write(&mut self, bytes: &[u8]) -> Result<(), Error>; +} + +pub trait Encodeable { + fn encode(&self, encoder: E) -> Result<(), Error>; +} + +pub trait Encode { + fn encode_u32(&mut self, val: u32) -> Result<(), Error>; +} + +pub struct Encoder { + writer: W, + config: PhantomData, +} + +impl Encoder { + pub fn new(writer: W) -> Encoder { + Encoder { + writer, + config: PhantomData, + } + } +} + +impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + let bytes = match C::ENDIAN { + Endian::Little => val.to_le_bytes(), + Endian::Big => val.to_be_bytes(), + }; + + self.writer.write(&bytes) + } +} + +impl Encodeable for u32 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u32(*self) + } +} + +pub struct SliceWriter<'storage> { + slice: &'storage mut [u8], + cursor: usize, +} + +impl<'storage> SliceWriter<'storage> { + pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { + SliceWriter { + slice: bytes, + cursor: 0, + } + } +} + +impl<'storage> Writer for SliceWriter<'storage> { + fn write(&mut self, bytes: &[u8]) -> Result<(), Error> { + if bytes.len() - self.cursor > self.slice.len() { + return Err(Error::UnexpectedEnd); + } + let temp = &mut self.slice[self.cursor..bytes.len()]; + + temp.copy_from_slice(bytes); + self.cursor += bytes.len(); + + Ok(()) + } +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs deleted file mode 100644 index 911a5e3..0000000 --- a/src/ser/mod.rs +++ /dev/null @@ -1,770 +0,0 @@ -use std::io::Write; -use std::u32; - -use byteorder::WriteBytesExt; - -use super::config::{IntEncoding, SizeLimit}; -use super::{Error, ErrorKind, Result}; -use crate::config::{BincodeByteOrder, Options}; -use std::mem::size_of; - -/// An Serializer that encodes values directly into a Writer. -/// -/// The specified byte-order will impact the endianness that is -/// used during the encoding. -/// -/// This struct should not be used often. -/// For most cases, prefer the `encode_into` function. -pub struct Serializer { - writer: W, - _options: O, -} - -macro_rules! impl_serialize_literal { - ($ser_method:ident($ty:ty) = $write:ident()) => { - pub(crate) fn $ser_method(&mut self, v: $ty) -> Result<()> { - self.writer - .$write::<::Endian>(v) - .map_err(Into::into) - } - }; -} - -impl Serializer { - /// Creates a new Serializer with the given `Write`r. - pub fn new(w: W, options: O) -> Serializer { - Serializer { - writer: w, - _options: options, - } - } - - pub(crate) fn serialize_byte(&mut self, v: u8) -> Result<()> { - self.writer.write_u8(v).map_err(Into::into) - } - - impl_serialize_literal! {serialize_literal_u16(u16) = write_u16()} - impl_serialize_literal! {serialize_literal_u32(u32) = write_u32()} - impl_serialize_literal! {serialize_literal_u64(u64) = write_u64()} - - serde_if_integer128! { - impl_serialize_literal!{serialize_literal_u128(u128) = write_u128()} - } -} - -macro_rules! impl_serialize_int { - ($ser_method:ident($ty:ty) = $ser_int:ident()) => { - fn $ser_method(self, v: $ty) -> Result<()> { - O::IntEncoding::$ser_int(self, v) - } - }; -} - -impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { - type Ok = (); - type Error = Error; - type SerializeSeq = Compound<'a, W, O>; - type SerializeTuple = Compound<'a, W, O>; - type SerializeTupleStruct = Compound<'a, W, O>; - type SerializeTupleVariant = Compound<'a, W, O>; - type SerializeMap = Compound<'a, W, O>; - type SerializeStruct = Compound<'a, W, O>; - type SerializeStructVariant = Compound<'a, W, O>; - - fn serialize_unit(self) -> Result<()> { - Ok(()) - } - - fn serialize_unit_struct(self, _: &'static str) -> Result<()> { - Ok(()) - } - - fn serialize_bool(self, v: bool) -> Result<()> { - self.serialize_byte(v as u8) - } - - fn serialize_u8(self, v: u8) -> Result<()> { - self.serialize_byte(v) - } - - impl_serialize_int! {serialize_u16(u16) = serialize_u16()} - impl_serialize_int! {serialize_u32(u32) = serialize_u32()} - impl_serialize_int! {serialize_u64(u64) = serialize_u64()} - - fn serialize_i8(self, v: i8) -> Result<()> { - self.serialize_byte(v as u8) - } - - impl_serialize_int! {serialize_i16(i16) = serialize_i16()} - impl_serialize_int! {serialize_i32(i32) = serialize_i32()} - impl_serialize_int! {serialize_i64(i64) = serialize_i64()} - - serde_if_integer128! { - impl_serialize_int!{serialize_u128(u128) = serialize_u128()} - impl_serialize_int!{serialize_i128(i128) = serialize_i128()} - } - - fn serialize_f32(self, v: f32) -> Result<()> { - self.writer - .write_f32::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_f64(self, v: f64) -> Result<()> { - self.writer - .write_f64::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_str(self, v: &str) -> Result<()> { - O::IntEncoding::serialize_len(self, v.len())?; - self.writer.write_all(v.as_bytes()).map_err(Into::into) - } - - fn serialize_char(self, c: char) -> Result<()> { - self.writer - .write_all(encode_utf8(c).as_slice()) - .map_err(Into::into) - } - - fn serialize_bytes(self, v: &[u8]) -> Result<()> { - O::IntEncoding::serialize_len(self, v.len())?; - self.writer.write_all(v).map_err(Into::into) - } - - fn serialize_none(self) -> Result<()> { - self.writer.write_u8(0).map_err(Into::into) - } - - fn serialize_some(self, v: &T) -> Result<()> - where - T: serde::Serialize, - { - self.writer.write_u8(1)?; - v.serialize(self) - } - - fn serialize_seq(self, len: Option) -> Result { - let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - O::IntEncoding::serialize_len(self, len)?; - Ok(Compound { ser: self }) - } - - fn serialize_tuple(self, _len: usize) -> Result { - Ok(Compound { ser: self }) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(Compound { ser: self }) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - O::IntEncoding::serialize_u32(self, variant_index)?; - Ok(Compound { ser: self }) - } - - fn serialize_map(self, len: Option) -> Result { - let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - O::IntEncoding::serialize_len(self, len)?; - Ok(Compound { ser: self }) - } - - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { - Ok(Compound { ser: self }) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - O::IntEncoding::serialize_u32(self, variant_index)?; - Ok(Compound { ser: self }) - } - - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - value: &T, - ) -> Result<()> - where - T: serde::ser::Serialize, - { - O::IntEncoding::serialize_u32(self, variant_index)?; - value.serialize(self) - } - - fn serialize_unit_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - ) -> Result<()> { - O::IntEncoding::serialize_u32(self, variant_index) - } - - fn is_human_readable(&self) -> bool { - false - } -} - -pub(crate) struct SizeChecker { - pub options: O, - pub total: u64, -} - -impl SizeChecker { - fn add_raw(&mut self, size: u64) -> Result<()> { - self.options.limit().add(size)?; - self.total += size; - - Ok(()) - } - - fn add_discriminant(&mut self, idx: u32) -> Result<()> { - let bytes = O::IntEncoding::u32_size(idx); - self.add_raw(bytes) - } - - fn add_len(&mut self, len: usize) -> Result<()> { - let bytes = O::IntEncoding::len_size(len); - self.add_raw(bytes) - } -} - -macro_rules! impl_size_int { - ($ser_method:ident($ty:ty) = $size_method:ident()) => { - fn $ser_method(self, v: $ty) -> Result<()> { - self.add_raw(O::IntEncoding::$size_method(v)) - } - }; -} - -impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { - type Ok = (); - type Error = Error; - type SerializeSeq = SizeCompound<'a, O>; - type SerializeTuple = SizeCompound<'a, O>; - type SerializeTupleStruct = SizeCompound<'a, O>; - type SerializeTupleVariant = SizeCompound<'a, O>; - type SerializeMap = SizeCompound<'a, O>; - type SerializeStruct = SizeCompound<'a, O>; - type SerializeStructVariant = SizeCompound<'a, O>; - - fn serialize_unit(self) -> Result<()> { - Ok(()) - } - - fn serialize_unit_struct(self, _: &'static str) -> Result<()> { - Ok(()) - } - - fn serialize_bool(self, _: bool) -> Result<()> { - self.add_raw(1) - } - - fn serialize_u8(self, _: u8) -> Result<()> { - self.add_raw(1) - } - fn serialize_i8(self, _: i8) -> Result<()> { - self.add_raw(1) - } - - impl_size_int! {serialize_u16(u16) = u16_size()} - impl_size_int! {serialize_u32(u32) = u32_size()} - impl_size_int! {serialize_u64(u64) = u64_size()} - impl_size_int! {serialize_i16(i16) = i16_size()} - impl_size_int! {serialize_i32(i32) = i32_size()} - impl_size_int! {serialize_i64(i64) = i64_size()} - - serde_if_integer128! { - impl_size_int!{serialize_u128(u128) = u128_size()} - impl_size_int!{serialize_i128(i128) = i128_size()} - } - - fn serialize_f32(self, _: f32) -> Result<()> { - self.add_raw(size_of::() as u64) - } - - fn serialize_f64(self, _: f64) -> Result<()> { - self.add_raw(size_of::() as u64) - } - - fn serialize_str(self, v: &str) -> Result<()> { - self.add_len(v.len())?; - self.add_raw(v.len() as u64) - } - - fn serialize_char(self, c: char) -> Result<()> { - self.add_raw(encode_utf8(c).as_slice().len() as u64) - } - - fn serialize_bytes(self, v: &[u8]) -> Result<()> { - self.add_len(v.len())?; - self.add_raw(v.len() as u64) - } - - fn serialize_none(self) -> Result<()> { - self.add_raw(1) - } - - fn serialize_some(self, v: &T) -> Result<()> - where - T: serde::Serialize, - { - self.add_raw(1)?; - v.serialize(self) - } - - fn serialize_seq(self, len: Option) -> Result { - let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - - self.add_len(len)?; - Ok(SizeCompound { ser: self }) - } - - fn serialize_tuple(self, _len: usize) -> Result { - Ok(SizeCompound { ser: self }) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Ok(SizeCompound { ser: self }) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - self.add_raw(O::IntEncoding::u32_size(variant_index))?; - Ok(SizeCompound { ser: self }) - } - - fn serialize_map(self, len: Option) -> Result { - let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - - self.add_len(len)?; - Ok(SizeCompound { ser: self }) - } - - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { - Ok(SizeCompound { ser: self }) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - self.add_discriminant(variant_index)?; - Ok(SizeCompound { ser: self }) - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - v: &V, - ) -> Result<()> { - v.serialize(self) - } - - fn serialize_unit_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - ) -> Result<()> { - self.add_discriminant(variant_index) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - variant_index: u32, - _variant: &'static str, - value: &V, - ) -> Result<()> { - self.add_discriminant(variant_index)?; - value.serialize(self) - } - - fn is_human_readable(&self) -> bool { - false - } -} - -pub struct Compound<'a, W: 'a, O: Options + 'a> { - ser: &'a mut Serializer, -} - -impl<'a, W, O> serde::ser::SerializeSeq for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeTuple for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeTupleStruct for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeTupleVariant for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeMap for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_key(&mut self, value: &K) -> Result<()> - where - K: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn serialize_value(&mut self, value: &V) -> Result<()> - where - V: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeStruct for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, W, O> serde::ser::SerializeStructVariant for Compound<'a, W, O> -where - W: Write, - O: Options, -{ - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -pub(crate) struct SizeCompound<'a, S: Options + 'a> { - ser: &'a mut SizeChecker, -} - -impl<'a, O: Options> serde::ser::SerializeSeq for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options> serde::ser::SerializeTuple for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options> serde::ser::SerializeTupleStruct for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options> serde::ser::SerializeTupleVariant for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options + 'a> serde::ser::SerializeMap for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_key(&mut self, value: &K) -> Result<()> - where - K: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn serialize_value(&mut self, value: &V) -> Result<()> - where - V: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options> serde::ser::SerializeStruct for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} - -impl<'a, O: Options> serde::ser::SerializeStructVariant for SizeCompound<'a, O> { - type Ok = (); - type Error = Error; - - #[inline] - fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> - where - T: serde::ser::Serialize, - { - value.serialize(&mut *self.ser) - } - - #[inline] - fn end(self) -> Result<()> { - Ok(()) - } -} -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; - -fn encode_utf8(c: char) -> EncodeUtf8 { - let code = c as u32; - let mut buf = [0; 4]; - let pos = if code < MAX_ONE_B { - buf[3] = code as u8; - 3 - } else if code < MAX_TWO_B { - buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B { - buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 1 - } else { - buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 0 - }; - EncodeUtf8 { buf, pos } -} - -struct EncodeUtf8 { - buf: [u8; 4], - pos: usize, -} - -impl EncodeUtf8 { - fn as_slice(&self) -> &[u8] { - &self.buf[self.pos..] - } -} diff --git a/tests/test.rs b/tests/test.rs index 0d64676..45cdc23 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,905 +1,19 @@ -#[macro_use] -extern crate serde_derive; - extern crate bincode; -extern crate byteorder; -#[macro_use] -extern crate serde; -extern crate serde_bytes; -use std::borrow::Cow; -use std::collections::HashMap; -use std::fmt::{self, Debug}; -use std::result::Result as StdResult; - -use bincode::{ - deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, - DefaultOptions, ErrorKind, Options, Result, -}; -use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; - -const LEN_SIZE: u64 = 8; - -fn the_same_impl(element: V, options: &mut O) -where - V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, - O: Options, -{ - let size = options.serialized_size(&element).unwrap(); - - { - let encoded = options.serialize(&element).unwrap(); - let decoded: V = options.deserialize(&encoded[..]).unwrap(); - let decoded_reader = options.deserialize_from(&mut &encoded[..]).unwrap(); - - assert_eq!(element, decoded); - assert_eq!(element, decoded_reader); - assert_eq!(size, encoded.len() as u64); - } -} +use core::fmt::Debug; fn the_same(element: V) where - V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + Clone + 'static, + V: bincode::ser::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, { - // add a new macro which calls the previous when you add a new option set - macro_rules! all_endians { - ($element:expr, $options:expr) => { - the_same_impl($element.clone(), &mut $options.with_native_endian()); - the_same_impl($element.clone(), &mut $options.with_big_endian()); - the_same_impl($element.clone(), &mut $options.with_little_endian()); - }; - } + let mut buffer = [0u8; 32]; + bincode::encode_into_slice(element.clone(), &mut buffer).unwrap(); + let decoded: V = bincode::decode(&mut buffer).unwrap(); - macro_rules! all_integer_encodings { - ($element:expr, $options:expr) => { - all_endians!($element, $options.with_fixint_encoding()); - all_endians!($element, $options.with_varint_encoding()); - }; - } - - all_integer_encodings!(element, DefaultOptions::new()); + assert_eq!(element, decoded); } #[test] fn test_numbers() { - // unsigned positive - the_same(5u8); - the_same(5u16); the_same(5u32); - the_same(5u64); - the_same(5usize); - // signed positive - the_same(5i8); - the_same(5i16); - the_same(5i32); - the_same(5i64); - the_same(5isize); - // signed negative - the_same(-5i8); - the_same(-5i16); - the_same(-5i32); - the_same(-5i64); - the_same(-5isize); - // floating - the_same(-100f32); - the_same(0f32); - the_same(5f32); - the_same(-100f64); - the_same(5f64); -} - -serde_if_integer128! { - #[test] - fn test_numbers_128bit() { - // unsigned positive - the_same(5u128); - the_same(u128::max_value()); - // signed positive - the_same(5i128); - the_same(i128::max_value()); - // signed negative - the_same(-5i128); - the_same(i128::min_value()); - } -} - -#[test] -fn test_string() { - the_same("".to_string()); - the_same("a".to_string()); -} - -#[test] -fn test_tuple() { - the_same((1isize,)); - the_same((1isize, 2isize, 3isize)); - the_same((1isize, "foo".to_string(), ())); -} - -#[test] -fn test_basic_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct Easy { - x: isize, - s: String, - y: usize, - } - the_same(Easy { - x: -4, - s: "foo".to_string(), - y: 10, - }); -} - -#[test] -fn test_nested_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct Easy { - x: isize, - s: String, - y: usize, - } - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct Nest { - f: Easy, - b: usize, - s: Easy, - } - - the_same(Nest { - f: Easy { - x: -1, - s: "foo".to_string(), - y: 20, - }, - b: 100, - s: Easy { - x: -100, - s: "bar".to_string(), - y: 20, - }, - }); -} - -#[test] -fn test_struct_newtype() { - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct NewtypeStr(usize); - - the_same(NewtypeStr(5)); -} - -#[test] -fn test_struct_tuple() { - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct TubStr(usize, String, f32); - - the_same(TubStr(5, "hello".to_string(), 3.2)); -} - -#[test] -fn test_option() { - the_same(Some(5usize)); - the_same(Some("foo bar".to_string())); - the_same(None::); -} - -#[test] -fn test_enum() { - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - enum TestEnum { - NoArg, - OneArg(usize), - Args(usize, usize), - AnotherNoArg, - StructLike { x: usize, y: f32 }, - } - the_same(TestEnum::NoArg); - the_same(TestEnum::OneArg(4)); - //the_same(TestEnum::Args(4, 5)); - the_same(TestEnum::AnotherNoArg); - the_same(TestEnum::StructLike { x: 4, y: 3.14159 }); - the_same(vec![ - TestEnum::NoArg, - TestEnum::OneArg(5), - TestEnum::AnotherNoArg, - TestEnum::StructLike { x: 4, y: 1.4 }, - ]); -} - -#[test] -fn test_vec() { - let v: Vec = vec![]; - the_same(v); - the_same(vec![1u64]); - the_same(vec![1u64, 2, 3, 4, 5, 6]); -} - -#[test] -fn test_map() { - let mut m = HashMap::new(); - m.insert(4u64, "foo".to_string()); - m.insert(0u64, "bar".to_string()); - the_same(m); -} - -#[test] -fn test_bool() { - the_same(true); - the_same(false); -} - -#[test] -fn test_unicode() { - the_same("å".to_string()); - the_same("aåååååååa".to_string()); -} - -#[test] -fn test_fixed_size_array() { - the_same([24u32; 32]); - the_same([1u64, 2, 3, 4, 5, 6, 7, 8]); - the_same([0u8; 19]); -} - -#[test] -fn deserializing_errors() { - match *deserialize::(&vec![0xA][..]).unwrap_err() { - ErrorKind::InvalidBoolEncoding(0xA) => {} - _ => panic!(), - } - - let invalid_str = vec![1, 0xFF]; - - match *deserialize::(&invalid_str[..]).unwrap_err() { - ErrorKind::InvalidUtf8Encoding(_) => {} - e => panic!("{:?}", e), - } - - // Out-of-bounds variant - #[derive(Serialize, Deserialize, Debug)] - enum Test { - One, - Two, - } - - let invalid_enum = vec![0, 0, 0, 5]; - - match *deserialize::(&invalid_enum[..]).unwrap_err() { - // Error message comes from serde - ErrorKind::Custom(_) => {} - _ => panic!(), - } - match *deserialize::>(&vec![5, 0][..]).unwrap_err() { - ErrorKind::InvalidTagEncoding(_) => {} - _ => panic!(), - } -} - -#[test] -fn trailing_bytes() { - match DefaultOptions::new() - .deserialize::(b"1x") - .map_err(|e| *e) - { - Err(ErrorKind::Custom(_)) => {} - other => panic!("Expecting TrailingBytes, got {:?}", other), - } -} - -#[test] -fn too_big_deserialize() { - let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = DefaultOptions::new() - .with_fixint_encoding() - .with_limit(3) - .deserialize_from(&mut &serialized[..]); - assert!(deserialized.is_err()); - - let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = DefaultOptions::new() - .with_fixint_encoding() - .with_limit(4) - .deserialize_from(&mut &serialized[..]); - assert!(deserialized.is_ok()); -} - -#[test] -fn char_serialization() { - let chars = "Aa\0☺♪"; - for c in chars.chars() { - let encoded = DefaultOptions::new() - .with_limit(4) - .serialize(&c) - .expect("serializing char failed"); - let decoded: char = deserialize(&encoded).expect("deserializing failed"); - assert_eq!(decoded, c); - } -} - -#[test] -fn too_big_char_deserialize() { - let serialized = vec![0x41]; - let deserialized: Result = DefaultOptions::new() - .with_limit(1) - .deserialize_from(&mut &serialized[..]); - assert!(deserialized.is_ok()); - assert_eq!(deserialized.unwrap(), 'A'); -} - -#[test] -fn too_big_serialize() { - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(3) - .serialize(&0u32) - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(4) - .serialize(&0u32) - .is_ok()); - - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(LEN_SIZE + 4) - .serialize(&"abcde") - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(LEN_SIZE + 5) - .serialize(&"abcde") - .is_ok()); -} - -#[test] -fn test_serialized_size() { - let opt = DefaultOptions::new().with_fixint_encoding(); - assert!(opt.serialized_size(&0u8).unwrap() == 1); - assert!(opt.serialized_size(&0u16).unwrap() == 2); - assert!(opt.serialized_size(&0u32).unwrap() == 4); - assert!(opt.serialized_size(&0u64).unwrap() == 8); - - // length isize stored as u64 - assert!(opt.serialized_size(&"").unwrap() == LEN_SIZE); - assert!(opt.serialized_size(&"a").unwrap() == LEN_SIZE + 1); - - assert!(opt.serialized_size(&vec![0u32, 1u32, 2u32]).unwrap() == LEN_SIZE + 3 * (4)); -} - -#[test] -fn test_serialized_size_bounded() { - // JUST RIGHT - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(1) - .serialized_size(&0u8) - .unwrap() - == 1 - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(2) - .serialized_size(&0u16) - .unwrap() - == 2 - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(4) - .serialized_size(&0u32) - .unwrap() - == 4 - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(8) - .serialized_size(&0u64) - .unwrap() - == 8 - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(8) - .serialized_size(&"") - .unwrap() - == LEN_SIZE - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(8 + 1) - .serialized_size(&"a") - .unwrap() - == LEN_SIZE + 1 - ); - assert!( - DefaultOptions::new() - .with_fixint_encoding() - .with_limit(LEN_SIZE + 3 * 4) - .serialized_size(&vec![0u32, 1u32, 2u32]) - .unwrap() - == LEN_SIZE + 3 * 4 - ); - // Below - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(0) - .serialized_size(&0u8) - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(1) - .serialized_size(&0u16) - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(3) - .serialized_size(&0u32) - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(7) - .serialized_size(&0u64) - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(7) - .serialized_size(&"") - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(8 + 0) - .serialized_size(&"a") - .is_err()); - assert!(DefaultOptions::new() - .with_fixint_encoding() - .with_limit(8 + 3 * 4 - 1) - .serialized_size(&vec![0u32, 1u32, 2u32]) - .is_err()); -} - -#[test] -fn encode_box() { - the_same(Box::new(5)); -} - -#[test] -fn test_cow_serialize() { - let large_object = vec![1u32, 2, 3, 4, 5, 6]; - let mut large_map = HashMap::new(); - large_map.insert(1, 2); - - #[derive(Serialize, Deserialize, Debug)] - enum Message<'a> { - M1(Cow<'a, Vec>), - M2(Cow<'a, HashMap>), - } - - // Test 1 - { - let serialized = serialize(&Message::M1(Cow::Borrowed(&large_object))).unwrap(); - let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); - - match deserialized { - Message::M1(b) => assert!(&b.into_owned() == &large_object), - _ => assert!(false), - } - } - - // Test 2 - { - let serialized = serialize(&Message::M2(Cow::Borrowed(&large_map))).unwrap(); - let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); - - match deserialized { - Message::M2(b) => assert!(&b.into_owned() == &large_map), - _ => assert!(false), - } - } -} - -#[test] -fn test_strbox_serialize() { - let strx: &'static str = "hello world"; - let serialized = serialize(&Cow::Borrowed(strx)).unwrap(); - let deserialized: Cow<'static, String> = deserialize_from(&mut &serialized[..]).unwrap(); - let stringx: String = deserialized.into_owned(); - assert!(strx == &stringx[..]); -} - -#[test] -fn test_slicebox_serialize() { - let slice = [1u32, 2, 3, 4, 5]; - let serialized = serialize(&Cow::Borrowed(&slice[..])).unwrap(); - println!("{:?}", serialized); - let deserialized: Cow<'static, Vec> = deserialize_from(&mut &serialized[..]).unwrap(); - { - let sb: &[u32] = &deserialized; - assert!(slice == sb); - } - let vecx: Vec = deserialized.into_owned(); - assert!(slice == &vecx[..]); -} - -#[test] -fn test_multi_strings_serialize() { - assert!(serialize(&("foo", "bar", "baz")).is_ok()); -} - -#[test] -fn test_oom_protection() { - use std::io::Cursor; - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct FakeVec { - len: u64, - byte: u8, - } - let x = DefaultOptions::new() - .with_limit(10) - .serialize(&FakeVec { - len: 0xffffffffffffffffu64, - byte: 1, - }) - .unwrap(); - let y: Result> = DefaultOptions::new() - .with_limit(10) - .deserialize_from(&mut Cursor::new(&x[..])); - assert!(y.is_err()); -} - -#[test] -fn path_buf() { - use std::path::{Path, PathBuf}; - let path = Path::new("foo").to_path_buf(); - let serde_encoded = serialize(&path).unwrap(); - let decoded: PathBuf = deserialize(&serde_encoded).unwrap(); - assert!(path.to_str() == decoded.to_str()); -} - -#[test] -fn bytes() { - use serde_bytes::Bytes; - - let data = b"abc\0123"; - let s = serialize(&data[..]).unwrap(); - let s2 = serialize(&Bytes::new(data)).unwrap(); - assert_eq!(s[..], s2[..]); -} - -#[test] -fn serde_bytes() { - use serde_bytes::ByteBuf; - the_same(ByteBuf::from(vec![1, 2, 3, 4, 5])); -} - -#[test] -fn endian_difference() { - let x = 10u64; - let little = DefaultOptions::new() - .with_fixint_encoding() - .serialize(&x) - .unwrap(); - let big = DefaultOptions::new() - .with_big_endian() - .with_fixint_encoding() - .serialize(&x) - .unwrap(); - assert_ne!(little, big); -} - -#[test] -fn test_zero_copy_parse() { - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] - struct Foo<'a> { - borrowed_str: &'a str, - borrowed_bytes: &'a [u8], - } - - let f = Foo { - borrowed_str: "hi", - borrowed_bytes: &[0, 1, 2, 3], - }; - { - let encoded = serialize(&f).unwrap(); - let out: Foo = deserialize(&encoded[..]).unwrap(); - assert_eq!(out, f); - } -} - -#[test] -fn test_zero_copy_parse_deserialize_into() { - use bincode::BincodeRead; - use std::io; - - /// A BincodeRead implementation for byte slices - pub struct SliceReader<'storage> { - slice: &'storage [u8], - } - - impl<'storage> SliceReader<'storage> { - #[inline(always)] - fn unexpected_eof() -> Box { - return Box::new(crate::ErrorKind::Io(io::Error::new( - io::ErrorKind::UnexpectedEof, - "", - ))); - } - } - - impl<'storage> io::Read for SliceReader<'storage> { - #[inline(always)] - fn read(&mut self, out: &mut [u8]) -> io::Result { - (&mut self.slice).read(out) - } - #[inline(always)] - fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { - (&mut self.slice).read_exact(out) - } - } - - impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { - #[inline(always)] - fn forward_read_str(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>, - { - use crate::ErrorKind; - if length > self.slice.len() { - return Err(SliceReader::unexpected_eof()); - } - - let string = match ::std::str::from_utf8(&self.slice[..length]) { - Ok(s) => s, - Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), - }; - let r = visitor.visit_borrowed_str(string); - self.slice = &self.slice[length..]; - r - } - - #[inline(always)] - fn get_byte_buffer(&mut self, length: usize) -> Result> { - if length > self.slice.len() { - return Err(SliceReader::unexpected_eof()); - } - - let r = &self.slice[..length]; - self.slice = &self.slice[length..]; - Ok(r.to_vec()) - } - - #[inline(always)] - fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'storage>, - { - if length > self.slice.len() { - return Err(SliceReader::unexpected_eof()); - } - - let r = visitor.visit_borrowed_bytes(&self.slice[..length]); - self.slice = &self.slice[length..]; - r - } - } - - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] - struct Foo<'a> { - borrowed_str: &'a str, - borrowed_bytes: &'a [u8], - } - - let f = Foo { - borrowed_str: "hi", - borrowed_bytes: &[0, 1, 2, 3], - }; - - { - let encoded = serialize(&f).unwrap(); - let mut target = Foo { - borrowed_str: "hello", - borrowed_bytes: &[10, 11, 12, 13], - }; - deserialize_in_place( - SliceReader { - slice: &encoded[..], - }, - &mut target, - ) - .unwrap(); - assert_eq!(target, f); - } -} - -#[test] -fn not_human_readable() { - use std::net::Ipv4Addr; - let ip = Ipv4Addr::new(1, 2, 3, 4); - the_same(ip); - assert_eq!(&ip.octets()[..], &serialize(&ip).unwrap()[..]); - assert_eq!( - ::std::mem::size_of::() as u64, - serialized_size(&ip).unwrap() - ); -} - -// The example is taken from serde::de::DeserializeSeed. -struct ExtendVec<'a, T: 'a>(&'a mut Vec); - -impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> -where - T: Deserialize<'de>, -{ - // The return type of the `deserialize` method. This implementation - // appends onto an existing vector but does not create any new data - // structure, so the return type is (). - type Value = (); - - fn deserialize(self, deserializer: D) -> StdResult - where - D: Deserializer<'de>, - { - // Visitor implementation that will walk an inner array of the JSON - // input. - struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec); - - impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> - where - T: Deserialize<'de>, - { - type Value = (); - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "an array of integers") - } - - fn visit_seq(self, mut seq: A) -> StdResult<(), A::Error> - where - A: SeqAccess<'de>, - { - // Visit each element in the inner array and push it onto - // the existing vector. - while let Some(elem) = seq.next_element()? { - self.0.push(elem); - } - Ok(()) - } - } - - deserializer.deserialize_seq(ExtendVecVisitor(self.0)) - } -} - -#[test] -fn test_default_deserialize_seed() { - let config = DefaultOptions::new(); - - let data: Vec<_> = (10..100).collect(); - let bytes = config.serialize(&data).expect("Config::serialize failed"); - - let mut seed_data: Vec<_> = (0..10).collect(); - { - let seed = ExtendVec(&mut seed_data); - config - .deserialize_seed(seed, &bytes) - .expect("Config::deserialize_seed failed"); - } - - assert_eq!(seed_data, (0..100).collect::>()); -} - -#[test] -fn test_big_endian_deserialize_seed() { - let config = DefaultOptions::new().with_big_endian(); - - let data: Vec<_> = (10..100).collect(); - let bytes = config.serialize(&data).expect("Config::serialize failed"); - - let mut seed_data: Vec<_> = (0..10).collect(); - { - let seed = ExtendVec(&mut seed_data); - config - .deserialize_seed(seed, &bytes) - .expect("Config::deserialize_seed failed"); - } - - assert_eq!(seed_data, (0..100).collect::>()); -} - -#[test] -fn test_default_deserialize_from_seed() { - let config = DefaultOptions::new(); - - let data: Vec<_> = (10..100).collect(); - let bytes = config.serialize(&data).expect("Config::serialize failed"); - - let mut seed_data: Vec<_> = (0..10).collect(); - { - let seed = ExtendVec(&mut seed_data); - config - .deserialize_from_seed(seed, &mut &*bytes) - .expect("Config::deserialize_from_seed failed"); - } - - assert_eq!(seed_data, (0..100).collect::>()); -} - -#[test] -fn test_big_endian_deserialize_from_seed() { - let config = DefaultOptions::new().with_big_endian(); - - let data: Vec<_> = (10..100).collect(); - let bytes = config.serialize(&data).expect("Config::serialize failed"); - - let mut seed_data: Vec<_> = (0..10).collect(); - { - let seed = ExtendVec(&mut seed_data); - config - .deserialize_from_seed(seed, &mut &*bytes) - .expect("Config::deserialize_from_seed failed"); - } - - assert_eq!(seed_data, (0..100).collect::>()); -} - -#[test] -fn test_varint_length_prefixes() { - let a = vec![(); 127]; // should be a single byte - let b = vec![(); 250]; // also should be a single byte - let c = vec![(); 251]; - let d = vec![(); u16::max_value() as usize + 1]; - - assert_eq!( - DefaultOptions::new() - .with_varint_encoding() - .serialized_size(&a[..]) - .unwrap(), - 1 - ); // 2 ** 7 - 1 - assert_eq!( - DefaultOptions::new() - .with_varint_encoding() - .serialized_size(&b[..]) - .unwrap(), - 1 - ); // 250 - assert_eq!( - DefaultOptions::new() - .with_varint_encoding() - .serialized_size(&c[..]) - .unwrap(), - (1 + std::mem::size_of::()) as u64 - ); // 251 - assert_eq!( - DefaultOptions::new() - .with_varint_encoding() - .serialized_size(&d[..]) - .unwrap(), - (1 + std::mem::size_of::()) as u64 - ); // 2 ** 16 + 1 -} - -#[test] -fn test_byte_vec_struct() { - #[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug)] - struct ByteVecs { - a: Vec, - b: Vec, - c: Vec, - } - - let byte_struct = ByteVecs { - a: vec![2; 20], - b: vec![3; 30], - c: vec![1; 10], - }; - - the_same(byte_struct); } From b7c0d1fac0c9b8294e1d653c4f80aac78a5d2dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Sun, 20 Jun 2021 00:12:10 +0200 Subject: [PATCH 02/80] reorganize de/enc modules --- src/de/impls.rs | 8 ++++ src/de/mod.rs | 48 ++++++++++++++++++++++++ src/{de.rs => de/read.rs} | 51 ++------------------------ src/enc/impls.rs | 8 ++++ src/enc/mod.rs | 44 ++++++++++++++++++++++ src/enc/write.rs | 30 +++++++++++++++ src/int_encoding.rs | 2 +- src/lib.rs | 10 ++--- src/ser.rs | 77 --------------------------------------- tests/test.rs | 2 +- 10 files changed, 148 insertions(+), 132 deletions(-) create mode 100644 src/de/impls.rs create mode 100644 src/de/mod.rs rename src/{de.rs => de/read.rs} (55%) create mode 100644 src/enc/impls.rs create mode 100644 src/enc/mod.rs create mode 100644 src/enc/write.rs delete mode 100644 src/ser.rs diff --git a/src/de/impls.rs b/src/de/impls.rs new file mode 100644 index 0000000..131750e --- /dev/null +++ b/src/de/impls.rs @@ -0,0 +1,8 @@ +use super::{Decode, Decodable}; +use crate::error::Error; + +impl Decodable for u32 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u32() + } +} \ No newline at end of file diff --git a/src/de/mod.rs b/src/de/mod.rs new file mode 100644 index 0000000..4b4c348 --- /dev/null +++ b/src/de/mod.rs @@ -0,0 +1,48 @@ +use core::marker::PhantomData; + +use crate::{ + config::{Config, Endian}, + error::Error, +}; +use read::Reader; + +mod impls; +pub mod read; + + + +pub trait Decodable: Sized { + fn decode(decoder: D) -> Result; +} + +pub trait Decode { + fn decode_u32(&mut self) -> Result; +} + +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + pub fn new(reader: R) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + + self.reader.read(bytes.as_mut())?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } +} + + diff --git a/src/de.rs b/src/de/read.rs similarity index 55% rename from src/de.rs rename to src/de/read.rs index ad15112..6e4270d 100644 --- a/src/de.rs +++ b/src/de/read.rs @@ -1,9 +1,4 @@ -use core::marker::PhantomData; - -use crate::{ - config::{Config, Endian}, - error::Error, -}; +use crate::error::Error; pub trait Reader<'storage> { fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error>; @@ -12,46 +7,6 @@ pub trait Reader<'storage> { F: Fn(&'storage [u8]) -> R; } -pub trait Decodable: Sized { - fn decode(decoder: D) -> Result; -} - -pub trait Decode { - fn decode_u32(&mut self) -> Result; -} - -pub struct Decoder { - reader: R, - config: PhantomData, -} - -impl<'de, R: Reader<'de>, C: Config> Decoder { - pub fn new(reader: R) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } -} - -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u32(&mut self) -> Result { - let mut bytes = [0u8; 4]; - - self.reader.read(bytes.as_mut())?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - }) - } -} - -impl Decodable for u32 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u32() - } -} - pub struct SliceReader<'storage> { slice: &'storage [u8], } @@ -75,7 +30,7 @@ impl<'storage> SliceReader<'storage> { impl<'storage> Reader<'storage> for SliceReader<'storage> { #[inline(always)] - fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + fn read<'a>(&'a mut self, bytes: &mut [u8]) -> Result<(), Error> { if bytes.len() > self.slice.len() { return Err(Error::UnexpectedEnd); } @@ -93,4 +48,4 @@ impl<'storage> Reader<'storage> for SliceReader<'storage> { { Ok(visitor(self.get_byte_slice(length)?)) } -} +} \ No newline at end of file diff --git a/src/enc/impls.rs b/src/enc/impls.rs new file mode 100644 index 0000000..87a149a --- /dev/null +++ b/src/enc/impls.rs @@ -0,0 +1,8 @@ +use super::{Encode, Encodeable}; +use crate::error::Error; + +impl Encodeable for u32 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u32(*self) + } +} \ No newline at end of file diff --git a/src/enc/mod.rs b/src/enc/mod.rs new file mode 100644 index 0000000..caf67a6 --- /dev/null +++ b/src/enc/mod.rs @@ -0,0 +1,44 @@ +use core::marker::PhantomData; + +use crate::{ + config::{Config, Endian}, + error::Error, +}; +use write::Writer; + +mod impls; +pub mod write; + + +pub trait Encodeable { + fn encode(&self, encoder: E) -> Result<(), Error>; +} + +pub trait Encode { + fn encode_u32(&mut self, val: u32) -> Result<(), Error>; +} + +pub struct Encoder { + writer: W, + config: PhantomData, +} + +impl Encoder { + pub fn new(writer: W) -> Encoder { + Encoder { + writer, + config: PhantomData, + } + } +} + +impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + let bytes = match C::ENDIAN { + Endian::Little => val.to_le_bytes(), + Endian::Big => val.to_be_bytes(), + }; + + self.writer.write(&bytes) + } +} \ No newline at end of file diff --git a/src/enc/write.rs b/src/enc/write.rs new file mode 100644 index 0000000..6d33e1a --- /dev/null +++ b/src/enc/write.rs @@ -0,0 +1,30 @@ +use crate::error::Error; + +pub trait Writer { + fn write(&mut self, bytes: &[u8]) -> Result<(), Error>; +} + +pub struct SliceWriter<'storage> { + slice: &'storage mut [u8], +} + +impl<'storage> SliceWriter<'storage> { + pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { + SliceWriter { + slice: bytes, + } + } +} + +impl<'storage> Writer for SliceWriter<'storage> { + fn write(&mut self, bytes: &[u8]) -> Result<(), Error> { + if bytes.len() > self.slice.len() { + return Err(Error::UnexpectedEnd); + } + let data = core::mem::take(&mut self.slice); + let (write_slice, remaining) = data.split_at_mut(bytes.len()); + write_slice.copy_from_slice(bytes); + self.slice = remaining; + Ok(()) + } +} \ No newline at end of file diff --git a/src/int_encoding.rs b/src/int_encoding.rs index 89c7005..cb81454 100644 --- a/src/int_encoding.rs +++ b/src/int_encoding.rs @@ -1,4 +1,4 @@ -use crate::{error::Error, ser::Writer}; +use crate::{error::Error, enc::write::Writer}; pub trait IntEncoding { fn encode_u32(writer: &mut W, val: u32) -> Result<(), Error>; diff --git a/src/lib.rs b/src/lib.rs index 677a188..16aa95a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,18 +18,18 @@ extern crate std; pub mod config; pub mod de; pub mod error; -pub mod ser; +pub mod enc; pub(crate) mod int_encoding; -pub fn encode_into_slice(val: E, dst: &mut [u8]) -> Result<(), error::Error> { - let writer = ser::SliceWriter::new(dst); - let mut encoder = ser::Encoder::<_, config::Default>::new(writer); +pub fn encode_into_slice(val: E, dst: &mut [u8]) -> Result<(), error::Error> { + let writer = enc::write::SliceWriter::new(dst); + let mut encoder = enc::Encoder::<_, config::Default>::new(writer); val.encode(&mut encoder) } pub fn decode(src: &mut [u8]) -> Result { - let reader = de::SliceReader::new(src); + let reader = de::read::SliceReader::new(src); let mut decoder = de::Decoder::<_, config::Default>::new(reader); D::decode(&mut decoder) } diff --git a/src/ser.rs b/src/ser.rs deleted file mode 100644 index 24ca57b..0000000 --- a/src/ser.rs +++ /dev/null @@ -1,77 +0,0 @@ -use core::marker::PhantomData; - -use crate::{ - config::{Config, Endian}, - error::Error, -}; - -pub trait Writer { - fn write(&mut self, bytes: &[u8]) -> Result<(), Error>; -} - -pub trait Encodeable { - fn encode(&self, encoder: E) -> Result<(), Error>; -} - -pub trait Encode { - fn encode_u32(&mut self, val: u32) -> Result<(), Error>; -} - -pub struct Encoder { - writer: W, - config: PhantomData, -} - -impl Encoder { - pub fn new(writer: W) -> Encoder { - Encoder { - writer, - config: PhantomData, - } - } -} - -impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { - let bytes = match C::ENDIAN { - Endian::Little => val.to_le_bytes(), - Endian::Big => val.to_be_bytes(), - }; - - self.writer.write(&bytes) - } -} - -impl Encodeable for u32 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { - encoder.encode_u32(*self) - } -} - -pub struct SliceWriter<'storage> { - slice: &'storage mut [u8], - cursor: usize, -} - -impl<'storage> SliceWriter<'storage> { - pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { - SliceWriter { - slice: bytes, - cursor: 0, - } - } -} - -impl<'storage> Writer for SliceWriter<'storage> { - fn write(&mut self, bytes: &[u8]) -> Result<(), Error> { - if bytes.len() - self.cursor > self.slice.len() { - return Err(Error::UnexpectedEnd); - } - let temp = &mut self.slice[self.cursor..bytes.len()]; - - temp.copy_from_slice(bytes); - self.cursor += bytes.len(); - - Ok(()) - } -} diff --git a/tests/test.rs b/tests/test.rs index 45cdc23..db65476 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -4,7 +4,7 @@ use core::fmt::Debug; fn the_same(element: V) where - V: bincode::ser::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + 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(); From 174ef41ac936578fc8d23a83c26f071cb5f3b0f1 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 12:07:10 +0200 Subject: [PATCH 03/80] First version of the bincode serialization spec --- docs/spec.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 docs/spec.md diff --git a/docs/spec.md b/docs/spec.md new file mode 100644 index 0000000..eab62b0 --- /dev/null +++ b/docs/spec.md @@ -0,0 +1,103 @@ +# Serialization specification + +*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization is done by `serde-derive` instead. `serde-derive` has the same guarantees as `bincode_derive` for now. + +Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123 + +## 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. + +All basic numeric types will be encoded based on the configured [IntEncoding](#IntEncoding). + +All floating point types will take up exactly 4 (for `f32`) or 8 (for `f64`) bytes. + +All tuples have no additional bytes, and are encoded in their specified order, e.g. +```rs +let tuple = (u32::min_value(), i32::max_value()); // 8 bytes +let encoded = bincode::encode_to_vec_with_options(&tuple, Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 0, // 4 bytes for first type: u32 + 255, 255, 255, 255 // 4 bytes for second type: i32 +]); +``` + +## IntEncoding +Bincode currently supports 2 different types of `IntEncoding`: + +### VarintEncoding +Encoding an unsigned integer v (of any type excepting u8) 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`. +1. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`. +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`. + +See the documentation of [VarintEncoding](https://docs.rs/bincode/latest/bincode/config/struct.VarintEncoding.html) for more information. + +### FixintEncoding + +- Fixed size integers are encoded directly +- Enum discriminants are encoded as u32 +- Lengths and usize are encoded as u64 + +See the documentation of [FixintEncoding](https://docs.rs/bincode/latest/bincode/config/struct.FixintEncoding.html) for more information. + +## Enums + +Enums are encoded with their variant first, followed by optionally the variant fields. The variant index is based on the `IntEncoding` during serilization. + +Both named and unnamed fields are serialized with their values only, and therefor encode to the same value. + +```rs +#[derive(bincode::Serialize)] +pub enum SomeEnum { + A, + B(u32), + C { value: u32 }, +} + +// SomeEnum::A +let encoded = bincode::encode_to_vec_with_options(&SomeEnum::A, Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 0, // first variant, A + // no extra bytes because A has no fields +]); + +// SomeEnum::B(0) +let encoded = bincode::encode_to_vec_with_options(&SomeEnum::B(0), Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 1, // first variant, B + 0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes +]); + +// SomeEnum::C { value: 0u32 } +let encoded = bincode::encode_to_vec_with_options(&SomeEnum::C { value: 0u32 }, Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 2, // first variant, C + 0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes +]); +``` + +# Collections + +Collections are encoded with their length value first, following by each entry of the collection. The length value is based on your `IntEncoding`. + +```rs +let list = vec![ + 0u8, + 1u8, + 2u8 +]; + +let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 0, 0, 0, 0, 3, // length of 3u64 + 0, // entry 0 + 1, // entry 1 + 2, // entry 2 +]); +``` + +This also applies to e.g. `HashMap`, where each entry is a [tuple](#Basic%20types) of the key and value. From 7cbca87d3e13fa5f9f86ad8fa5b7618ce215a65e Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 12:11:24 +0200 Subject: [PATCH 04/80] Added documentation on String/&str --- docs/spec.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/spec.md b/docs/spec.md index eab62b0..d506eff 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -101,3 +101,17 @@ assert_eq!(encoded.as_slice(), &[ ``` This also applies to e.g. `HashMap`, where each entry is a [tuple](#Basic%20types) of the key and value. + +# String and &str + +Both `String` and `&str` are treated as a `Vec`. See [Collections](#Collections) for more information. + +```rs +let str = "Hello"; // Could also be `String::new(...)` + +let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 0, 0, 0, 0, 0, 0, 0, 5, // length of the string, 5 bytes + b'H', b'e', b'l', b'l', b'o' +]); +``` From a6435388a12e76d61b6884f22b490da35ccd2972 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 12:12:09 +0200 Subject: [PATCH 05/80] Fixed internal links in spec.md --- docs/spec.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index d506eff..e1fb077 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -100,11 +100,11 @@ assert_eq!(encoded.as_slice(), &[ ]); ``` -This also applies to e.g. `HashMap`, where each entry is a [tuple](#Basic%20types) of the key and value. +This also applies to e.g. `HashMap`, where each entry is a [tuple](#basic-types) of the key and value. # String and &str -Both `String` and `&str` are treated as a `Vec`. See [Collections](#Collections) for more information. +Both `String` and `&str` are treated as a `Vec`. See [Collections](#collections) for more information. ```rs let str = "Hello"; // Could also be `String::new(...)` From bab0cf4bd15ed86ecc677d0f652fdfc80a408ede Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 13:20:47 +0200 Subject: [PATCH 06/80] Started working on bincode_derive --- Cargo.toml | 11 ++++++- derive/.gitignore | 1 + derive/Cargo.lock | 46 ++++++++++++++++++++++++++++++ derive/Cargo.toml | 15 ++++++++++ derive/src/derive_enum.rs | 19 +++++++++++++ derive/src/derive_struct.rs | 57 +++++++++++++++++++++++++++++++++++++ derive/src/error.rs | 24 ++++++++++++++++ derive/src/lib.rs | 49 +++++++++++++++++++++++++++++++ docs/spec.md | 4 +-- src/de/impls.rs | 4 +-- src/de/mod.rs | 4 --- src/de/read.rs | 4 +-- src/enc/impls.rs | 14 ++++++++- src/enc/mod.rs | 38 +++++++++++++++++++++++-- src/enc/write.rs | 16 +++++++---- src/int_encoding.rs | 2 +- src/lib.rs | 12 ++++++-- tests/derive.rs | 19 +++++++++++++ 18 files changed, 315 insertions(+), 24 deletions(-) create mode 100644 derive/.gitignore create mode 100644 derive/Cargo.lock create mode 100644 derive/Cargo.toml create mode 100644 derive/src/derive_enum.rs create mode 100644 derive/src/derive_struct.rs create mode 100644 derive/src/error.rs create mode 100644 derive/src/lib.rs create mode 100644 tests/derive.rs diff --git a/Cargo.toml b/Cargo.toml index 8d21054..4062fd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,13 @@ keywords = ["binary", "encode", "decode", "serialize", "deserialize"] license = "MIT" description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!" -edition = "2018" \ No newline at end of file +edition = "2018" + +[features] +default = ["std"] +std = [] +alloc = [] + +[dependencies] +bincode_derive = { path = "derive" } +# serde = { version = "1.0.130", optional = true } diff --git a/derive/.gitignore b/derive/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/derive/.gitignore @@ -0,0 +1 @@ +target diff --git a/derive/Cargo.lock b/derive/Cargo.lock new file mode 100644 index 0000000..c581e3f --- /dev/null +++ b/derive/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bincode_derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/derive/Cargo.toml b/derive/Cargo.toml new file mode 100644 index 0000000..2987147 --- /dev/null +++ b/derive/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "bincode_derive" +version = "0.1.0" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.9" + +[dependencies.syn] +version = "1.0.74" +default-features = false +features = ["parsing", "derive", "proc-macro", "printing"] diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs new file mode 100644 index 0000000..73c0b08 --- /dev/null +++ b/derive/src/derive_enum.rs @@ -0,0 +1,19 @@ +use crate::Result; +use proc_macro::TokenStream; +use syn::Ident; + +pub struct DeriveEnum {} + +impl DeriveEnum { + pub fn parse(_name: Ident, _en: syn::DataEnum) -> Result { + unimplemented!() + } + + pub fn to_encodable(self) -> Result { + unimplemented!() + } + + pub fn to_decodable(self) -> Result { + unimplemented!() + } +} diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs new file mode 100644 index 0000000..0bb7de3 --- /dev/null +++ b/derive/src/derive_struct.rs @@ -0,0 +1,57 @@ +use crate::Result; +use proc_macro::TokenStream; +use quote::quote; +use syn::{spanned::Spanned, Ident}; + +pub struct DeriveStruct { + name: Ident, + fields: Vec, +} + +impl DeriveStruct { + pub fn parse(name: Ident, str: syn::DataStruct) -> Result { + let fields = match str.fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .map(|f| f.ident.clone().unwrap()) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .enumerate() + .map(|(i, field)| Ident::new(&i.to_string(), field.ty.span())) + .collect(), + syn::Fields::Unit => Vec::new(), + }; + Ok(Self { name, fields }) + } + + pub fn to_encodable(self) -> Result { + let DeriveStruct { name, fields } = self; + + let fields = fields + .into_iter() + .map(|field| { + quote! { + bincode::enc::Encodeable::encode(&self. #field, &mut encoder)?; + } + }) + .collect::>(); + + let result = quote! { + impl bincode::enc::Encodeable for #name { + fn encode(&self, mut encoder: E) -> Result<(), bincode::error::Error> { + #(#fields)* + Ok(()) + } + + } + }; + Ok(result.into()) + } + + pub fn to_decodable(self) -> Result { + unimplemented!() + } +} diff --git a/derive/src/error.rs b/derive/src/error.rs new file mode 100644 index 0000000..ff1abee --- /dev/null +++ b/derive/src/error.rs @@ -0,0 +1,24 @@ +use proc_macro::TokenStream; +use quote::__private::Span; +use std::fmt; + +pub enum Error { + UnionNotSupported, +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::UnionNotSupported => write!(fmt, "Unions are not supported"), + } + } +} + +impl Error { + pub fn into_token_stream(self) -> TokenStream { + self.into_token_stream_with_span(Span::call_site()) + } + pub fn into_token_stream_with_span(self, span: Span) -> TokenStream { + syn::Error::new(span, self).into_compile_error().into() + } +} diff --git a/derive/src/lib.rs b/derive/src/lib.rs new file mode 100644 index 0000000..82be10a --- /dev/null +++ b/derive/src/lib.rs @@ -0,0 +1,49 @@ +extern crate proc_macro; + +mod derive_enum; +mod derive_struct; +mod error; + +use derive_enum::DeriveEnum; +use derive_struct::DeriveStruct; +use error::Error; +use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; + +type Result = std::result::Result; + +#[proc_macro_derive(Encodable)] +pub fn derive_encodable(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_encodable_inner(input).unwrap_or_else(|e| e.into_token_stream()) +} + +fn derive_encodable_inner(input: DeriveInput) -> Result { + match input.data { + syn::Data::Struct(struct_definition) => { + DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_encodable()) + } + syn::Data::Enum(enum_definition) => { + DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_encodable()) + } + syn::Data::Union(_) => Err(Error::UnionNotSupported), + } +} + +#[proc_macro_derive(Decodable)] +pub fn derive_decodable(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_decodable_inner(input).unwrap_or_else(|e| e.into_token_stream()) +} + +fn derive_decodable_inner(input: DeriveInput) -> Result { + match input.data { + syn::Data::Struct(struct_definition) => { + DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_decodable()) + } + syn::Data::Enum(enum_definition) => { + DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_decodable()) + } + syn::Data::Union(_) => Err(Error::UnionNotSupported), + } +} diff --git a/docs/spec.md b/docs/spec.md index e1fb077..ed23380 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -1,6 +1,6 @@ # Serialization specification -*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization is done by `serde-derive` instead. `serde-derive` has the same guarantees as `bincode_derive` for now. +*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization with `serde-derive` is supported as well. `serde-derive` has the same guarantees as `bincode_derive` for now. Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123 @@ -51,7 +51,7 @@ Enums are encoded with their variant first, followed by optionally the variant f Both named and unnamed fields are serialized with their values only, and therefor encode to the same value. ```rs -#[derive(bincode::Serialize)] +#[derive(bincode::Encodable)] pub enum SomeEnum { A, B(u32), diff --git a/src/de/impls.rs b/src/de/impls.rs index 131750e..265b664 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,8 +1,8 @@ -use super::{Decode, Decodable}; +use super::{Decodable, Decode}; use crate::error::Error; impl Decodable for u32 { fn decode(mut decoder: D) -> Result { decoder.decode_u32() } -} \ No newline at end of file +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 4b4c348..b97152c 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -9,8 +9,6 @@ use read::Reader; mod impls; pub mod read; - - pub trait Decodable: Sized { fn decode(decoder: D) -> Result; } @@ -44,5 +42,3 @@ impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { }) } } - - diff --git a/src/de/read.rs b/src/de/read.rs index 6e4270d..f9cd893 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -30,7 +30,7 @@ impl<'storage> SliceReader<'storage> { impl<'storage> Reader<'storage> for SliceReader<'storage> { #[inline(always)] - fn read<'a>(&'a mut self, bytes: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error> { if bytes.len() > self.slice.len() { return Err(Error::UnexpectedEnd); } @@ -48,4 +48,4 @@ impl<'storage> Reader<'storage> for SliceReader<'storage> { { Ok(visitor(self.get_byte_slice(length)?)) } -} \ No newline at end of file +} diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 87a149a..da16aa2 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,8 +1,20 @@ use super::{Encode, Encodeable}; use crate::error::Error; +impl Encodeable for u8 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u8(*self) + } +} + impl Encodeable for u32 { fn encode(&self, mut encoder: E) -> Result<(), Error> { encoder.encode_u32(*self) } -} \ No newline at end of file +} + +impl Encodeable for i32 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_i32(*self) + } +} diff --git a/src/enc/mod.rs b/src/enc/mod.rs index caf67a6..e6c7100 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -9,13 +9,28 @@ use write::Writer; mod impls; pub mod write; - pub trait Encodeable { fn encode(&self, encoder: E) -> Result<(), Error>; } - pub trait Encode { + fn encode_u8(&mut self, val: u8) -> Result<(), Error>; fn encode_u32(&mut self, val: u32) -> Result<(), Error>; + fn encode_i32(&mut self, val: i32) -> Result<(), Error>; +} + +impl<'a, T> Encode for &'a mut T +where + T: Encode, +{ + fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + T::encode_u8(self, val) + } + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + T::encode_u32(self, val) + } + fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + T::encode_i32(self, val) + } } pub struct Encoder { @@ -30,9 +45,17 @@ impl Encoder { config: PhantomData, } } + + pub fn into_writer(self) -> W { + self.writer + } } impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { + fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + self.writer.write(&[val]) + } + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { let bytes = match C::ENDIAN { Endian::Little => val.to_le_bytes(), @@ -41,4 +64,13 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { self.writer.write(&bytes) } -} \ No newline at end of file + + fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + let bytes = match C::ENDIAN { + Endian::Little => val.to_le_bytes(), + Endian::Big => val.to_be_bytes(), + }; + + self.writer.write(&bytes) + } +} diff --git a/src/enc/write.rs b/src/enc/write.rs index 6d33e1a..1f8d6e7 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -6,25 +6,31 @@ pub trait Writer { pub struct SliceWriter<'storage> { slice: &'storage mut [u8], + idx: usize, } impl<'storage> SliceWriter<'storage> { pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { SliceWriter { slice: bytes, + idx: 0, } } + + pub(crate) fn bytes_written(&self) -> usize { + self.idx + } } impl<'storage> Writer for SliceWriter<'storage> { fn write(&mut self, bytes: &[u8]) -> Result<(), Error> { - if bytes.len() > self.slice.len() { + let remaining = &mut self.slice[self.idx..]; + if bytes.len() > remaining.len() { return Err(Error::UnexpectedEnd); } - let data = core::mem::take(&mut self.slice); - let (write_slice, remaining) = data.split_at_mut(bytes.len()); + self.idx += bytes.len(); + let write_slice = &mut remaining[..bytes.len()]; write_slice.copy_from_slice(bytes); - self.slice = remaining; Ok(()) } -} \ No newline at end of file +} diff --git a/src/int_encoding.rs b/src/int_encoding.rs index cb81454..f3117ed 100644 --- a/src/int_encoding.rs +++ b/src/int_encoding.rs @@ -1,4 +1,4 @@ -use crate::{error::Error, enc::write::Writer}; +use crate::{enc::write::Writer, error::Error}; pub trait IntEncoding { fn encode_u32(writer: &mut W, val: u32) -> Result<(), Error>; diff --git a/src/lib.rs b/src/lib.rs index 16aa95a..3c72acb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,15 +17,21 @@ extern crate std; pub mod config; pub mod de; -pub mod error; pub mod enc; +pub mod error; + +pub use bincode_derive::{Decodable, Encodable}; pub(crate) mod int_encoding; -pub fn encode_into_slice(val: E, dst: &mut [u8]) -> Result<(), error::Error> { +pub fn encode_into_slice( + val: E, + dst: &mut [u8], +) -> Result { let writer = enc::write::SliceWriter::new(dst); let mut encoder = enc::Encoder::<_, config::Default>::new(writer); - val.encode(&mut encoder) + val.encode(&mut encoder)?; + Ok(encoder.into_writer().bytes_written()) } pub fn decode(src: &mut [u8]) -> Result { diff --git a/tests/derive.rs b/tests/derive.rs new file mode 100644 index 0000000..35a5e8b --- /dev/null +++ b/tests/derive.rs @@ -0,0 +1,19 @@ +#[derive(bincode::Encodable, PartialEq, Debug)] +pub struct Test { + a: i32, + b: u32, + c: u8, +} + +#[test] +fn test_encodable() { + let start = Test { + a: 5i32, + b: 10u32, + c: 20u8, + }; + 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]); +} From d800d0f181dd9efbed0d8c152cf924152c91fab7 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 13:22:47 +0200 Subject: [PATCH 07/80] Removed derive/Cargo.lock --- derive/.gitignore | 3 ++- derive/Cargo.lock | 46 ---------------------------------------------- 2 files changed, 2 insertions(+), 47 deletions(-) delete mode 100644 derive/Cargo.lock diff --git a/derive/.gitignore b/derive/.gitignore index eb5a316..4fffb2f 100644 --- a/derive/.gitignore +++ b/derive/.gitignore @@ -1 +1,2 @@ -target +/target +/Cargo.lock diff --git a/derive/Cargo.lock b/derive/Cargo.lock deleted file mode 100644 index c581e3f..0000000 --- a/derive/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "bincode_derive" -version = "0.1.0" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" From cbd5c6b94008017b7cbfb0e937c8b07f570e878b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 13 Sep 2021 13:36:29 +0200 Subject: [PATCH 08/80] Enable CI for the deserde branch --- .github/workflows/rust.yml | 353 +++++++++++++++++++------------------ Cargo.toml | 54 +++--- derive/Cargo.toml | 2 +- 3 files changed, 206 insertions(+), 203 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 13e13e5..24b29a7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,175 +1,178 @@ -{ - "name": "CI", - "on": { - "push": { - "branches": [ - "trunk", - "v*.x" - ] - }, - "pull_request": { - "branches": [ - "trunk", - "v*.x" - ] - } - }, - "jobs": { - "check": { - "name": "Check", - "runs-on": "ubuntu-latest", - "strategy": { - "fail-fast": false, - "matrix": { - "rust": [ - "stable", - "beta", - "nightly", - "1.41.0" - ] - } - }, - "steps": [ - { - "uses": "actions/checkout@v2", - "name": "Checkout" - }, - { - "uses": "actions-rs/toolchain@v1", - "with": { - "profile": "minimal", - "toolchain": "${{ matrix.rust }}", - "override": true - }, - "name": "Install Rust ${{ matrix.rust }}" - }, - { - "uses": "actions-rs/cargo@v1", - "with": { - "command": "check" - }, - "name": "Run `cargo check`" - }, - { - "uses": "actions-rs/cargo@v1", - "with": { - "command": "check", - "args": "--examples" - }, - "name": "Check examples", - "if": "matrix.rust != '1.41.0'" - } - ] - }, - "test": { - "name": "Test", - "runs-on": "ubuntu-latest", - "strategy": { - "matrix": { - "rust": [ - "stable", - "beta", - "nightly" - ] - } - }, - "steps": [ - { - "uses": "actions/checkout@v2", - "name": "Checkout" - }, - { - "uses": "actions-rs/toolchain@v1", - "with": { - "profile": "minimal", - "toolchain": "${{ matrix.rust }}", - "override": true - }, - "name": "Install Rust ${{ matrix.rust }}" - }, - { - "uses": "actions-rs/cargo@v1", - "with": { - "command": "test" - }, - "name": "Run `cargo test`" - } - ] - }, - "lints": { - "name": "Lints", - "runs-on": "ubuntu-latest", - "steps": [ - { - "uses": "actions/checkout@v2", - "name": "Checkout" - }, - { - "uses": "actions-rs/toolchain@v1", - "with": { - "profile": "minimal", - "toolchain": "stable", - "override": true, - "components": "rustfmt, clippy" - }, - "name": "Install Rust stable" - }, - { - "uses": "actions-rs/cargo@v1", - "with": { - "command": "fmt", - "args": "--all -- --check" - }, - "name": "Run `cargo fmt`" - }, - { - "uses": "actions-rs/cargo@v1", - "with": { - "command": "clippy", - "args": "-- -D warnings" - }, - "name": "Run `cargo clippy`" - } - ] - }, - "coverage": { - "name": "Code Coverage", - "runs-on": "ubuntu-latest", - "steps": [ - { - "uses": "actions/checkout@v2", - "name": "Checkout" - }, - { - "uses": "actions-rs/toolchain@v1", - "with": { - "profile": "minimal", - "toolchain": "nightly", - "override": true - }, - "name": "Install Rust nightly" - }, - { - "name": "Run cargo-tarpaulin", - "uses": "actions-rs/tarpaulin@v0.1", - "with": { - "version": "0.12.3", - "args": "--ignore-tests -- --test-threads 1" - } - }, - { - "name": "Upload to codecov.io", - "uses": "codecov/codecov-action@v1" - }, - { - "name": "Archive code coverage results", - "uses": "actions/upload-artifact@v1", - "with": { - "name": "code-coverage-report", - "path": "cobertura.xml" - } - } - ] - } - } -} +{ + "name": "CI", + "on": { + "push": { + "branches": [ + "trunk", + "feature/deserde", # Temporary while we work on deserde + "v*.x" + ] + }, + "pull_request": { + "branches": [ + "trunk", + "v*.x" + ] + } + }, + "jobs": { + "check": { + "name": "Check", + "runs-on": "ubuntu-latest", + "strategy": { + "fail-fast": false, + "matrix": { + "rust": [ + "stable", + "beta", + "nightly", + "1.41.0" + ] + } + }, + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "${{ matrix.rust }}", + "override": true + }, + "name": "Install Rust ${{ matrix.rust }}" + }, + { + "uses": "actions-rs/cargo@v1", + "with": { + "command": "check" + }, + "name": "Run `cargo check`" + } + # , + # { + # "uses": "actions-rs/cargo@v1", + # "with": { + # "command": "check", + # "args": "--examples" + # }, + # "name": "Check examples", + # "if": "matrix.rust != '1.41.0'" + # } + ] + }, + "test": { + "name": "Test", + "runs-on": "ubuntu-latest", + "strategy": { + "matrix": { + "rust": [ + "stable", + "beta", + "nightly" + ] + } + }, + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "${{ matrix.rust }}", + "override": true + }, + "name": "Install Rust ${{ matrix.rust }}" + }, + { + "uses": "actions-rs/cargo@v1", + "with": { + "command": "test" + }, + "name": "Run `cargo test`" + } + ] + }, + "lints": { + "name": "Lints", + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "stable", + "override": true, + "components": "rustfmt, clippy" + }, + "name": "Install Rust stable" + }, + { + "uses": "actions-rs/cargo@v1", + "with": { + "command": "fmt", + "args": "--all -- --check" + }, + "name": "Run `cargo fmt`" + }, + { + "uses": "actions-rs/cargo@v1", + "with": { + "command": "clippy", + "args": "-- -D warnings" + }, + "name": "Run `cargo clippy`" + } + ] + } + # Tarpaulin seems to not work with bincode_derive + # "coverage": { + # "name": "Code Coverage", + # "runs-on": "ubuntu-latest", + # "steps": [ + # { + # "uses": "actions/checkout@v2", + # "name": "Checkout" + # }, + # { + # "uses": "actions-rs/toolchain@v1", + # "with": { + # "profile": "minimal", + # "toolchain": "nightly", + # "override": true + # }, + # "name": "Install Rust nightly" + # }, + # { + # "name": "Run cargo-tarpaulin", + # "uses": "actions-rs/tarpaulin@v0.1", + # "with": { + # "version": "0.18.2", + # "args": "--ignore-tests -- --test-threads 1" + # } + # }, + # { + # "name": "Upload to codecov.io", + # "uses": "codecov/codecov-action@v1" + # }, + # { + # "name": "Archive code coverage results", + # "uses": "actions/upload-artifact@v1", + # "with": { + # "name": "code-coverage-report", + # "path": "cobertura.xml" + # } + # } + # ] + # } + } +} diff --git a/Cargo.toml b/Cargo.toml index 4062fd8..51c22f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,27 +1,27 @@ -[package] -name = "bincode" -version = "2.0.0-dev" # remember to update html_root_url -authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan "] -exclude = ["logo.png", "examples/*", ".gitignore", ".github/"] - -publish = true - -repository = "https://github.com/bincode-org/bincode" -documentation = "https://docs.rs/bincode" -readme = "./readme.md" -categories = ["encoding", "network-programming"] -keywords = ["binary", "encode", "decode", "serialize", "deserialize"] - -license = "MIT" -description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!" - -edition = "2018" - -[features] -default = ["std"] -std = [] -alloc = [] - -[dependencies] -bincode_derive = { path = "derive" } -# serde = { version = "1.0.130", optional = true } +[package] +name = "bincode" +version = "2.0.0-dev" # remember to update html_root_url and bincode_derive +authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan "] +exclude = ["logo.png", "examples/*", ".gitignore", ".github/"] + +publish = true + +repository = "https://github.com/bincode-org/bincode" +documentation = "https://docs.rs/bincode" +readme = "./readme.md" +categories = ["encoding", "network-programming"] +keywords = ["binary", "encode", "decode", "serialize", "deserialize"] + +license = "MIT" +description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!" + +edition = "2018" + +[features] +default = ["std"] +std = [] +alloc = [] + +[dependencies] +bincode_derive = { path = "derive", version = "2.0.0-dev" } +# serde = { version = "1.0.130", optional = true } diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 2987147..381bb9c 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bincode_derive" -version = "0.1.0" +version = "2.0.0-dev" # remember to update bincode edition = "2018" [lib] From 8a4eac82fb2a452bb77500c6e071ad5e6f53c1cd Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 08:28:38 +0200 Subject: [PATCH 09/80] Made the encoder respect intencoding, implemented FixintEncoding --- src/config.rs | 20 +++---- src/enc/impls.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++ src/enc/mod.rs | 96 +++++++++++++++++++++++----------- src/int_encoding.rs | 116 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 316 insertions(+), 41 deletions(-) diff --git a/src/config.rs b/src/config.rs index 751146b..31f90d1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,19 +1,26 @@ +use crate::int_encoding::FixintEncoding; + pub(crate) use self::internal::*; pub trait Config: InternalConfig + Sized {} pub struct Default; -impl InternalConfig for Default {} +impl InternalConfig for Default { + type IntEncoding = FixintEncoding; +} 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)] @@ -22,16 +29,11 @@ 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/impls.rs b/src/enc/impls.rs index da16aa2..cb800a9 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -7,14 +7,139 @@ impl Encodeable for u8 { } } +impl Encodeable for u16 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u16(*self) + } +} + impl Encodeable for u32 { fn encode(&self, mut encoder: E) -> Result<(), Error> { encoder.encode_u32(*self) } } +impl Encodeable for u64 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u64(*self) + } +} + +impl Encodeable for u128 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_u128(*self) + } +} + +impl Encodeable for usize { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_usize(*self) + } +} + +impl Encodeable for i8 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_i8(*self) + } +} + +impl Encodeable for i16 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_i16(*self) + } +} + impl Encodeable for i32 { fn encode(&self, mut encoder: E) -> Result<(), Error> { encoder.encode_i32(*self) } } + +impl Encodeable for i64 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_i64(*self) + } +} + +impl Encodeable for i128 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_i128(*self) + } +} + +impl Encodeable for isize { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_isize(*self) + } +} + +impl Encodeable for f32 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_f32(*self) + } +} + +impl Encodeable for f64 { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_f64(*self) + } +} + +impl Encodeable for &'_ [u8] { + fn encode(&self, mut encoder: E) -> Result<(), Error> { + encoder.encode_blob(*self) + } +} + +impl<'a, T> Encode for &'a mut T +where + T: Encode, +{ + fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + T::encode_u8(self, val) + } + fn encode_u16(&mut self, val: u16) -> Result<(), Error> { + T::encode_u16(self, val) + } + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + T::encode_u32(self, val) + } + fn encode_u64(&mut self, val: u64) -> Result<(), Error> { + T::encode_u64(self, val) + } + fn encode_u128(&mut self, val: u128) -> Result<(), Error> { + T::encode_u128(self, val) + } + fn encode_usize(&mut self, val: usize) -> Result<(), Error> { + T::encode_usize(self, val) + } + + fn encode_i8(&mut self, val: i8) -> Result<(), Error> { + T::encode_i8(self, val) + } + fn encode_i16(&mut self, val: i16) -> Result<(), Error> { + T::encode_i16(self, val) + } + fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + T::encode_i32(self, val) + } + fn encode_i64(&mut self, val: i64) -> Result<(), Error> { + T::encode_i64(self, val) + } + fn encode_i128(&mut self, val: i128) -> Result<(), Error> { + T::encode_i128(self, val) + } + fn encode_isize(&mut self, val: isize) -> Result<(), Error> { + T::encode_isize(self, val) + } + + fn encode_f32(&mut self, val: f32) -> Result<(), Error> { + T::encode_f32(self, val) + } + fn encode_f64(&mut self, val: f64) -> Result<(), Error> { + T::encode_f64(self, val) + } + fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error> { + T::encode_blob(self, val) + } +} diff --git a/src/enc/mod.rs b/src/enc/mod.rs index e6c7100..4ac0329 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -1,9 +1,6 @@ use core::marker::PhantomData; -use crate::{ - config::{Config, Endian}, - error::Error, -}; +use crate::{config::Config, error::Error, int_encoding::IntEncoding}; use write::Writer; mod impls; @@ -12,25 +9,25 @@ pub mod write; pub trait Encodeable { fn encode(&self, encoder: E) -> Result<(), Error>; } + pub trait Encode { fn encode_u8(&mut self, val: u8) -> Result<(), Error>; + fn encode_u16(&mut self, val: u16) -> Result<(), Error>; fn encode_u32(&mut self, val: u32) -> Result<(), Error>; - fn encode_i32(&mut self, val: i32) -> Result<(), Error>; -} + fn encode_u64(&mut self, val: u64) -> Result<(), Error>; + fn encode_u128(&mut self, val: u128) -> Result<(), Error>; + fn encode_usize(&mut self, val: usize) -> Result<(), Error>; -impl<'a, T> Encode for &'a mut T -where - T: Encode, -{ - fn encode_u8(&mut self, val: u8) -> Result<(), Error> { - T::encode_u8(self, val) - } - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { - T::encode_u32(self, val) - } - fn encode_i32(&mut self, val: i32) -> Result<(), Error> { - T::encode_i32(self, val) - } + fn encode_i8(&mut self, val: i8) -> Result<(), Error>; + fn encode_i16(&mut self, val: i16) -> Result<(), Error>; + fn encode_i32(&mut self, val: i32) -> Result<(), Error>; + fn encode_i64(&mut self, val: i64) -> Result<(), Error>; + fn encode_i128(&mut self, val: i128) -> Result<(), Error>; + fn encode_isize(&mut self, val: isize) -> Result<(), Error>; + + fn encode_f32(&mut self, val: f32) -> Result<(), Error>; + fn encode_f64(&mut self, val: f64) -> Result<(), Error>; + fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error>; } pub struct Encoder { @@ -56,21 +53,60 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { self.writer.write(&[val]) } - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { - let bytes = match C::ENDIAN { - Endian::Little => val.to_le_bytes(), - Endian::Big => val.to_be_bytes(), - }; + fn encode_u16(&mut self, val: u16) -> Result<(), Error> { + ::int_encode_u16(&mut self.writer, C::ENDIAN, val) + } - self.writer.write(&bytes) + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + ::int_encode_u32(&mut self.writer, C::ENDIAN, val) + } + + fn encode_u64(&mut self, val: u64) -> Result<(), Error> { + ::int_encode_u64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_u128(&mut self, val: u128) -> Result<(), Error> { + ::int_encode_u128(&mut self.writer, C::ENDIAN, val) + } + + fn encode_usize(&mut self, val: usize) -> Result<(), Error> { + ::int_encode_usize(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i8(&mut self, val: i8) -> Result<(), Error> { + self.writer.write(&[val as u8]) + } + + fn encode_i16(&mut self, val: i16) -> Result<(), Error> { + ::int_encode_i16(&mut self.writer, C::ENDIAN, val) } fn encode_i32(&mut self, val: i32) -> Result<(), Error> { - let bytes = match C::ENDIAN { - Endian::Little => val.to_le_bytes(), - Endian::Big => val.to_be_bytes(), - }; + ::int_encode_i32(&mut self.writer, C::ENDIAN, val) + } - self.writer.write(&bytes) + fn encode_i64(&mut self, val: i64) -> Result<(), Error> { + ::int_encode_i64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i128(&mut self, val: i128) -> Result<(), Error> { + ::int_encode_i128(&mut self.writer, C::ENDIAN, val) + } + + fn encode_isize(&mut self, val: isize) -> Result<(), Error> { + ::int_encode_isize(&mut self.writer, C::ENDIAN, val) + } + + fn encode_f32(&mut self, val: f32) -> Result<(), Error> { + ::int_encode_f32(&mut self.writer, C::ENDIAN, val) + } + + fn encode_f64(&mut self, val: f64) -> Result<(), Error> { + ::int_encode_f64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error> { + // TODO: Should this be swapped if we're big or little endian? + self.writer.write(val) } } diff --git a/src/int_encoding.rs b/src/int_encoding.rs index f3117ed..ba6622e 100644 --- a/src/int_encoding.rs +++ b/src/int_encoding.rs @@ -1,8 +1,120 @@ -use crate::{enc::write::Writer, error::Error}; +use crate::{config::Endian, enc::write::Writer, error::Error}; pub trait IntEncoding { - fn encode_u32(writer: &mut W, val: u32) -> Result<(), Error>; + 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()), + } + } +} From 6802edc62584fed12ea34f6cb5a25632bc4e289b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 08:30:28 +0200 Subject: [PATCH 10/80] Renamed blob to slice --- src/enc/impls.rs | 6 +++--- src/enc/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/enc/impls.rs b/src/enc/impls.rs index cb800a9..d443fe5 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -87,7 +87,7 @@ impl Encodeable for f64 { impl Encodeable for &'_ [u8] { fn encode(&self, mut encoder: E) -> Result<(), Error> { - encoder.encode_blob(*self) + encoder.encode_slice(*self) } } @@ -139,7 +139,7 @@ where fn encode_f64(&mut self, val: f64) -> Result<(), Error> { T::encode_f64(self, val) } - fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error> { - T::encode_blob(self, val) + fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { + T::encode_slice(self, val) } } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index 4ac0329..b7cb40f 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -27,7 +27,7 @@ pub trait Encode { fn encode_f32(&mut self, val: f32) -> Result<(), Error>; fn encode_f64(&mut self, val: f64) -> Result<(), Error>; - fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error>; + fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error>; } pub struct Encoder { @@ -105,7 +105,7 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { ::int_encode_f64(&mut self.writer, C::ENDIAN, val) } - fn encode_blob(&mut self, val: &[u8]) -> Result<(), Error> { + fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { // TODO: Should this be swapped if we're big or little endian? self.writer.write(val) } From 7448b7bb87a9467a54609726bf42f7d00ae44e71 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 08:34:14 +0200 Subject: [PATCH 11/80] Moved Encoder to its own file --- src/enc/encoder.rs | 85 ++++++++++++++++++++++++++++++++++++++++++ src/enc/mod.rs | 92 +++------------------------------------------- 2 files changed, 91 insertions(+), 86 deletions(-) create mode 100644 src/enc/encoder.rs diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs new file mode 100644 index 0000000..6f7ea95 --- /dev/null +++ b/src/enc/encoder.rs @@ -0,0 +1,85 @@ +use super::write::Writer; +use super::Encode; +use crate::{config::Config, error::Error, int_encoding::IntEncoding}; +use core::marker::PhantomData; + +pub struct Encoder { + writer: W, + config: PhantomData, +} + +impl Encoder { + pub fn new(writer: W) -> Encoder { + Encoder { + writer, + config: PhantomData, + } + } + + pub fn into_writer(self) -> W { + self.writer + } +} + +impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { + fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + self.writer.write(&[val]) + } + + fn encode_u16(&mut self, val: u16) -> Result<(), Error> { + ::int_encode_u16(&mut self.writer, C::ENDIAN, val) + } + + fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + ::int_encode_u32(&mut self.writer, C::ENDIAN, val) + } + + fn encode_u64(&mut self, val: u64) -> Result<(), Error> { + ::int_encode_u64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_u128(&mut self, val: u128) -> Result<(), Error> { + ::int_encode_u128(&mut self.writer, C::ENDIAN, val) + } + + fn encode_usize(&mut self, val: usize) -> Result<(), Error> { + ::int_encode_usize(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i8(&mut self, val: i8) -> Result<(), Error> { + self.writer.write(&[val as u8]) + } + + fn encode_i16(&mut self, val: i16) -> Result<(), Error> { + ::int_encode_i16(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + ::int_encode_i32(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i64(&mut self, val: i64) -> Result<(), Error> { + ::int_encode_i64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_i128(&mut self, val: i128) -> Result<(), Error> { + ::int_encode_i128(&mut self.writer, C::ENDIAN, val) + } + + fn encode_isize(&mut self, val: isize) -> Result<(), Error> { + ::int_encode_isize(&mut self.writer, C::ENDIAN, val) + } + + fn encode_f32(&mut self, val: f32) -> Result<(), Error> { + ::int_encode_f32(&mut self.writer, C::ENDIAN, val) + } + + fn encode_f64(&mut self, val: f64) -> Result<(), Error> { + ::int_encode_f64(&mut self.writer, C::ENDIAN, val) + } + + fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { + // TODO: Should this be swapped if we're big or little endian? + self.writer.write(val) + } +} diff --git a/src/enc/mod.rs b/src/enc/mod.rs index b7cb40f..0d1906d 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -1,11 +1,12 @@ -use core::marker::PhantomData; - -use crate::{config::Config, error::Error, int_encoding::IntEncoding}; -use write::Writer; - +mod encoder; mod impls; + +use crate::error::Error; + pub mod write; +pub use self::encoder::Encoder; + pub trait Encodeable { fn encode(&self, encoder: E) -> Result<(), Error>; } @@ -29,84 +30,3 @@ pub trait Encode { fn encode_f64(&mut self, val: f64) -> Result<(), Error>; fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error>; } - -pub struct Encoder { - writer: W, - config: PhantomData, -} - -impl Encoder { - pub fn new(writer: W) -> Encoder { - Encoder { - writer, - config: PhantomData, - } - } - - pub fn into_writer(self) -> W { - self.writer - } -} - -impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { - fn encode_u8(&mut self, val: u8) -> Result<(), Error> { - self.writer.write(&[val]) - } - - fn encode_u16(&mut self, val: u16) -> Result<(), Error> { - ::int_encode_u16(&mut self.writer, C::ENDIAN, val) - } - - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { - ::int_encode_u32(&mut self.writer, C::ENDIAN, val) - } - - fn encode_u64(&mut self, val: u64) -> Result<(), Error> { - ::int_encode_u64(&mut self.writer, C::ENDIAN, val) - } - - fn encode_u128(&mut self, val: u128) -> Result<(), Error> { - ::int_encode_u128(&mut self.writer, C::ENDIAN, val) - } - - fn encode_usize(&mut self, val: usize) -> Result<(), Error> { - ::int_encode_usize(&mut self.writer, C::ENDIAN, val) - } - - fn encode_i8(&mut self, val: i8) -> Result<(), Error> { - self.writer.write(&[val as u8]) - } - - fn encode_i16(&mut self, val: i16) -> Result<(), Error> { - ::int_encode_i16(&mut self.writer, C::ENDIAN, val) - } - - fn encode_i32(&mut self, val: i32) -> Result<(), Error> { - ::int_encode_i32(&mut self.writer, C::ENDIAN, val) - } - - fn encode_i64(&mut self, val: i64) -> Result<(), Error> { - ::int_encode_i64(&mut self.writer, C::ENDIAN, val) - } - - fn encode_i128(&mut self, val: i128) -> Result<(), Error> { - ::int_encode_i128(&mut self.writer, C::ENDIAN, val) - } - - fn encode_isize(&mut self, val: isize) -> Result<(), Error> { - ::int_encode_isize(&mut self.writer, C::ENDIAN, val) - } - - fn encode_f32(&mut self, val: f32) -> Result<(), Error> { - ::int_encode_f32(&mut self.writer, C::ENDIAN, val) - } - - fn encode_f64(&mut self, val: f64) -> Result<(), Error> { - ::int_encode_f64(&mut self.writer, C::ENDIAN, val) - } - - fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { - // TODO: Should this be swapped if we're big or little endian? - self.writer.write(val) - } -} From 723bdd312aebe73ab9324557337c2608c99db030 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 09:25:47 +0200 Subject: [PATCH 12/80] 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]); } From 446eb2367bb807c655279f68e8604845bcfeeb6a Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 09:35:46 +0200 Subject: [PATCH 13/80] Disabled rust 1.41 CI check --- .github/workflows/rust.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 24b29a7..6b8a4ef 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,8 +25,8 @@ "rust": [ "stable", "beta", - "nightly", - "1.41.0" + "nightly" + # "1.55.0" TODO: Pick latest stable version when we release 2.0 ] } }, @@ -72,6 +72,7 @@ "stable", "beta", "nightly" + # "1.55.0" TODO: Pick latest stable version when we release 2.0 ] } }, From 715c9c657782f65c83980fb3955026e28cca356a Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 09:48:37 +0200 Subject: [PATCH 14/80] Re-enabled tarpaulin --- .github/workflows/rust.yml | 80 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6b8a4ef..a7974c1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,7 +4,7 @@ "push": { "branches": [ "trunk", - "feature/deserde", # Temporary while we work on deserde + "feature/deserde*", # Temporary while we work on deserde "v*.x" ] }, @@ -134,46 +134,44 @@ "name": "Run `cargo clippy`" } ] + }, + "coverage": { + "name": "Code Coverage", + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "nightly", + "override": true + }, + "name": "Install Rust nightly" + }, + { + "name": "Run cargo-tarpaulin", + "uses": "actions-rs/tarpaulin@v0.1", + "with": { + "version": "0.18.2" + } + }, + { + "name": "Upload to codecov.io", + "uses": "codecov/codecov-action@v1" + }, + { + "name": "Archive code coverage results", + "uses": "actions/upload-artifact@v1", + "with": { + "name": "code-coverage-report", + "path": "cobertura.xml" + } + } + ] } - # Tarpaulin seems to not work with bincode_derive - # "coverage": { - # "name": "Code Coverage", - # "runs-on": "ubuntu-latest", - # "steps": [ - # { - # "uses": "actions/checkout@v2", - # "name": "Checkout" - # }, - # { - # "uses": "actions-rs/toolchain@v1", - # "with": { - # "profile": "minimal", - # "toolchain": "nightly", - # "override": true - # }, - # "name": "Install Rust nightly" - # }, - # { - # "name": "Run cargo-tarpaulin", - # "uses": "actions-rs/tarpaulin@v0.1", - # "with": { - # "version": "0.18.2", - # "args": "--ignore-tests -- --test-threads 1" - # } - # }, - # { - # "name": "Upload to codecov.io", - # "uses": "codecov/codecov-action@v1" - # }, - # { - # "name": "Archive code coverage results", - # "uses": "actions/upload-artifact@v1", - # "with": { - # "name": "code-coverage-report", - # "path": "cobertura.xml" - # } - # } - # ] - # } } } From ccca6ee49ea328c6df17bf53650f885af228dd49 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 10:52:21 +0200 Subject: [PATCH 15/80] Split Error into EncodeError and DecodeError --- derive/src/derive_struct.rs | 2 +- src/de/impls.rs | 4 +- src/de/mod.rs | 8 +-- src/de/read.rs | 16 ++--- src/enc/encoder.rs | 52 ++++++++-------- src/enc/impls.rs | 62 +++++++++---------- src/enc/mod.rs | 34 +++++----- src/enc/write.rs | 8 +-- src/error.rs | 25 +++++++- src/lib.rs | 6 +- .../signed.rs => varint/encode_signed.rs} | 24 +++++-- .../unsigned.rs => varint/encode_unsigned.rs} | 24 +++++-- src/{varint_encoding => varint}/mod.rs | 8 +-- 13 files changed, 160 insertions(+), 113 deletions(-) rename src/{varint_encoding/signed.rs => varint/encode_signed.rs} (79%) rename src/{varint_encoding/unsigned.rs => varint/encode_unsigned.rs} (96%) rename src/{varint_encoding => varint}/mod.rs (79%) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 0bb7de3..7f922e9 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -41,7 +41,7 @@ impl DeriveStruct { let result = quote! { impl bincode::enc::Encodeable for #name { - fn encode(&self, mut encoder: E) -> Result<(), bincode::error::Error> { + fn encode(&self, mut encoder: E) -> Result<(), bincode::error::EncodeError> { #(#fields)* Ok(()) } diff --git a/src/de/impls.rs b/src/de/impls.rs index 265b664..da515f3 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,8 +1,8 @@ use super::{Decodable, Decode}; -use crate::error::Error; +use crate::error::DecodeError; impl Decodable for u32 { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { decoder.decode_u32() } } diff --git a/src/de/mod.rs b/src/de/mod.rs index b97152c..0295e58 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use crate::{ config::{Config, Endian}, - error::Error, + error::DecodeError, }; use read::Reader; @@ -10,11 +10,11 @@ mod impls; pub mod read; pub trait Decodable: Sized { - fn decode(decoder: D) -> Result; + fn decode(decoder: D) -> Result; } pub trait Decode { - fn decode_u32(&mut self) -> Result; + fn decode_u32(&mut self) -> Result; } pub struct Decoder { @@ -32,7 +32,7 @@ impl<'de, R: Reader<'de>, C: Config> Decoder { } impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u32(&mut self) -> Result { + fn decode_u32(&mut self) -> Result { let mut bytes = [0u8; 4]; self.reader.read(bytes.as_mut())?; diff --git a/src/de/read.rs b/src/de/read.rs index f9cd893..f78fcf0 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -1,8 +1,8 @@ -use crate::error::Error; +use crate::error::DecodeError; pub trait Reader<'storage> { - fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error>; - fn forward_read(&mut self, length: usize, visitor: F) -> Result + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>; + fn forward_read(&mut self, length: usize, visitor: F) -> Result where F: Fn(&'storage [u8]) -> R; } @@ -18,9 +18,9 @@ impl<'storage> SliceReader<'storage> { } #[inline(always)] - fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8], Error> { + fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8], DecodeError> { if length > self.slice.len() { - return Err(Error::UnexpectedEnd); + return Err(DecodeError::UnexpectedEnd); } let (read_slice, remaining) = self.slice.split_at(length); self.slice = remaining; @@ -30,9 +30,9 @@ impl<'storage> SliceReader<'storage> { impl<'storage> Reader<'storage> for SliceReader<'storage> { #[inline(always)] - fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { if bytes.len() > self.slice.len() { - return Err(Error::UnexpectedEnd); + return Err(DecodeError::UnexpectedEnd); } let (read_slice, remaining) = self.slice.split_at(bytes.len()); bytes.copy_from_slice(read_slice); @@ -42,7 +42,7 @@ impl<'storage> Reader<'storage> for SliceReader<'storage> { } #[inline(always)] - fn forward_read(&mut self, length: usize, visitor: F) -> Result + fn forward_read(&mut self, length: usize, visitor: F) -> Result where F: Fn(&'storage [u8]) -> R, { diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 0fede26..524c58f 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -2,7 +2,7 @@ use super::write::Writer; use super::Encode; use crate::{ config::{Config, Endian, IntEncoding}, - error::Error, + error::EncodeError, }; use core::marker::PhantomData; @@ -25,14 +25,14 @@ impl Encoder { } impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { - fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError> { self.writer.write(&[val]) } - fn encode_u16(&mut self, val: u16) -> Result<(), Error> { + fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_u16(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_u16(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -41,10 +41,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_u32(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_u32(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -53,10 +53,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_u64(&mut self, val: u64) -> Result<(), Error> { + fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_u64(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_u64(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -65,10 +65,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_u128(&mut self, val: u128) -> Result<(), Error> { + fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_u128(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_u128(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -77,10 +77,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_usize(&mut self, val: usize) -> Result<(), Error> { + fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_usize(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_usize(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -89,14 +89,14 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_i8(&mut self, val: i8) -> Result<(), Error> { + fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError> { self.writer.write(&[val as u8]) } - fn encode_i16(&mut self, val: i16) -> Result<(), Error> { + fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_i16(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_i16(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -105,10 +105,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_i32(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_i32(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -117,10 +117,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_i64(&mut self, val: i64) -> Result<(), Error> { + fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_i64(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_i64(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -129,10 +129,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_i128(&mut self, val: i128) -> Result<(), Error> { + fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_i128(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_i128(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -141,10 +141,10 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_isize(&mut self, val: isize) -> Result<(), Error> { + fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => { - crate::varint_encoding::varint_encode_isize(&mut self.writer, C::ENDIAN, val) + crate::varint::varint_encode_isize(&mut self.writer, C::ENDIAN, val) } IntEncoding::Fixed => match C::ENDIAN { Endian::Big => self.writer.write(&val.to_be_bytes()), @@ -153,7 +153,7 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_f32(&mut self, val: f32) -> Result<(), Error> { + fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => unimplemented!(), // crate::int_encoding::varint_encode_f32(&mut self.writer, C::ENDIAN, val), IntEncoding::Fixed => match C::ENDIAN { @@ -163,7 +163,7 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_f64(&mut self, val: f64) -> Result<(), Error> { + fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError> { match C::INT_ENCODING { IntEncoding::Variable => unimplemented!(), // crate::int_encoding::varint_encode_f64(&mut self.writer, C::ENDIAN, val), IntEncoding::Fixed => match C::ENDIAN { @@ -173,7 +173,7 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } } - fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { + fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError> { // TODO: Should this be swapped if we're big or little endian? self.writer.write(val) } diff --git a/src/enc/impls.rs b/src/enc/impls.rs index d443fe5..35c9a69 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,92 +1,92 @@ use super::{Encode, Encodeable}; -use crate::error::Error; +use crate::error::EncodeError; impl Encodeable for u8 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u8(*self) } } impl Encodeable for u16 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u16(*self) } } impl Encodeable for u32 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u32(*self) } } impl Encodeable for u64 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u64(*self) } } impl Encodeable for u128 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u128(*self) } } impl Encodeable for usize { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_usize(*self) } } impl Encodeable for i8 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i8(*self) } } impl Encodeable for i16 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i16(*self) } } impl Encodeable for i32 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i32(*self) } } impl Encodeable for i64 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i64(*self) } } impl Encodeable for i128 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i128(*self) } } impl Encodeable for isize { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_isize(*self) } } impl Encodeable for f32 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_f32(*self) } } impl Encodeable for f64 { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_f64(*self) } } impl Encodeable for &'_ [u8] { - fn encode(&self, mut encoder: E) -> Result<(), Error> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_slice(*self) } } @@ -95,51 +95,51 @@ impl<'a, T> Encode for &'a mut T where T: Encode, { - fn encode_u8(&mut self, val: u8) -> Result<(), Error> { + fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError> { T::encode_u8(self, val) } - fn encode_u16(&mut self, val: u16) -> Result<(), Error> { + fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError> { T::encode_u16(self, val) } - fn encode_u32(&mut self, val: u32) -> Result<(), Error> { + fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError> { T::encode_u32(self, val) } - fn encode_u64(&mut self, val: u64) -> Result<(), Error> { + fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError> { T::encode_u64(self, val) } - fn encode_u128(&mut self, val: u128) -> Result<(), Error> { + fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError> { T::encode_u128(self, val) } - fn encode_usize(&mut self, val: usize) -> Result<(), Error> { + fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError> { T::encode_usize(self, val) } - fn encode_i8(&mut self, val: i8) -> Result<(), Error> { + fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError> { T::encode_i8(self, val) } - fn encode_i16(&mut self, val: i16) -> Result<(), Error> { + fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError> { T::encode_i16(self, val) } - fn encode_i32(&mut self, val: i32) -> Result<(), Error> { + fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError> { T::encode_i32(self, val) } - fn encode_i64(&mut self, val: i64) -> Result<(), Error> { + fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError> { T::encode_i64(self, val) } - fn encode_i128(&mut self, val: i128) -> Result<(), Error> { + fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError> { T::encode_i128(self, val) } - fn encode_isize(&mut self, val: isize) -> Result<(), Error> { + fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError> { T::encode_isize(self, val) } - fn encode_f32(&mut self, val: f32) -> Result<(), Error> { + fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError> { T::encode_f32(self, val) } - fn encode_f64(&mut self, val: f64) -> Result<(), Error> { + fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError> { T::encode_f64(self, val) } - fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error> { + fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError> { T::encode_slice(self, val) } } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index 0d1906d..ca5ebfe 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -1,32 +1,32 @@ mod encoder; mod impls; -use crate::error::Error; +use crate::error::EncodeError; pub mod write; pub use self::encoder::Encoder; pub trait Encodeable { - fn encode(&self, encoder: E) -> Result<(), Error>; + fn encode(&self, encoder: E) -> Result<(), EncodeError>; } pub trait Encode { - fn encode_u8(&mut self, val: u8) -> Result<(), Error>; - fn encode_u16(&mut self, val: u16) -> Result<(), Error>; - fn encode_u32(&mut self, val: u32) -> Result<(), Error>; - fn encode_u64(&mut self, val: u64) -> Result<(), Error>; - fn encode_u128(&mut self, val: u128) -> Result<(), Error>; - fn encode_usize(&mut self, val: usize) -> Result<(), Error>; + fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError>; + fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError>; + fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError>; + fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError>; + fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError>; + fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError>; - fn encode_i8(&mut self, val: i8) -> Result<(), Error>; - fn encode_i16(&mut self, val: i16) -> Result<(), Error>; - fn encode_i32(&mut self, val: i32) -> Result<(), Error>; - fn encode_i64(&mut self, val: i64) -> Result<(), Error>; - fn encode_i128(&mut self, val: i128) -> Result<(), Error>; - fn encode_isize(&mut self, val: isize) -> Result<(), Error>; + fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError>; + fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError>; + fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError>; + fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError>; + fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError>; + fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError>; - fn encode_f32(&mut self, val: f32) -> Result<(), Error>; - fn encode_f64(&mut self, val: f64) -> Result<(), Error>; - fn encode_slice(&mut self, val: &[u8]) -> Result<(), Error>; + fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError>; + fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError>; + fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError>; } diff --git a/src/enc/write.rs b/src/enc/write.rs index 1f8d6e7..1b6e8f7 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -1,7 +1,7 @@ -use crate::error::Error; +use crate::error::EncodeError; pub trait Writer { - fn write(&mut self, bytes: &[u8]) -> Result<(), Error>; + fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>; } pub struct SliceWriter<'storage> { @@ -23,10 +23,10 @@ impl<'storage> SliceWriter<'storage> { } impl<'storage> Writer for SliceWriter<'storage> { - fn write(&mut self, bytes: &[u8]) -> Result<(), Error> { + fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { let remaining = &mut self.slice[self.idx..]; if bytes.len() > remaining.len() { - return Err(Error::UnexpectedEnd); + return Err(EncodeError::UnexpectedEnd); } self.idx += bytes.len(); let write_slice = &mut remaining[..bytes.len()]; diff --git a/src/error.rs b/src/error.rs index 2e3cc60..7ade7fc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,29 @@ #[non_exhaustive] #[derive(Debug)] -pub enum Error { +pub enum EncodeError { InvalidIntEncoding, UnexpectedEnd, } + +#[non_exhaustive] +#[derive(Debug)] +pub enum DecodeError { + UnexpectedEnd, + /// Invalid type was found. The decoder tried to read type `expected`, but found type `found` instead. + InvalidIntegerType { + /// The type that was being read from the reader + expected: IntegerType, + /// The type that was encoded in the data + found: IntegerType, + }, +} + +#[non_exhaustive] +#[derive(Debug)] +pub enum IntegerType { + U16, + U32, + U64, + U128, + USize, +} diff --git a/src/lib.rs b/src/lib.rs index 912f3ae..522f73c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,19 +22,19 @@ pub mod error; pub use bincode_derive::{Decodable, Encodable}; -pub(crate) mod varint_encoding; +pub(crate) mod varint; pub fn encode_into_slice( val: E, dst: &mut [u8], -) -> Result { +) -> Result { let writer = enc::write::SliceWriter::new(dst); let mut encoder = enc::Encoder::<_, config::Default>::new(writer); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written()) } -pub fn decode(src: &mut [u8]) -> Result { +pub fn decode(src: &mut [u8]) -> Result { let reader = de::read::SliceReader::new(src); let mut decoder = de::Decoder::<_, config::Default>::new(reader); D::decode(&mut decoder) diff --git a/src/varint_encoding/signed.rs b/src/varint/encode_signed.rs similarity index 79% rename from src/varint_encoding/signed.rs rename to src/varint/encode_signed.rs index b41f190..1f01bd3 100644 --- a/src/varint_encoding/signed.rs +++ b/src/varint/encode_signed.rs @@ -1,7 +1,11 @@ use super::{varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64}; -use crate::{config::Endian, enc::write::Writer, error::Error}; +use crate::{config::Endian, enc::write::Writer, error::EncodeError}; -pub fn varint_encode_i16(writer: &mut W, endian: Endian, val: i16) -> Result<(), Error> { +pub fn varint_encode_i16( + writer: &mut W, + endian: Endian, + val: i16, +) -> Result<(), EncodeError> { varint_encode_u16( writer, endian, @@ -16,7 +20,11 @@ pub fn varint_encode_i16(writer: &mut W, endian: Endian, val: i16) -> ) } -pub fn varint_encode_i32(writer: &mut W, endian: Endian, val: i32) -> Result<(), Error> { +pub fn varint_encode_i32( + writer: &mut W, + endian: Endian, + val: i32, +) -> Result<(), EncodeError> { varint_encode_u32( writer, endian, @@ -31,7 +39,11 @@ pub fn varint_encode_i32(writer: &mut W, endian: Endian, val: i32) -> ) } -pub fn varint_encode_i64(writer: &mut W, endian: Endian, val: i64) -> Result<(), Error> { +pub fn varint_encode_i64( + writer: &mut W, + endian: Endian, + val: i64, +) -> Result<(), EncodeError> { varint_encode_u64( writer, endian, @@ -50,7 +62,7 @@ pub fn varint_encode_i128( writer: &mut W, endian: Endian, val: i128, -) -> Result<(), Error> { +) -> Result<(), EncodeError> { varint_encode_u128( writer, endian, @@ -69,7 +81,7 @@ pub fn varint_encode_isize( writer: &mut W, endian: Endian, val: isize, -) -> Result<(), Error> { +) -> Result<(), EncodeError> { // isize is being encoded as a i64 varint_encode_i64(writer, endian, val as i64) } diff --git a/src/varint_encoding/unsigned.rs b/src/varint/encode_unsigned.rs similarity index 96% rename from src/varint_encoding/unsigned.rs rename to src/varint/encode_unsigned.rs index 99ba53f..6c1138d 100644 --- a/src/varint_encoding/unsigned.rs +++ b/src/varint/encode_unsigned.rs @@ -1,7 +1,11 @@ use super::{SINGLE_BYTE_MAX, U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE}; -use crate::{config::Endian, enc::write::Writer, error::Error}; +use crate::{config::Endian, enc::write::Writer, error::EncodeError}; -pub fn varint_encode_u16(writer: &mut W, endian: Endian, val: u16) -> Result<(), Error> { +pub fn varint_encode_u16( + writer: &mut W, + endian: Endian, + val: u16, +) -> Result<(), EncodeError> { if val <= SINGLE_BYTE_MAX as _ { writer.write(&[val as u8]) } else { @@ -13,7 +17,11 @@ pub fn varint_encode_u16(writer: &mut W, endian: Endian, val: u16) -> } } -pub fn varint_encode_u32(writer: &mut W, endian: Endian, val: u32) -> Result<(), Error> { +pub fn varint_encode_u32( + writer: &mut W, + endian: Endian, + val: u32, +) -> Result<(), EncodeError> { if val <= SINGLE_BYTE_MAX as _ { writer.write(&[val as u8]) } else if val <= u16::MAX as _ { @@ -31,7 +39,11 @@ pub fn varint_encode_u32(writer: &mut W, endian: Endian, val: u32) -> } } -pub fn varint_encode_u64(writer: &mut W, endian: Endian, val: u64) -> Result<(), Error> { +pub fn varint_encode_u64( + writer: &mut W, + endian: Endian, + val: u64, +) -> Result<(), EncodeError> { if val <= SINGLE_BYTE_MAX as _ { writer.write(&[val as u8]) } else if val <= u16::MAX as _ { @@ -59,7 +71,7 @@ pub fn varint_encode_u128( writer: &mut W, endian: Endian, val: u128, -) -> Result<(), Error> { +) -> Result<(), EncodeError> { if val <= SINGLE_BYTE_MAX as _ { writer.write(&[val as u8]) } else if val <= u16::MAX as _ { @@ -93,7 +105,7 @@ pub fn varint_encode_usize( writer: &mut W, endian: Endian, val: usize, -) -> Result<(), Error> { +) -> Result<(), EncodeError> { // usize is being encoded as a u64 varint_encode_u64(writer, endian, val as u64) } diff --git a/src/varint_encoding/mod.rs b/src/varint/mod.rs similarity index 79% rename from src/varint_encoding/mod.rs rename to src/varint/mod.rs index d25f3a0..f6e761f 100644 --- a/src/varint_encoding/mod.rs +++ b/src/varint/mod.rs @@ -1,11 +1,11 @@ -mod signed; -mod unsigned; +mod encode_signed; +mod encode_unsigned; -pub use self::signed::{ +pub use self::encode_signed::{ varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64, varint_encode_isize, }; -pub use self::unsigned::{ +pub use self::encode_unsigned::{ varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64, varint_encode_usize, }; From ca353b98828b88915b0f145b65db1469b6a43cba Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 10:53:07 +0200 Subject: [PATCH 16/80] Added decode_unsigned --- src/varint/decode_unsigned.rs | 288 ++++++++++++++++++++++++++++++++++ src/varint/mod.rs | 5 + 2 files changed, 293 insertions(+) create mode 100644 src/varint/decode_unsigned.rs diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs new file mode 100644 index 0000000..fcb7379 --- /dev/null +++ b/src/varint/decode_unsigned.rs @@ -0,0 +1,288 @@ +use super::{U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE}; +use crate::{ + config::Endian, + de::read::Reader, + error::{DecodeError, IntegerType}, +}; + +#[allow(dead_code)] +pub fn varint_decode_u16<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + let mut byte = [0u8; 1]; + read.read(&mut byte)?; + match byte[0] { + U16_BYTE => { + let mut bytes = [0u8; 2]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u16::from_be_bytes(bytes), + Endian::Little => u16::from_le_bytes(bytes), + }) + } + U32_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U32, + }), + U64_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U64, + }), + U128_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U128, + }), + x => Ok(x as u16), + } +} + +#[allow(dead_code)] +pub fn varint_decode_u32<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + let mut byte = [0u8; 1]; + read.read(&mut byte)?; + match byte[0] { + U16_BYTE => { + let mut bytes = [0u8; 2]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u16::from_be_bytes(bytes) as u32, + Endian::Little => u16::from_le_bytes(bytes) as u32, + }) + } + U32_BYTE => { + let mut bytes = [0u8; 4]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u32::from_be_bytes(bytes), + Endian::Little => u32::from_le_bytes(bytes), + }) + } + U64_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U32, + found: IntegerType::U64, + }), + U128_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U32, + found: IntegerType::U128, + }), + x => Ok(x as u32), + } +} + +#[allow(dead_code)] +pub fn varint_decode_u64<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + let mut byte = [0u8; 1]; + read.read(&mut byte)?; + match byte[0] { + U16_BYTE => { + let mut bytes = [0u8; 2]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u16::from_be_bytes(bytes) as u64, + Endian::Little => u16::from_le_bytes(bytes) as u64, + }) + } + U32_BYTE => { + let mut bytes = [0u8; 4]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u32::from_be_bytes(bytes) as u64, + Endian::Little => u32::from_le_bytes(bytes) as u64, + }) + } + U64_BYTE => { + let mut bytes = [0u8; 8]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u64::from_be_bytes(bytes), + Endian::Little => u64::from_le_bytes(bytes), + }) + } + U128_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::U64, + found: IntegerType::U128, + }), + x => Ok(x as u64), + } +} + +#[allow(dead_code)] +pub fn varint_decode_usize<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + let mut byte = [0u8; 1]; + read.read(&mut byte)?; + match byte[0] { + U16_BYTE => { + let mut bytes = [0u8; 2]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u16::from_be_bytes(bytes) as usize, + Endian::Little => u16::from_le_bytes(bytes) as usize, + }) + } + U32_BYTE => { + let mut bytes = [0u8; 4]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u32::from_be_bytes(bytes) as usize, + Endian::Little => u32::from_le_bytes(bytes) as usize, + }) + } + U64_BYTE => { + let mut bytes = [0u8; 8]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u64::from_be_bytes(bytes) as usize, + Endian::Little => u64::from_le_bytes(bytes) as usize, + }) + } + U128_BYTE => Err(DecodeError::InvalidIntegerType { + expected: IntegerType::USize, + found: IntegerType::U128, + }), + x => Ok(x as usize), + } +} + +#[allow(dead_code)] +pub fn varint_decode_u128<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + let mut byte = [0u8; 1]; + read.read(&mut byte)?; + match byte[0] { + U16_BYTE => { + let mut bytes = [0u8; 2]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u16::from_be_bytes(bytes) as u128, + Endian::Little => u16::from_le_bytes(bytes) as u128, + }) + } + U32_BYTE => { + let mut bytes = [0u8; 4]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u32::from_be_bytes(bytes) as u128, + Endian::Little => u32::from_le_bytes(bytes) as u128, + }) + } + U64_BYTE => { + let mut bytes = [0u8; 8]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u64::from_be_bytes(bytes) as u128, + Endian::Little => u64::from_le_bytes(bytes) as u128, + }) + } + U128_BYTE => { + let mut bytes = [0u8; 16]; + read.read(&mut bytes)?; + Ok(match endian { + Endian::Big => u128::from_be_bytes(bytes), + Endian::Little => u128::from_le_bytes(bytes), + }) + } + x => Ok(x as u128), + } +} + +#[test] +fn test_decode_u16() { + let cases: &[(&[u8], u16, u16)] = &[ + (&[0], 0, 0), + (&[10], 10, 10), + (&[U16_BYTE, 0, 10], 2560, 10), + ]; + for &(slice, expected_le, expected_be) in cases { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u16(&mut reader, Endian::Little).unwrap(); + assert_eq!(expected_le, found); + + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u16(&mut reader, Endian::Big).unwrap(); + assert_eq!(expected_be, found); + } +} + +#[test] +fn test_decode_u32() { + let cases: &[(&[u8], u32, u32)] = &[ + (&[0], 0, 0), + (&[10], 10, 10), + (&[U16_BYTE, 0, 10], 2560, 10), + (&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10), + ]; + for &(slice, expected_le, expected_be) in cases { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u32(&mut reader, Endian::Little).unwrap(); + assert_eq!(expected_le, found); + + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u32(&mut reader, Endian::Big).unwrap(); + assert_eq!(expected_be, found); + } +} + +#[test] +fn test_decode_u64() { + let cases: &[(&[u8], u64, u64)] = &[ + (&[0], 0, 0), + (&[10], 10, 10), + (&[U16_BYTE, 0, 10], 2560, 10), + (&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10), + ( + &[U64_BYTE, 0, 0, 0, 0, 0, 0, 0, 10], + 72_057_594_037_9279_360, + 10, + ), + ]; + for &(slice, expected_le, expected_be) in cases { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u64(&mut reader, Endian::Little).unwrap(); + assert_eq!(expected_le, found); + + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u64(&mut reader, Endian::Big).unwrap(); + assert_eq!(expected_be, found); + } +} + +#[test] +fn test_decode_u128() { + let cases: &[(&[u8], u128, u128)] = &[ + (&[0], 0, 0), + (&[10], 10, 10), + (&[U16_BYTE, 0, 10], 2560, 10), + (&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10), + ( + &[U64_BYTE, 0, 0, 0, 0, 0, 0, 0, 10], + 72_057_594_037_9279_360, + 10, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10], + 13_292_279_957_849_158_729_038_070_602_803_445_760, + 10, + ), + ]; + for &(slice, expected_le, expected_be) in cases { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u128(&mut reader, Endian::Little).unwrap(); + assert_eq!(expected_le, found); + + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u128(&mut reader, Endian::Big).unwrap(); + assert_eq!(expected_be, found); + } +} diff --git a/src/varint/mod.rs b/src/varint/mod.rs index f6e761f..54d19e5 100644 --- a/src/varint/mod.rs +++ b/src/varint/mod.rs @@ -1,6 +1,11 @@ +mod decode_unsigned; mod encode_signed; mod encode_unsigned; +pub use self::decode_unsigned::{ + varint_decode_u128, varint_decode_u16, varint_decode_u32, varint_decode_u64, + varint_decode_usize, +}; pub use self::encode_signed::{ varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64, varint_encode_isize, From 1313e989adee29b4050de633ade568443b17997b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 11:02:33 +0200 Subject: [PATCH 17/80] Added unit tests for decoding errors --- src/varint/decode_unsigned.rs | 154 ++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index fcb7379..24d60d6 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -213,6 +213,38 @@ fn test_decode_u16() { let found = varint_decode_u16(&mut reader, Endian::Big).unwrap(); assert_eq!(expected_be, found); } + + let errors: &[(&[u8], DecodeError)] = &[ + ( + &[U32_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U32, + }, + ), + ( + &[U64_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U64, + }, + ), + ( + &[U128_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U16, + found: IntegerType::U128, + }, + ), + (&[U16_BYTE], DecodeError::UnexpectedEnd), + (&[U16_BYTE, 0], DecodeError::UnexpectedEnd), + ]; + + for (slice, expected) in errors { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u16(&mut reader, Endian::Little).unwrap_err(); + assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found)); + } } #[test] @@ -232,6 +264,35 @@ fn test_decode_u32() { let found = varint_decode_u32(&mut reader, Endian::Big).unwrap(); assert_eq!(expected_be, found); } + + let errors: &[(&[u8], DecodeError)] = &[ + ( + &[U64_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U32, + found: IntegerType::U64, + }, + ), + ( + &[U128_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U32, + found: IntegerType::U128, + }, + ), + (&[U16_BYTE], DecodeError::UnexpectedEnd), + (&[U16_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + ]; + + for (slice, expected) in errors { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u32(&mut reader, Endian::Little).unwrap_err(); + assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found)); + } } #[test] @@ -256,6 +317,36 @@ fn test_decode_u64() { let found = varint_decode_u64(&mut reader, Endian::Big).unwrap(); assert_eq!(expected_be, found); } + + let errors: &[(&[u8], DecodeError)] = &[ + ( + &[U128_BYTE], + DecodeError::InvalidIntegerType { + expected: IntegerType::U64, + found: IntegerType::U128, + }, + ), + (&[U16_BYTE], DecodeError::UnexpectedEnd), + (&[U16_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + ]; + + for (slice, expected) in errors { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u64(&mut reader, Endian::Little).unwrap_err(); + assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found)); + } } #[test] @@ -285,4 +376,67 @@ fn test_decode_u128() { let found = varint_decode_u128(&mut reader, Endian::Big).unwrap(); assert_eq!(expected_be, found); } + + let errors: &[(&[u8], DecodeError)] = &[ + (&[U16_BYTE], DecodeError::UnexpectedEnd), + (&[U16_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U32_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + (&[U128_BYTE, 0, 0, 0, 0, 0, 0], DecodeError::UnexpectedEnd), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ( + &[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + DecodeError::UnexpectedEnd, + ), + ]; + + for (slice, expected) in errors { + let mut reader = crate::de::read::SliceReader::new(slice); + let found = varint_decode_u128(&mut reader, Endian::Little).unwrap_err(); + std::dbg!(slice); + assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found)); + } } From f914b3e580f28dcee80dfff45c1793736edb7632 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 19 Sep 2021 11:24:42 +0200 Subject: [PATCH 18/80] Added unit tests for encode_signed --- src/varint/encode_signed.rs | 219 +++++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 4 deletions(-) diff --git a/src/varint/encode_signed.rs b/src/varint/encode_signed.rs index 1f01bd3..0afa11c 100644 --- a/src/varint/encode_signed.rs +++ b/src/varint/encode_signed.rs @@ -88,20 +88,231 @@ pub fn varint_encode_isize( #[test] fn test_encode_i16() { - // TODO + let cases: &[(i16, &[u8], &[u8])] = &[ + (0, &[0], &[0]), + (2, &[4], &[4]), + (256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]), + ( + 16_000, + &[super::U16_BYTE, 0, 125], + &[super::U16_BYTE, 125, 0], + ), + ( + i16::MAX - 1, + &[super::U16_BYTE, 252, 255], + &[super::U16_BYTE, 255, 252], + ), + ( + i16::MAX, + &[super::U16_BYTE, 254, 255], + &[super::U16_BYTE, 255, 254], + ), + ]; + + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + for &(value, expected_le, expected_be) in cases { + std::dbg!(value); + + // Little endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i16(&mut writer, Endian::Little, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_le.len()); + assert_eq!(&buffer[..expected_le.len()], expected_le); + + // Big endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i16(&mut writer, Endian::Big, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_be.len()); + assert_eq!(&buffer[..expected_be.len()], expected_be); + } } #[test] fn test_encode_i32() { - // TODO + let cases: &[(i32, &[u8], &[u8])] = &[ + (0, &[0], &[0]), + (2, &[4], &[4]), + (256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]), + ( + 16_000, + &[super::U16_BYTE, 0, 125], + &[super::U16_BYTE, 125, 0], + ), + ( + 40_000, + &[super::U32_BYTE, 128, 56, 1, 0], + &[super::U32_BYTE, 0, 1, 56, 128], + ), + ( + i32::MAX - 1, + &[super::U32_BYTE, 252, 255, 255, 255], + &[super::U32_BYTE, 255, 255, 255, 252], + ), + ( + i32::MAX, + &[super::U32_BYTE, 254, 255, 255, 255], + &[super::U32_BYTE, 255, 255, 255, 254], + ), + ]; + + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + for &(value, expected_le, expected_be) in cases { + std::dbg!(value); + + // Little endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i32(&mut writer, Endian::Little, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_le.len()); + assert_eq!(&buffer[..expected_le.len()], expected_le); + + // Big endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i32(&mut writer, Endian::Big, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_be.len()); + assert_eq!(&buffer[..expected_be.len()], expected_be); + } } #[test] fn test_encode_i64() { - // TODO + let cases: &[(i64, &[u8], &[u8])] = &[ + (0, &[0], &[0]), + (2, &[4], &[4]), + (256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]), + ( + 16_000, + &[super::U16_BYTE, 0, 125], + &[super::U16_BYTE, 125, 0], + ), + ( + 40_000, + &[super::U32_BYTE, 128, 56, 1, 0], + &[super::U32_BYTE, 0, 1, 56, 128], + ), + ( + 3_000_000_000, + &[super::U64_BYTE, 0, 188, 160, 101, 1, 0, 0, 0], + &[super::U64_BYTE, 0, 0, 0, 1, 101, 160, 188, 0], + ), + ( + i64::MAX - 1, + &[super::U64_BYTE, 252, 255, 255, 255, 255, 255, 255, 255], + &[super::U64_BYTE, 255, 255, 255, 255, 255, 255, 255, 252], + ), + ( + i64::MAX, + &[super::U64_BYTE, 254, 255, 255, 255, 255, 255, 255, 255], + &[super::U64_BYTE, 255, 255, 255, 255, 255, 255, 255, 254], + ), + ]; + + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + for &(value, expected_le, expected_be) in cases { + std::dbg!(value); + + // Little endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i64(&mut writer, Endian::Little, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_le.len()); + assert_eq!(&buffer[..expected_le.len()], expected_le); + + // Big endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i64(&mut writer, Endian::Big, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_be.len()); + assert_eq!(&buffer[..expected_be.len()], expected_be); + } } #[test] fn test_encode_i128() { - // TODO + #[rustfmt::skip] + let cases: &[(i128, &[u8], &[u8])] = &[ + (0, &[0], &[0]), + (2, &[4], &[4]), + (256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]), + ( + 16_000, + &[super::U16_BYTE, 0, 125], + &[super::U16_BYTE, 125, 0], + ), + ( + 40_000, + &[super::U32_BYTE, 128, 56, 1, 0], + &[super::U32_BYTE, 0, 1, 56, 128], + ), + ( + 3_000_000_000, + &[super::U64_BYTE, 0, 188, 160, 101, 1, 0, 0, 0], + &[super::U64_BYTE, 0, 0, 0, 1, 101, 160, 188, 0], + ), + ( + 11_000_000_000_000_000_000, + &[ + super::U128_BYTE, + 0, 0, 152, 98, 112, 179, 79, 49, + 1, 0, 0, 0, 0, 0, 0, 0, + ], + &[ + super::U128_BYTE, + 0, 0, 0, 0, 0, 0, 0, 1, + 49, 79, 179, 112, 98, 152, 0, 0, + ], + ), + ( + i128::MAX - 1, + &[ + super::U128_BYTE, + 252, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + ], + &[ + super::U128_BYTE, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 252, + ], + ), + ( + i128::MAX, + &[ + super::U128_BYTE, + 254, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + ], + &[ + super::U128_BYTE, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 254, + ], + ), + ]; + + use crate::enc::write::SliceWriter; + let mut buffer = [0u8; 20]; + for &(value, expected_le, expected_be) in cases { + std::dbg!(value); + + // Little endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i128(&mut writer, Endian::Little, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_le.len()); + assert_eq!(&buffer[..expected_le.len()], expected_le); + + // Big endian + let mut writer = SliceWriter::new(&mut buffer); + varint_encode_i128(&mut writer, Endian::Big, value).unwrap(); + + assert_eq!(writer.bytes_written(), expected_be.len()); + assert_eq!(&buffer[..expected_be.len()], expected_be); + } } From 8241e6c656495448c61007ac19c41376924d6773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Mon, 20 Sep 2021 15:58:16 +0200 Subject: [PATCH 19/80] Add generic bound support to derive --- derive/src/derive_struct.rs | 23 +++++++++++++++++------ derive/src/lib.rs | 6 ++++-- tests/derive.rs | 6 ++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 7f922e9..1668657 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,15 +1,16 @@ use crate::Result; use proc_macro::TokenStream; -use quote::quote; -use syn::{spanned::Spanned, Ident}; +use quote::{quote, quote_spanned}; +use syn::{spanned::Spanned, Generics, Ident}; pub struct DeriveStruct { name: Ident, + generics: Generics, fields: Vec, } impl DeriveStruct { - pub fn parse(name: Ident, str: syn::DataStruct) -> Result { + pub fn parse(name: Ident, generics: Generics, str: syn::DataStruct) -> Result { let fields = match str.fields { syn::Fields::Named(fields) => fields .named @@ -24,11 +25,21 @@ impl DeriveStruct { .collect(), syn::Fields::Unit => Vec::new(), }; - Ok(Self { name, fields }) + Ok(Self { + name, + generics, + fields, + }) } pub fn to_encodable(self) -> Result { - let DeriveStruct { name, fields } = self; + let DeriveStruct { + name, + generics, + fields, + } = self; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let fields = fields .into_iter() @@ -40,7 +51,7 @@ impl DeriveStruct { .collect::>(); let result = quote! { - impl bincode::enc::Encodeable for #name { + impl #impl_generics bincode::enc::Encodeable for #name #ty_generics #where_clause { fn encode(&self, mut encoder: E) -> Result<(), bincode::error::EncodeError> { #(#fields)* Ok(()) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 82be10a..c9cce74 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -21,7 +21,8 @@ pub fn derive_encodable(input: TokenStream) -> TokenStream { fn derive_encodable_inner(input: DeriveInput) -> Result { match input.data { syn::Data::Struct(struct_definition) => { - DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_encodable()) + DeriveStruct::parse(input.ident, input.generics, struct_definition) + .and_then(|str| str.to_encodable()) } syn::Data::Enum(enum_definition) => { DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_encodable()) @@ -39,7 +40,8 @@ pub fn derive_decodable(input: TokenStream) -> TokenStream { fn derive_decodable_inner(input: DeriveInput) -> Result { match input.data { syn::Data::Struct(struct_definition) => { - DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_decodable()) + DeriveStruct::parse(input.ident, input.generics, struct_definition) + .and_then(|str| str.to_decodable()) } syn::Data::Enum(enum_definition) => { DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_decodable()) diff --git a/tests/derive.rs b/tests/derive.rs index 4aa0156..155925b 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,6 +1,8 @@ +use bincode::enc::Encodeable; + #[derive(bincode::Encodable, PartialEq, Debug)] -pub struct Test { - a: i32, +pub struct Test { + a: T, b: u32, c: u8, } From e414cabd33c4a3c21c24df2063672058632b5bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Mon, 20 Sep 2021 16:35:36 +0200 Subject: [PATCH 20/80] Add derive for Decodeable --- derive/src/derive_struct.rs | 29 ++++++++++++++++++++++++++++- src/de/mod.rs | 26 ++++++++++++++++++++------ tests/derive.rs | 21 ++++++++++++++++++++- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 1668657..5680850 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -63,6 +63,33 @@ impl DeriveStruct { } pub fn to_decodable(self) -> Result { - unimplemented!() + let DeriveStruct { + name, + generics, + fields, + } = self; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let fields = fields + .into_iter() + .map(|field| { + quote! { + #field: bincode::de::Decodable::decode(&mut decoder)?, + } + }) + .collect::>(); + + let result = quote! { + impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { + fn decode(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { + Ok(#name { + #(#fields)* + }) + } + + } + }; + Ok(result.into()) } } diff --git a/src/de/mod.rs b/src/de/mod.rs index 0295e58..8ee5567 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use crate::{ - config::{Config, Endian}, + config::{Config, Endian, IntEncoding}, error::DecodeError, }; use read::Reader; @@ -33,12 +33,26 @@ impl<'de, R: Reader<'de>, C: Config> Decoder { impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { fn decode_u32(&mut self) -> Result { - let mut bytes = [0u8; 4]; + Ok(match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN)?, + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; - self.reader.read(bytes.as_mut())?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), + self.reader.read(bytes.as_mut())?; + match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + } + } }) } } + +impl<'a, T> Decode for &'a mut T +where + T: Decode, +{ + fn decode_u32(&mut self) -> Result { + T::decode_u32(self) + } +} diff --git a/tests/derive.rs b/tests/derive.rs index 155925b..27c23f3 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,4 +1,4 @@ -use bincode::enc::Encodeable; +use bincode::{de::Decodable, enc::Encodeable}; #[derive(bincode::Encodable, PartialEq, Debug)] pub struct Test { @@ -7,6 +7,13 @@ pub struct Test { c: u8, } +#[derive(bincode::Decodable, PartialEq, Debug, Eq)] +pub struct Test2 { + a: T, + b: u32, + c: u32, +} + #[test] fn test_encodable() { let start = Test { @@ -19,3 +26,15 @@ fn test_encodable() { assert_eq!(bytes_written, 3); assert_eq!(&slice[..bytes_written], &[10, 10, 20]); } + +#[test] +fn test_decodable() { + let start = Test2 { + a: 5u32, + b: 10u32, + c: 1024u32, + }; + let mut slice = [5, 10, 251, 0, 4]; + let result: Test2 = bincode::decode(&mut slice).unwrap(); + assert_eq!(result, start); +} From 2d0254405b80acf7240c3185b3a04921ba5c5912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Mon, 20 Sep 2021 16:56:17 +0200 Subject: [PATCH 21/80] Add derive support for tuple structs --- derive/Cargo.toml | 1 + derive/src/derive_struct.rs | 11 ++++++----- tests/derive.rs | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 381bb9c..34d6a61 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -8,6 +8,7 @@ proc-macro = true [dependencies] quote = "1.0.9" +proc-macro2 = "1.0" [dependencies.syn] version = "1.0.74" diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 5680850..c955dd1 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,12 +1,13 @@ use crate::Result; use proc_macro::TokenStream; -use quote::{quote, quote_spanned}; -use syn::{spanned::Spanned, Generics, Ident}; +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{spanned::Spanned, Generics, Ident, Index}; pub struct DeriveStruct { name: Ident, generics: Generics, - fields: Vec, + fields: Vec, } impl DeriveStruct { @@ -15,13 +16,13 @@ impl DeriveStruct { syn::Fields::Named(fields) => fields .named .iter() - .map(|f| f.ident.clone().unwrap()) + .map(|f| f.ident.clone().unwrap().to_token_stream()) .collect(), syn::Fields::Unnamed(fields) => fields .unnamed .iter() .enumerate() - .map(|(i, field)| Ident::new(&i.to_string(), field.ty.span())) + .map(|(i, _)| Index::from(i).to_token_stream()) .collect(), syn::Fields::Unit => Vec::new(), }; diff --git a/tests/derive.rs b/tests/derive.rs index 27c23f3..e407837 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -14,6 +14,9 @@ pub struct Test2 { c: u32, } +#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +pub struct TestTupleStruct(u32, u32, u32); + #[test] fn test_encodable() { let start = Test { @@ -38,3 +41,20 @@ fn test_decodable() { let result: Test2 = bincode::decode(&mut slice).unwrap(); assert_eq!(result, start); } + +#[test] +fn test_encodable_tuple() { + let start = TestTupleStruct(5, 10, 1024); + let mut slice = [0u8; 1024]; + let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + assert_eq!(bytes_written, 5); + assert_eq!(&slice[..bytes_written], &[5, 10, 251, 0, 4]); +} + +#[test] +fn test_decodable_tuple() { + let start = TestTupleStruct(5, 10, 1024); + let mut slice = [5, 10, 251, 0, 4]; + let result: TestTupleStruct = bincode::decode(&mut slice).unwrap(); + assert_eq!(result, start); +} From c83c36333d9ecc1d2763049190bd4f5bf5ae79a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Mon, 20 Sep 2021 23:06:25 +0200 Subject: [PATCH 22/80] Add enum encode/decode derive --- derive/src/derive_enum.rs | 178 ++++++++++++++++++++++++++++++++++++-- derive/src/lib.rs | 6 +- src/error.rs | 5 ++ tests/derive.rs | 58 +++++++++++++ 4 files changed, 238 insertions(+), 9 deletions(-) diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 73c0b08..cb1d563 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,19 +1,183 @@ use crate::Result; use proc_macro::TokenStream; -use syn::Ident; - -pub struct DeriveEnum {} +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use quote::ToTokens; +use syn::{spanned::Spanned, Field, Fields, Generics, Ident, Index, Variant}; +pub struct DeriveEnum { + name: Ident, + generics: Generics, + variants: Vec, +} impl DeriveEnum { - pub fn parse(_name: Ident, _en: syn::DataEnum) -> Result { - unimplemented!() + pub fn parse(name: Ident, generics: Generics, en: syn::DataEnum) -> Result { + let variants = en.variants.into_iter().collect(); + + Ok(DeriveEnum { + name, + generics, + variants, + }) } pub fn to_encodable(self) -> Result { - unimplemented!() + let DeriveEnum { + name, + generics, + variants, + } = self; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let match_arms = variants.iter().enumerate().map(|(index, variant)| { + let fields_section = fields_to_match_arm(&variant.fields); + let encode_statements = field_names_to_encodable(&fields_to_names(&variant.fields)); + let variant_name = variant.ident.clone(); + quote! { + #name :: #variant_name #fields_section => { + encoder.encode_u32(#index as u32)?; + #(#encode_statements)* + } + } + }); + let result = quote! { + impl #impl_generics bincode::enc::Encodeable for #name #ty_generics #where_clause { + fn encode(&self, mut encoder: E) -> Result<(), bincode::error::EncodeError> { + match self { + #(#match_arms)* + } + Ok(()) + } + + } + }; + + Ok(result.into()) } pub fn to_decodable(self) -> Result { - unimplemented!() + let DeriveEnum { + name, + generics, + variants, + } = self; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let max_variant = (variants.len() - 1) as u32; + let match_arms = variants.iter().enumerate().map(|(index, variant)| { + let index = index as u32; + let decode_statements = + field_names_to_decodable(&fields_to_constructable_names(&variant.fields)); + let variant_name = variant.ident.clone(); + quote! { + #index => { + #name :: #variant_name { + #(#decode_statements)* + } + } + } + }); + let result = quote! { + impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { + fn decode(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { + let i = decoder.decode_u32()?; + Ok(match i { + #(#match_arms)* + variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ + min: 0, + max: #max_variant, + found: variant, + }) + }) + } + + } + }; + + Ok(result.into()) } } + +fn fields_to_match_arm(fields: &Fields) -> TokenStream2 { + match fields { + syn::Fields::Named(fields) => { + let fields: Vec<_> = fields + .named + .iter() + .map(|f| f.ident.clone().unwrap().to_token_stream()) + .collect(); + quote! { + {#(#fields),*} + } + } + syn::Fields::Unnamed(fields) => { + let fields: Vec<_> = fields + .unnamed + .iter() + .enumerate() + .map(|(i, f)| Ident::new(&format!("_{}", i), f.span())) + .collect(); + quote! { + (#(#fields),*) + } + } + syn::Fields::Unit => quote! {}, + } +} + +fn fields_to_names(fields: &Fields) -> Vec { + match fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .map(|f| f.ident.clone().unwrap().to_token_stream()) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .enumerate() + .map(|(i, f)| Ident::new(&format!("_{}", i), f.span()).to_token_stream()) + .collect(), + syn::Fields::Unit => Vec::new(), + } +} + +fn field_names_to_encodable(names: &[TokenStream2]) -> Vec { + names + .into_iter() + .map(|field| { + quote! { + bincode::enc::Encodeable::encode(#field, &mut encoder)?; + } + }) + .collect::>() +} + +fn fields_to_constructable_names(fields: &Fields) -> Vec { + match fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .map(|f| f.ident.clone().unwrap().to_token_stream()) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .enumerate() + .map(|(i, f)| Index::from(i).to_token_stream()) + .collect(), + syn::Fields::Unit => Vec::new(), + } +} + +fn field_names_to_decodable(names: &[TokenStream2]) -> Vec { + names + .into_iter() + .map(|field| { + quote! { + #field: bincode::de::Decodable::decode(&mut decoder)?, + } + }) + .collect::>() +} diff --git a/derive/src/lib.rs b/derive/src/lib.rs index c9cce74..2925525 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -25,7 +25,8 @@ fn derive_encodable_inner(input: DeriveInput) -> Result { .and_then(|str| str.to_encodable()) } syn::Data::Enum(enum_definition) => { - DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_encodable()) + DeriveEnum::parse(input.ident, input.generics, enum_definition) + .and_then(|str| str.to_encodable()) } syn::Data::Union(_) => Err(Error::UnionNotSupported), } @@ -44,7 +45,8 @@ fn derive_decodable_inner(input: DeriveInput) -> Result { .and_then(|str| str.to_decodable()) } syn::Data::Enum(enum_definition) => { - DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_decodable()) + DeriveEnum::parse(input.ident, input.generics, enum_definition) + .and_then(|str| str.to_decodable()) } syn::Data::Union(_) => Err(Error::UnionNotSupported), } diff --git a/src/error.rs b/src/error.rs index 7ade7fc..47340c7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,11 @@ pub enum DecodeError { /// The type that was encoded in the data found: IntegerType, }, + UnexpectedVariant { + min: u32, + max: u32, + found: u32, + }, } #[non_exhaustive] diff --git a/tests/derive.rs b/tests/derive.rs index e407837..e699aee 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -17,6 +17,13 @@ pub struct Test2 { #[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] pub struct TestTupleStruct(u32, u32, u32); +#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +pub enum TestEnum { + Foo, + Bar { name: u32 }, + Baz(u32, u32, u32), +} + #[test] fn test_encodable() { let start = Test { @@ -58,3 +65,54 @@ fn test_decodable_tuple() { let result: TestTupleStruct = bincode::decode(&mut slice).unwrap(); assert_eq!(result, start); } + +#[test] +fn test_encodable_enum_struct_variant() { + let start = TestEnum::Bar { name: 5u32 }; + let mut slice = [0u8; 1024]; + let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + assert_eq!(bytes_written, 2); + assert_eq!(&slice[..bytes_written], &[1, 5]); +} + +#[test] +fn test_decodable_enum_struct_variant() { + let start = TestEnum::Bar { name: 5u32 }; + let mut slice = [1, 5]; + let result: TestEnum = bincode::decode(&mut slice).unwrap(); + assert_eq!(result, start); +} + +#[test] +fn test_encodable_enum_tuple_variant() { + let start = TestEnum::Baz(5, 10, 1024); + let mut slice = [0u8; 1024]; + let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + assert_eq!(bytes_written, 6); + assert_eq!(&slice[..bytes_written], &[2, 5, 10, 251, 0, 4]); +} + +#[test] +fn test_decodable_enum_unit_variant() { + let start = TestEnum::Foo; + let mut slice = [0]; + let result: TestEnum = bincode::decode(&mut slice).unwrap(); + assert_eq!(result, start); +} + +#[test] +fn test_encodable_enum_unit_variant() { + let start = TestEnum::Foo; + let mut slice = [0u8; 1024]; + let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + assert_eq!(bytes_written, 1); + assert_eq!(&slice[..bytes_written], &[0]); +} + +#[test] +fn test_decodable_enum_tuple_variant() { + let start = TestEnum::Baz(5, 10, 1024); + let mut slice = [2, 5, 10, 251, 0, 4]; + let result: TestEnum = bincode::decode(&mut slice).unwrap(); + assert_eq!(result, start); +} From cffc9fcffa00177057a258e3939a115a63d5c083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Mon, 20 Sep 2021 23:20:49 +0200 Subject: [PATCH 23/80] Exclude derive from coverage --- .github/workflows/rust.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a7974c1..59c7a37 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -156,7 +156,8 @@ "name": "Run cargo-tarpaulin", "uses": "actions-rs/tarpaulin@v0.1", "with": { - "version": "0.18.2" + "version": "0.18.2", + "args": "--exclude-files derive/" } }, { From 6361ad7d69711df745fb58be5b37cf39817841bf Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 21 Sep 2021 09:57:48 +0200 Subject: [PATCH 24/80] Made clippy also check _derive, fixed clippy warnings --- Cargo.toml | 5 +++++ derive/src/derive_enum.rs | 12 ++++++------ derive/src/derive_struct.rs | 8 ++++---- derive/src/lib.rs | 8 ++++---- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51c22f0..3b9097b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,8 @@ +[workspace] +members = [ + "derive" +] + [package] name = "bincode" version = "2.0.0-dev" # remember to update html_root_url and bincode_derive diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index cb1d563..9e14519 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -3,7 +3,7 @@ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use quote::ToTokens; -use syn::{spanned::Spanned, Field, Fields, Generics, Ident, Index, Variant}; +use syn::{spanned::Spanned, Fields, Generics, Ident, Index, Variant}; pub struct DeriveEnum { name: Ident, generics: Generics, @@ -21,7 +21,7 @@ impl DeriveEnum { }) } - pub fn to_encodable(self) -> Result { + pub fn generate_encodable(self) -> Result { let DeriveEnum { name, generics, @@ -56,7 +56,7 @@ impl DeriveEnum { Ok(result.into()) } - pub fn to_decodable(self) -> Result { + pub fn generate_decodable(self) -> Result { let DeriveEnum { name, generics, @@ -145,7 +145,7 @@ fn fields_to_names(fields: &Fields) -> Vec { fn field_names_to_encodable(names: &[TokenStream2]) -> Vec { names - .into_iter() + .iter() .map(|field| { quote! { bincode::enc::Encodeable::encode(#field, &mut encoder)?; @@ -165,7 +165,7 @@ fn fields_to_constructable_names(fields: &Fields) -> Vec { .unnamed .iter() .enumerate() - .map(|(i, f)| Index::from(i).to_token_stream()) + .map(|(i, _)| Index::from(i).to_token_stream()) .collect(), syn::Fields::Unit => Vec::new(), } @@ -173,7 +173,7 @@ fn fields_to_constructable_names(fields: &Fields) -> Vec { fn field_names_to_decodable(names: &[TokenStream2]) -> Vec { names - .into_iter() + .iter() .map(|field| { quote! { #field: bincode::de::Decodable::decode(&mut decoder)?, diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index c955dd1..ff63e74 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,8 +1,8 @@ use crate::Result; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, quote_spanned, ToTokens}; -use syn::{spanned::Spanned, Generics, Ident, Index}; +use quote::{quote, ToTokens}; +use syn::{Generics, Ident, Index}; pub struct DeriveStruct { name: Ident, @@ -33,7 +33,7 @@ impl DeriveStruct { }) } - pub fn to_encodable(self) -> Result { + pub fn generate_encodable(self) -> Result { let DeriveStruct { name, generics, @@ -63,7 +63,7 @@ impl DeriveStruct { Ok(result.into()) } - pub fn to_decodable(self) -> Result { + pub fn generate_decodable(self) -> Result { let DeriveStruct { name, generics, diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 2925525..2e91110 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -22,11 +22,11 @@ fn derive_encodable_inner(input: DeriveInput) -> Result { match input.data { syn::Data::Struct(struct_definition) => { DeriveStruct::parse(input.ident, input.generics, struct_definition) - .and_then(|str| str.to_encodable()) + .and_then(|str| str.generate_encodable()) } syn::Data::Enum(enum_definition) => { DeriveEnum::parse(input.ident, input.generics, enum_definition) - .and_then(|str| str.to_encodable()) + .and_then(|str| str.generate_encodable()) } syn::Data::Union(_) => Err(Error::UnionNotSupported), } @@ -42,11 +42,11 @@ fn derive_decodable_inner(input: DeriveInput) -> Result { match input.data { syn::Data::Struct(struct_definition) => { DeriveStruct::parse(input.ident, input.generics, struct_definition) - .and_then(|str| str.to_decodable()) + .and_then(|str| str.generate_decodable()) } syn::Data::Enum(enum_definition) => { DeriveEnum::parse(input.ident, input.generics, enum_definition) - .and_then(|str| str.to_decodable()) + .and_then(|str| str.generate_decodable()) } syn::Data::Union(_) => Err(Error::UnionNotSupported), } From 78cb27f782d5a6711e7be26979a55346a60c5160 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Wed, 22 Sep 2021 09:54:09 +0200 Subject: [PATCH 25/80] Added decode_ fns --- src/de/decoder.rs | 210 ++++++++++++++++++++++++++++++++++++ src/de/impls.rs | 135 +++++++++++++++++++++++ src/de/mod.rs | 64 ++++------- src/enc/encoder.rs | 19 ++-- src/varint/decode_signed.rs | 43 ++++++++ src/varint/mod.rs | 5 + 6 files changed, 418 insertions(+), 58 deletions(-) create mode 100644 src/de/decoder.rs create mode 100644 src/varint/decode_signed.rs diff --git a/src/de/decoder.rs b/src/de/decoder.rs new file mode 100644 index 0000000..f94592c --- /dev/null +++ b/src/de/decoder.rs @@ -0,0 +1,210 @@ +use super::{read::Reader, Decode}; +use crate::{ + config::{Config, Endian, IntEncoding}, + error::DecodeError, +}; +use std::marker::PhantomData; + +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + pub fn new(reader: R) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } + + pub fn into_reader(self) -> R { + self.reader + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0]) + } + + fn decode_u16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u16::from_le_bytes(bytes), + Endian::Big => u16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u128::from_le_bytes(bytes), + Endian::Big => u128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_usize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + } as usize) + } + } + } + + fn decode_i8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0] as i8) + } + + fn decode_i16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i16::from_le_bytes(bytes), + Endian::Big => i16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i32::from_le_bytes(bytes), + Endian::Big => i32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i128::from_le_bytes(bytes), + Endian::Big => i128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_isize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + } as isize) + } + } + } + + fn decode_f32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f32::from_le_bytes(bytes), + Endian::Big => f32::from_be_bytes(bytes), + }) + } + + fn decode_f64(&mut self) -> Result { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f64::from_le_bytes(bytes), + Endian::Big => f64::from_be_bytes(bytes), + }) + } + + fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError> { + self.reader.read(slice) + } + + fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { + let mut array = [0u8; N]; + self.reader.read(&mut array)?; + Ok(array) + } +} diff --git a/src/de/impls.rs b/src/de/impls.rs index da515f3..4360cfd 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,8 +1,143 @@ use super::{Decodable, Decode}; use crate::error::DecodeError; +impl Decodable for u8 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u8() + } +} + +impl Decodable for u16 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u16() + } +} + impl Decodable for u32 { fn decode(mut decoder: D) -> Result { decoder.decode_u32() } } + +impl Decodable for u64 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u64() + } +} + +impl Decodable for u128 { + fn decode(mut decoder: D) -> Result { + decoder.decode_u128() + } +} + +impl Decodable for usize { + fn decode(mut decoder: D) -> Result { + decoder.decode_usize() + } +} + +impl Decodable for i8 { + fn decode(mut decoder: D) -> Result { + decoder.decode_i8() + } +} + +impl Decodable for i16 { + fn decode(mut decoder: D) -> Result { + decoder.decode_i16() + } +} + +impl Decodable for i32 { + fn decode(mut decoder: D) -> Result { + decoder.decode_i32() + } +} + +impl Decodable for i64 { + fn decode(mut decoder: D) -> Result { + decoder.decode_i64() + } +} + +impl Decodable for i128 { + fn decode(mut decoder: D) -> Result { + decoder.decode_i128() + } +} + +impl Decodable for isize { + fn decode(mut decoder: D) -> Result { + decoder.decode_isize() + } +} + +impl<'a, T> Decode for &'a mut T +where + T: Decode, +{ + fn decode_u8(&mut self) -> Result { + T::decode_u8(self) + } + + fn decode_u16(&mut self) -> Result { + T::decode_u16(self) + } + + fn decode_u32(&mut self) -> Result { + T::decode_u32(self) + } + + fn decode_u64(&mut self) -> Result { + T::decode_u64(self) + } + + fn decode_u128(&mut self) -> Result { + T::decode_u128(self) + } + + fn decode_usize(&mut self) -> Result { + T::decode_usize(self) + } + + fn decode_i8(&mut self) -> Result { + T::decode_i8(self) + } + + fn decode_i16(&mut self) -> Result { + T::decode_i16(self) + } + + fn decode_i32(&mut self) -> Result { + T::decode_i32(self) + } + + fn decode_i64(&mut self) -> Result { + T::decode_i64(self) + } + + fn decode_i128(&mut self) -> Result { + T::decode_i128(self) + } + + fn decode_isize(&mut self) -> Result { + T::decode_isize(self) + } + + fn decode_f32(&mut self) -> Result { + T::decode_f32(self) + } + + fn decode_f64(&mut self) -> Result { + T::decode_f64(self) + } + + fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError> { + T::decode_slice(self, slice) + } + + fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { + T::decode_array::(self) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 8ee5567..dca66a2 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,58 +1,32 @@ -use core::marker::PhantomData; - -use crate::{ - config::{Config, Endian, IntEncoding}, - error::DecodeError, -}; -use read::Reader; +use crate::error::DecodeError; +mod decoder; mod impls; + pub mod read; +pub use self::decoder::Decoder; pub trait Decodable: Sized { fn decode(decoder: D) -> Result; } pub trait Decode { + fn decode_u8(&mut self) -> Result; + fn decode_u16(&mut self) -> Result; fn decode_u32(&mut self) -> Result; -} + fn decode_u64(&mut self) -> Result; + fn decode_u128(&mut self) -> Result; + fn decode_usize(&mut self) -> Result; -pub struct Decoder { - reader: R, - config: PhantomData, -} + fn decode_i8(&mut self) -> Result; + fn decode_i16(&mut self) -> Result; + fn decode_i32(&mut self) -> Result; + fn decode_i64(&mut self) -> Result; + fn decode_i128(&mut self) -> Result; + fn decode_isize(&mut self) -> Result; -impl<'de, R: Reader<'de>, C: Config> Decoder { - pub fn new(reader: R) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } -} - -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u32(&mut self) -> Result { - Ok(match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN)?, - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - - self.reader.read(bytes.as_mut())?; - match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - } - } - }) - } -} - -impl<'a, T> Decode for &'a mut T -where - T: Decode, -{ - fn decode_u32(&mut self) -> Result { - T::decode_u32(self) - } + fn decode_f32(&mut self) -> Result; + fn decode_f64(&mut self) -> Result; + fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError>; + fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; } diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 524c58f..c01ba62 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -154,27 +154,20 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError> { - 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()), - }, + 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<(), EncodeError> { - 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()), - }, + 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<(), EncodeError> { - // TODO: Should this be swapped if we're big or little endian? self.writer.write(val) } } diff --git a/src/varint/decode_signed.rs b/src/varint/decode_signed.rs new file mode 100644 index 0000000..cc14951 --- /dev/null +++ b/src/varint/decode_signed.rs @@ -0,0 +1,43 @@ +#![allow(unused_variables)] + +use crate::{config::Endian, de::read::Reader, error::DecodeError}; + +#[allow(dead_code)] +pub fn varint_decode_i16<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + unimplemented!() +} + +#[allow(dead_code)] +pub fn varint_decode_i32<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + unimplemented!() +} + +#[allow(dead_code)] +pub fn varint_decode_i64<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + unimplemented!() +} + +#[allow(dead_code)] +pub fn varint_decode_i128<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + unimplemented!() +} + +#[allow(dead_code)] +pub fn varint_decode_isize<'a, R: Reader<'a>>( + read: &mut R, + endian: Endian, +) -> Result { + unimplemented!() +} diff --git a/src/varint/mod.rs b/src/varint/mod.rs index 54d19e5..a104586 100644 --- a/src/varint/mod.rs +++ b/src/varint/mod.rs @@ -1,7 +1,12 @@ +mod decode_signed; mod decode_unsigned; mod encode_signed; mod encode_unsigned; +pub use self::decode_signed::{ + varint_decode_i128, varint_decode_i16, varint_decode_i32, varint_decode_i64, + varint_decode_isize, +}; pub use self::decode_unsigned::{ varint_decode_u128, varint_decode_u16, varint_decode_u32, varint_decode_u64, varint_decode_usize, From ffb565c4058aa45d65907670b34cd4227193c262 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Wed, 22 Sep 2021 10:40:27 +0200 Subject: [PATCH 26/80] 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); } From 9c7fb85e0ef29033170d43a66220dad9702a23e5 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Wed, 22 Sep 2021 12:02:42 +0200 Subject: [PATCH 27/80] Added support for slices, str, fixed size arrays. Added lifetime to Decode trait --- derive/Cargo.toml | 2 +- derive/src/derive_enum.rs | 37 ++++++++++++++-- derive/src/derive_struct.rs | 37 +++++++++++++--- docs/spec.md | 37 ++++++++++++++++ src/de/decoder.rs | 6 +-- src/de/impls.rs | 88 +++++++++++++++++++++++-------------- src/de/mod.rs | 8 ++-- src/enc/encoder.rs | 5 +++ src/enc/impls.rs | 15 +++++++ src/enc/mod.rs | 1 + src/error.rs | 2 + src/lib.rs | 8 ++-- tests/derive.rs | 5 ++- tests/test.rs | 50 ++++++++++++++++++++- 14 files changed, 245 insertions(+), 56 deletions(-) diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 34d6a61..b4379a8 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -13,4 +13,4 @@ proc-macro2 = "1.0" [dependencies.syn] version = "1.0.74" default-features = false -features = ["parsing", "derive", "proc-macro", "printing"] +features = ["parsing", "derive", "proc-macro", "printing", "clone-impls"] diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 9e14519..68ddda9 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,8 +1,12 @@ use crate::Result; use proc_macro::TokenStream; +use proc_macro2::Span; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use quote::ToTokens; +use syn::GenericParam; +use syn::Lifetime; +use syn::LifetimeDef; use syn::{spanned::Spanned, Fields, Generics, Ident, Index, Variant}; pub struct DeriveEnum { name: Ident, @@ -63,7 +67,34 @@ impl DeriveEnum { variants, } = self; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + // check if we don't already have a '__de lifetime + let mut should_insert_lifetime = true; + + for param in &generics.params { + if let GenericParam::Lifetime(lt) = param { + if lt.lifetime.ident == "__de" { + should_insert_lifetime = false; + break; + } + } + } + + // if we don't have a '__de lifetime, insert it + let mut generics_with_decode_lifetime; + if should_insert_lifetime { + generics_with_decode_lifetime = generics.clone(); + generics_with_decode_lifetime + .params + .push(GenericParam::Lifetime(LifetimeDef::new(Lifetime::new( + "'__de", + Span::call_site(), + )))); + + impl_generics = generics_with_decode_lifetime.split_for_impl().0; + } + let max_variant = (variants.len() - 1) as u32; let match_arms = variants.iter().enumerate().map(|(index, variant)| { let index = index as u32; @@ -79,8 +110,8 @@ impl DeriveEnum { } }); let result = quote! { - impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { - fn decode(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { + impl #impl_generics bincode::de::Decodable<'__de> for #name #ty_generics #where_clause { + fn decode>(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { let i = decoder.decode_u32()?; Ok(match i { #(#match_arms)* diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index ff63e74..1c43796 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,8 +1,8 @@ use crate::Result; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; -use syn::{Generics, Ident, Index}; +use syn::{GenericParam, Generics, Ident, Index, Lifetime, LifetimeDef}; pub struct DeriveStruct { name: Ident, @@ -70,7 +70,33 @@ impl DeriveStruct { fields, } = self; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + // check if we don't already have a '__de lifetime + let mut should_insert_lifetime = true; + + for param in &generics.params { + if let GenericParam::Lifetime(lt) = param { + if lt.lifetime.ident == "__de" { + should_insert_lifetime = false; + break; + } + } + } + + // if we don't have a '__de lifetime, insert it + let mut generics_with_decode_lifetime; + if should_insert_lifetime { + generics_with_decode_lifetime = generics.clone(); + generics_with_decode_lifetime + .params + .push(GenericParam::Lifetime(LifetimeDef::new(Lifetime::new( + "'__de", + Span::call_site(), + )))); + + impl_generics = generics_with_decode_lifetime.split_for_impl().0; + } let fields = fields .into_iter() @@ -82,8 +108,8 @@ impl DeriveStruct { .collect::>(); let result = quote! { - impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { - fn decode(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { + impl #impl_generics bincode::de::Decodable< '__de > for #name #ty_generics #where_clause { + fn decode>(mut decoder: D) -> Result { Ok(#name { #(#fields)* }) @@ -91,6 +117,7 @@ impl DeriveStruct { } }; + Ok(result.into()) } } diff --git a/docs/spec.md b/docs/spec.md index fb24e24..8313c47 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -90,6 +90,8 @@ assert_eq!(encoded.as_slice(), &[ Collections are encoded with their length value first, following by each entry of the collection. The length value is based on your `IntEncoding`. +**note**: fixed array length do not have their `len` encoded. See [Arrays](#arrays) + ```rs let list = vec![ 0u8, @@ -121,3 +123,38 @@ assert_eq!(encoded.as_slice(), &[ b'H', b'e', b'l', b'l', b'o' ]); ``` + +# Arrays + +Arrays are encoded *without* a length. + +```rs +let arr: [u8; 5] = [10, 20, 30, 40, 50]; +let encoded = bincode::encode_to_vec(&list).unwrap(); +assert_eq!(encoded.as_slice(), &[10, 20, 30, 40 50]); +``` + +This applies to any type `T` that implements `Encodabl`/`Decodabl` + +```rs +#[derive(bincode::Encodabl)] +struct Foo { + first: u8, + second: u8 +}; + +let arr: [Foo; 2] = [ + Foo { + first: 10, + second: 20, + }, + Foo { + first: 30, + second: 40, + }, +]; + +let encoded = bincode::encode_to_vec(&list).unwrap(); +assert_eq!(encoded.as_slice(), &[10, 20, 30, 40]); +``` + diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 7d04156..2819ec7 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -23,7 +23,7 @@ impl<'de, R: Reader<'de>, C: Config> Decoder { } } -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { +impl<'a, 'de, R: Reader<'de>, C: Config> Decode<'de> for &'a mut Decoder { fn decode_u8(&mut self) -> Result { let mut bytes = [0u8; 1]; self.reader.read(&mut bytes)?; @@ -198,8 +198,8 @@ impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { }) } - fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError> { - self.reader.read(slice) + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + self.reader.forward_read(len, |s| s) } fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { diff --git a/src/de/impls.rs b/src/de/impls.rs index ce5a08c..9218939 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,99 +1,119 @@ use super::{Decodable, Decode}; use crate::error::DecodeError; -impl Decodable for u8 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for u8 { + fn decode>(mut decoder: D) -> Result { decoder.decode_u8() } } -impl Decodable for u16 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for u16 { + fn decode>(mut decoder: D) -> Result { decoder.decode_u16() } } -impl Decodable for u32 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for u32 { + fn decode>(mut decoder: D) -> Result { decoder.decode_u32() } } -impl Decodable for u64 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for u64 { + fn decode>(mut decoder: D) -> Result { decoder.decode_u64() } } -impl Decodable for u128 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for u128 { + fn decode>(mut decoder: D) -> Result { decoder.decode_u128() } } -impl Decodable for usize { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for usize { + fn decode>(mut decoder: D) -> Result { decoder.decode_usize() } } -impl Decodable for i8 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for i8 { + fn decode>(mut decoder: D) -> Result { decoder.decode_i8() } } -impl Decodable for i16 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for i16 { + fn decode>(mut decoder: D) -> Result { decoder.decode_i16() } } -impl Decodable for i32 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for i32 { + fn decode>(mut decoder: D) -> Result { decoder.decode_i32() } } -impl Decodable for i64 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for i64 { + fn decode>(mut decoder: D) -> Result { decoder.decode_i64() } } -impl Decodable for i128 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for i128 { + fn decode>(mut decoder: D) -> Result { decoder.decode_i128() } } -impl Decodable for isize { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for isize { + fn decode>(mut decoder: D) -> Result { decoder.decode_isize() } } -impl Decodable for f32 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for f32 { + fn decode>(mut decoder: D) -> Result { decoder.decode_f32() } } -impl Decodable for f64 { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for f64 { + fn decode>(mut decoder: D) -> Result { decoder.decode_f64() } } -impl Decodable for [u8; N] { - fn decode(mut decoder: D) -> Result { +impl<'de> Decodable<'de> for &'de [u8] { + fn decode>(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + decoder.decode_slice(len) + } +} + +impl<'de> Decodable<'de> for &'de str { + fn decode>(decoder: D) -> Result { + let slice: &[u8] = Decodable::decode(decoder)?; + core::str::from_utf8(slice).map_err(DecodeError::Utf8) + } +} + +impl<'de, const N: usize> Decodable<'de> for [u8; N] { + fn decode>(mut decoder: D) -> Result { decoder.decode_array() } } -impl<'a, T> Decode for &'a mut T +impl<'de, T> Decodable<'de> for core::marker::PhantomData { + fn decode>(_: D) -> Result { + Ok(core::marker::PhantomData) + } +} + +impl<'a, 'de, T> Decode<'de> for &'a mut T where - T: Decode, + T: Decode<'de>, { fn decode_u8(&mut self) -> Result { T::decode_u8(self) @@ -151,8 +171,8 @@ where T::decode_f64(self) } - fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError> { - T::decode_slice(self, slice) + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + T::decode_slice(self, len) } fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { diff --git a/src/de/mod.rs b/src/de/mod.rs index dca66a2..31f3b38 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -6,11 +6,11 @@ mod impls; pub mod read; pub use self::decoder::Decoder; -pub trait Decodable: Sized { - fn decode(decoder: D) -> Result; +pub trait Decodable<'de>: Sized { + fn decode>(decoder: D) -> Result; } -pub trait Decode { +pub trait Decode<'de> { fn decode_u8(&mut self) -> Result; fn decode_u16(&mut self) -> Result; fn decode_u32(&mut self) -> Result; @@ -27,6 +27,6 @@ pub trait Decode { fn decode_f32(&mut self) -> Result; fn decode_f64(&mut self) -> Result; - fn decode_slice(&mut self, slice: &mut [u8]) -> Result<(), DecodeError>; + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; } diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index c01ba62..5ffdada 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -168,6 +168,11 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError> { + self.encode_usize(val.len())?; self.writer.write(val) } + + fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { + self.writer.write(&val) + } } diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 35c9a69..5d199e0 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -91,6 +91,18 @@ impl Encodeable for &'_ [u8] { } } +impl Encodeable for &'_ str { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.encode_slice(self.as_bytes()) + } +} + +impl Encodeable for [u8; N] { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.encode_array(*self) + } +} + impl<'a, T> Encode for &'a mut T where T: Encode, @@ -142,4 +154,7 @@ where fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError> { T::encode_slice(self, val) } + fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { + T::encode_array(self, val) + } } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index ca5ebfe..ad997a3 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -29,4 +29,5 @@ pub trait Encode { fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError>; fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError>; fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError>; + fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError>; } diff --git a/src/error.rs b/src/error.rs index 47340c7..04db286 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,6 +21,8 @@ pub enum DecodeError { max: u32, found: u32, }, + + Utf8(core::str::Utf8Error), } #[non_exhaustive] diff --git a/src/lib.rs b/src/lib.rs index 38c0f95..3857395 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,12 +43,14 @@ pub fn encode_into_slice_with_config( Ok(encoder.into_writer().bytes_written()) } -pub fn decode(src: &mut [u8]) -> Result { +pub fn decode<'__de, D: de::Decodable<'__de>>( + src: &'__de mut [u8], +) -> Result { decode_with_config(src, config::Default) } -pub fn decode_with_config( - src: &mut [u8], +pub fn decode_with_config<'__de, D: de::Decodable<'__de>, C: Config>( + src: &'__de mut [u8], _config: C, ) -> Result { let reader = de::read::SliceReader::new(src); diff --git a/tests/derive.rs b/tests/derive.rs index e699aee..a33c2a2 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,4 +1,5 @@ use bincode::{de::Decodable, enc::Encodeable}; +use core::marker::PhantomData; #[derive(bincode::Encodable, PartialEq, Debug)] pub struct Test { @@ -8,10 +9,11 @@ pub struct Test { } #[derive(bincode::Decodable, PartialEq, Debug, Eq)] -pub struct Test2 { +pub struct Test2<'__de, T: Decodable<'__de>> { a: T, b: u32, c: u32, + pd: PhantomData<&'__de ()>, } #[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] @@ -43,6 +45,7 @@ fn test_decodable() { a: 5u32, b: 10u32, c: 1024u32, + pd: PhantomData, }; let mut slice = [5, 10, 251, 0, 4]; let result: Test2 = bincode::decode(&mut slice).unwrap(); diff --git a/tests/test.rs b/tests/test.rs index 2664ec1..2850355 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -5,7 +5,12 @@ 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, + V: bincode::enc::Encodeable + + for<'de> bincode::de::Decodable<'de> + + PartialEq + + Debug + + Clone + + 'static, C: Config, { let mut buffer = [0u8; 32]; @@ -16,7 +21,12 @@ where } fn the_same(element: V) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + V: bincode::enc::Encodeable + + for<'de> bincode::de::Decodable<'de> + + PartialEq + + Debug + + Clone + + 'static, { the_same_with_config( element.clone(), @@ -61,3 +71,39 @@ fn test_numbers() { the_same(5.0f32); the_same(5.0f64); } + +#[test] +fn test_slice() { + let mut buffer = [0u8; 32]; + let input: &[u8] = &[1, 2, 3, 4, 5, 6, 7]; + bincode::encode_into_slice(input, &mut buffer).unwrap(); + assert_eq!(&buffer[..8], &[7, 1, 2, 3, 4, 5, 6, 7]); + + let output: &[u8] = bincode::decode(&mut buffer[..8]).unwrap(); + assert_eq!(input, output); +} + +#[test] +fn test_str() { + let mut buffer = [0u8; 32]; + let input: &str = "Hello world"; + bincode::encode_into_slice(input, &mut buffer).unwrap(); + assert_eq!( + &buffer[..12], + &[11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100] + ); + + let output: &str = bincode::decode(&mut buffer[..12]).unwrap(); + assert_eq!(input, output); +} + +#[test] +fn test_array() { + let mut buffer = [0u8; 32]; + let input: [u8; 10] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; + bincode::encode_into_slice(input, &mut buffer).unwrap(); + assert_eq!(&buffer[..10], &[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]); + + let output: [u8; 10] = bincode::decode(&mut buffer[..10]).unwrap(); + assert_eq!(input, output); +} From 4b672de11020313ba39ae6c169bbd4cba4fa6288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 15:08:52 +0200 Subject: [PATCH 28/80] Enable non-slice readers --- src/de/decoder.rs | 15 ++++++++++----- src/de/impls.rs | 16 ++++++---------- src/de/mod.rs | 17 +++++++++++++++-- src/de/read.rs | 27 +++++++++++++++++++-------- src/lib.rs | 20 ++++++++++++++++++-- 5 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 2819ec7..309ab69 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,4 +1,7 @@ -use super::{read::Reader, Decode}; +use super::{ + read::{BorrowReader, Reader}, + BorrowDecode, Decode, +}; use crate::{ config::{Config, Endian, IntEncoding}, error::DecodeError, @@ -23,6 +26,12 @@ impl<'de, R: Reader<'de>, C: Config> Decoder { } } +impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + self.reader.take_bytes(len) + } +} + impl<'a, 'de, R: Reader<'de>, C: Config> Decode<'de> for &'a mut Decoder { fn decode_u8(&mut self) -> Result { let mut bytes = [0u8; 1]; @@ -198,10 +207,6 @@ impl<'a, 'de, R: Reader<'de>, C: Config> Decode<'de> for &'a mut Decoder { }) } - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - self.reader.forward_read(len, |s| s) - } - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { let mut array = [0u8; N]; self.reader.read(&mut array)?; diff --git a/src/de/impls.rs b/src/de/impls.rs index 9218939..afbb55f 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,4 +1,4 @@ -use super::{Decodable, Decode}; +use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; use crate::error::DecodeError; impl<'de> Decodable<'de> for u8 { @@ -85,16 +85,16 @@ impl<'de> Decodable<'de> for f64 { } } -impl<'de> Decodable<'de> for &'de [u8] { - fn decode>(mut decoder: D) -> Result { +impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a [u8] { + fn borrow_decode>(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; decoder.decode_slice(len) } } -impl<'de> Decodable<'de> for &'de str { - fn decode>(decoder: D) -> Result { - let slice: &[u8] = Decodable::decode(decoder)?; +impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a str { + fn borrow_decode>(decoder: D) -> Result { + let slice: &[u8] = BorrowDecodable::borrow_decode(decoder)?; core::str::from_utf8(slice).map_err(DecodeError::Utf8) } } @@ -171,10 +171,6 @@ where T::decode_f64(self) } - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - T::decode_slice(self, len) - } - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { T::decode_array::(self) } diff --git a/src/de/mod.rs b/src/de/mod.rs index 31f3b38..d0dc730 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -6,10 +6,20 @@ mod impls; pub mod read; pub use self::decoder::Decoder; -pub trait Decodable<'de>: Sized { +pub trait Decodable<'de>: Sized + BorrowDecodable<'de> { fn decode>(decoder: D) -> Result; } +pub trait BorrowDecodable<'de>: Sized { + fn borrow_decode>(decoder: D) -> Result; +} + +impl<'de, T: Decodable<'de>> BorrowDecodable<'de> for T { + fn borrow_decode>(decoder: D) -> Result { + Decodable::decode(decoder) + } +} + pub trait Decode<'de> { fn decode_u8(&mut self) -> Result; fn decode_u16(&mut self) -> Result; @@ -27,6 +37,9 @@ pub trait Decode<'de> { fn decode_f32(&mut self) -> Result; fn decode_f64(&mut self) -> Result; - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; } + +pub trait BorrowDecode<'de>: Decode<'de> { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; +} diff --git a/src/de/read.rs b/src/de/read.rs index f78fcf0..a9280e6 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -2,9 +2,10 @@ use crate::error::DecodeError; pub trait Reader<'storage> { fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>; - fn forward_read(&mut self, length: usize, visitor: F) -> Result - where - F: Fn(&'storage [u8]) -> R; +} + +pub trait BorrowReader<'storage>: Reader<'storage> { + fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError>; } pub struct SliceReader<'storage> { @@ -40,12 +41,22 @@ impl<'storage> Reader<'storage> for SliceReader<'storage> { Ok(()) } +} +impl<'storage> BorrowReader<'storage> for SliceReader<'storage> { #[inline(always)] - fn forward_read(&mut self, length: usize, visitor: F) -> Result - where - F: Fn(&'storage [u8]) -> R, - { - Ok(visitor(self.get_byte_slice(length)?)) + fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError> { + self.get_byte_slice(length) + } +} + +#[cfg(feature = "std")] +impl<'storage, R: std::io::Read> Reader<'storage> for R { + #[inline(always)] + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { + match self.read_exact(bytes) { + Ok(_) => Ok(()), + Err(_) => Err(DecodeError::UnexpectedEnd), + } } } diff --git a/src/lib.rs b/src/lib.rs index 3857395..debac78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,17 +43,33 @@ pub fn encode_into_slice_with_config( Ok(encoder.into_writer().bytes_written()) } -pub fn decode<'__de, D: de::Decodable<'__de>>( +pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( src: &'__de mut [u8], ) -> Result { decode_with_config(src, config::Default) } -pub fn decode_with_config<'__de, D: de::Decodable<'__de>, C: Config>( +pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( src: &'__de mut [u8], _config: C, ) -> Result { let reader = de::read::SliceReader::new(src); let mut decoder = de::Decoder::<_, C>::new(reader, _config); + D::borrow_decode(&mut decoder) +} + +#[cfg(feature = "std")] +pub fn decode_from<'__de, D: de::Decodable<'__de>, R: std::io::Read>( + src: &'__de mut R, +) -> Result { + decode_from_with_config(src, config::Default) +} + +#[cfg(feature = "std")] +pub fn decode_from_with_config<'__de, D: de::Decodable<'__de>, C: Config, R: std::io::Read>( + src: &'__de mut R, + _config: C, +) -> Result { + let mut decoder = de::Decoder::<_, C>::new(src, _config); D::decode(&mut decoder) } From 254b87c6ebc481dda519eebc5059921d65930aaf Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Wed, 22 Sep 2021 16:13:30 +0200 Subject: [PATCH 29/80] Moved all feature flags to src/features, made the CI run tests on all feature combinations --- .github/workflows/rust.yml | 11 ++++++++--- Cargo.toml | 7 ++++--- derive/src/derive_enum.rs | 13 +++++-------- src/config.rs | 2 +- src/de/decoder.rs | 2 +- src/de/read.rs | 11 ----------- src/enc/encoder.rs | 3 +-- src/features/derive.rs | 1 + src/features/impl_alloc.rs | 1 + src/features/impl_std.rs | 29 +++++++++++++++++++++++++++++ src/features/mod.rs | 14 ++++++++++++++ src/lib.rs | 26 ++++++-------------------- src/varint/mod.rs | 32 +++++++++++++++++--------------- tests/derive.rs | 2 ++ tests/test.rs | 2 -- 15 files changed, 90 insertions(+), 66 deletions(-) create mode 100644 src/features/derive.rs create mode 100644 src/features/impl_alloc.rs create mode 100644 src/features/impl_std.rs create mode 100644 src/features/mod.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 59c7a37..fcd150f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -91,11 +91,16 @@ "name": "Install Rust ${{ matrix.rust }}" }, { - "uses": "actions-rs/cargo@v1", + "uses": "actions-rs/install@v0.1", "with": { - "command": "test" + "crate": "cargo-all-features", + "version": "1.6.0" }, - "name": "Run `cargo test`" + "name": "Install cargo-all-features" + }, + { + "run": "cargo test-all-features", + "name": "Run `cargo test` on all features" } ] }, diff --git a/Cargo.toml b/Cargo.toml index 3b9097b..f2ef9eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,11 @@ description = "A binary serialization / deserialization strategy for transformin edition = "2018" [features] -default = ["std"] -std = [] +default = ["std", "derive"] +std = ["alloc"] alloc = [] +derive = ["bincode_derive"] [dependencies] -bincode_derive = { path = "derive", version = "2.0.0-dev" } +bincode_derive = { path = "derive", version = "2.0.0-dev", optional = true } # serde = { version = "1.0.130", optional = true } diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 68ddda9..d3b0e6c 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,13 +1,10 @@ use crate::Result; use proc_macro::TokenStream; -use proc_macro2::Span; -use proc_macro2::TokenStream as TokenStream2; -use quote::quote; -use quote::ToTokens; -use syn::GenericParam; -use syn::Lifetime; -use syn::LifetimeDef; -use syn::{spanned::Spanned, Fields, Generics, Ident, Index, Variant}; +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::{quote, ToTokens}; +use syn::{ + spanned::Spanned, Fields, GenericParam, Generics, Ident, Index, Lifetime, LifetimeDef, Variant, +}; pub struct DeriveEnum { name: Ident, generics: Generics, diff --git a/src/config.rs b/src/config.rs index e768ed0..ad549c3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,5 @@ pub(crate) use self::internal::*; -use std::marker::PhantomData; +use core::marker::PhantomData; pub trait Config: InternalConfig + Copy + Clone + Sized { fn with_big_endian(self) -> BigEndian { diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 309ab69..2599112 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -6,7 +6,7 @@ use crate::{ config::{Config, Endian, IntEncoding}, error::DecodeError, }; -use std::marker::PhantomData; +use core::marker::PhantomData; pub struct Decoder { reader: R, diff --git a/src/de/read.rs b/src/de/read.rs index a9280e6..2b568da 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -49,14 +49,3 @@ impl<'storage> BorrowReader<'storage> for SliceReader<'storage> { self.get_byte_slice(length) } } - -#[cfg(feature = "std")] -impl<'storage, R: std::io::Read> Reader<'storage> for R { - #[inline(always)] - fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { - match self.read_exact(bytes) { - Ok(_) => Ok(()), - Err(_) => Err(DecodeError::UnexpectedEnd), - } - } -} diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 5ffdada..5a15e4b 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,5 +1,4 @@ -use super::write::Writer; -use super::Encode; +use super::{write::Writer, Encode}; use crate::{ config::{Config, Endian, IntEncoding}, error::EncodeError, diff --git a/src/features/derive.rs b/src/features/derive.rs new file mode 100644 index 0000000..b55c1b5 --- /dev/null +++ b/src/features/derive.rs @@ -0,0 +1 @@ +pub use bincode_derive::{Decodable, Encodable}; diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/features/impl_alloc.rs @@ -0,0 +1 @@ + diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs new file mode 100644 index 0000000..9cb3463 --- /dev/null +++ b/src/features/impl_std.rs @@ -0,0 +1,29 @@ +use crate::{ + config::{self, Config}, + de::{read::Reader, Decodable, Decoder}, + error::DecodeError, +}; + +pub fn decode_from<'__de, D: Decodable<'__de>, R: std::io::Read>( + src: &'__de mut R, +) -> Result { + decode_from_with_config(src, config::Default) +} + +pub fn decode_from_with_config<'__de, D: Decodable<'__de>, C: Config, R: std::io::Read>( + src: &'__de mut R, + _config: C, +) -> Result { + let mut decoder = Decoder::<_, C>::new(src, _config); + D::decode(&mut decoder) +} + +impl<'storage, R: std::io::Read> Reader<'storage> for R { + #[inline(always)] + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { + match self.read_exact(bytes) { + Ok(_) => Ok(()), + Err(_) => Err(DecodeError::UnexpectedEnd), + } + } +} diff --git a/src/features/mod.rs b/src/features/mod.rs new file mode 100644 index 0000000..25ba517 --- /dev/null +++ b/src/features/mod.rs @@ -0,0 +1,14 @@ +#[cfg(feature = "alloc")] +mod impl_alloc; +#[cfg(feature = "alloc")] +pub use self::impl_alloc::*; + +#[cfg(feature = "std")] +mod impl_std; +#[cfg(feature = "std")] +pub use self::impl_std::*; + +#[cfg(feature = "derive")] +mod derive; +#[cfg(feature = "derive")] +pub use self::derive::*; diff --git a/src/lib.rs b/src/lib.rs index debac78..35f8441 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,19 +12,21 @@ #[cfg(feature = "alloc")] extern crate alloc; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", test))] extern crate std; +mod features; +pub(crate) mod varint; + +pub use features::*; + pub mod config; pub mod de; 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], @@ -57,19 +59,3 @@ pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( let mut decoder = de::Decoder::<_, C>::new(reader, _config); D::borrow_decode(&mut decoder) } - -#[cfg(feature = "std")] -pub fn decode_from<'__de, D: de::Decodable<'__de>, R: std::io::Read>( - src: &'__de mut R, -) -> Result { - decode_from_with_config(src, config::Default) -} - -#[cfg(feature = "std")] -pub fn decode_from_with_config<'__de, D: de::Decodable<'__de>, C: Config, R: std::io::Read>( - src: &'__de mut R, - _config: C, -) -> Result { - let mut decoder = de::Decoder::<_, C>::new(src, _config); - D::decode(&mut decoder) -} diff --git a/src/varint/mod.rs b/src/varint/mod.rs index a104586..afadfb5 100644 --- a/src/varint/mod.rs +++ b/src/varint/mod.rs @@ -3,21 +3,23 @@ mod decode_unsigned; mod encode_signed; mod encode_unsigned; -pub use self::decode_signed::{ - varint_decode_i128, varint_decode_i16, varint_decode_i32, varint_decode_i64, - varint_decode_isize, -}; -pub use self::decode_unsigned::{ - varint_decode_u128, varint_decode_u16, varint_decode_u32, varint_decode_u64, - varint_decode_usize, -}; -pub use self::encode_signed::{ - varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64, - varint_encode_isize, -}; -pub use self::encode_unsigned::{ - varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64, - varint_encode_usize, +pub use self::{ + decode_signed::{ + varint_decode_i128, varint_decode_i16, varint_decode_i32, varint_decode_i64, + varint_decode_isize, + }, + decode_unsigned::{ + varint_decode_u128, varint_decode_u16, varint_decode_u32, varint_decode_u64, + varint_decode_usize, + }, + encode_signed::{ + varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64, + varint_encode_isize, + }, + encode_unsigned::{ + varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64, + varint_encode_usize, + }, }; pub(self) const SINGLE_BYTE_MAX: u8 = 250; diff --git a/tests/derive.rs b/tests/derive.rs index a33c2a2..2bf0606 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "derive")] + use bincode::{de::Decodable, enc::Encodeable}; use core::marker::PhantomData; diff --git a/tests/test.rs b/tests/test.rs index 2850355..f09625c 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,5 +1,3 @@ -extern crate bincode; - use bincode::config::{self, Config}; use core::fmt::Debug; From 044942891f41c2a3dbe47ea6ece0ee15b246ac4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 22:15:35 +0200 Subject: [PATCH 30/80] Clean up the borrow crimes --- derive/src/derive_enum.rs | 87 +++++++++++++++++++++++++------------ derive/src/derive_struct.rs | 64 ++++++++++++++++++--------- src/de/decoder.rs | 2 +- src/de/impls.rs | 77 +++++++++++++++++--------------- src/de/mod.rs | 12 ++--- src/features/impl_std.rs | 4 +- tests/derive.rs | 23 +++++++--- tests/test.rs | 4 +- 8 files changed, 173 insertions(+), 100 deletions(-) diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index d3b0e6c..e08c63c 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -66,15 +66,13 @@ impl DeriveEnum { let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - // check if we don't already have a '__de lifetime - let mut should_insert_lifetime = true; + // check if the type has lifetimes + let mut should_insert_lifetime = false; for param in &generics.params { - if let GenericParam::Lifetime(lt) = param { - if lt.lifetime.ident == "__de" { - should_insert_lifetime = false; - break; - } + if let GenericParam::Lifetime(_) = param { + should_insert_lifetime = true; + break; } } @@ -82,12 +80,18 @@ impl DeriveEnum { let mut generics_with_decode_lifetime; if should_insert_lifetime { generics_with_decode_lifetime = generics.clone(); + + let mut new_lifetime = LifetimeDef::new(Lifetime::new("'__de", Span::call_site())); + + for param in &generics.params { + if let GenericParam::Lifetime(lt) = param { + new_lifetime.bounds.push(lt.lifetime.clone()) + } + } + generics_with_decode_lifetime .params - .push(GenericParam::Lifetime(LifetimeDef::new(Lifetime::new( - "'__de", - Span::call_site(), - )))); + .push(GenericParam::Lifetime(new_lifetime)); impl_generics = generics_with_decode_lifetime.split_for_impl().0; } @@ -95,8 +99,10 @@ impl DeriveEnum { let max_variant = (variants.len() - 1) as u32; let match_arms = variants.iter().enumerate().map(|(index, variant)| { let index = index as u32; - let decode_statements = - field_names_to_decodable(&fields_to_constructable_names(&variant.fields)); + let decode_statements = field_names_to_decodable( + &fields_to_constructable_names(&variant.fields), + should_insert_lifetime, + ); let variant_name = variant.ident.clone(); quote! { #index => { @@ -106,20 +112,39 @@ impl DeriveEnum { } } }); - let result = quote! { - impl #impl_generics bincode::de::Decodable<'__de> for #name #ty_generics #where_clause { - fn decode>(mut decoder: D) -> Result<#name #ty_generics, bincode::error::DecodeError> { - let i = decoder.decode_u32()?; - Ok(match i { - #(#match_arms)* - variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ - min: 0, - max: #max_variant, - found: variant, + let result = if should_insert_lifetime { + quote! { + impl #impl_generics bincode::de::BorrowDecodable<'__de> for #name #ty_generics #where_clause { + fn borrow_decode>(mut decoder: D) -> Result { + let i = decoder.decode_u32()?; + Ok(match i { + #(#match_arms)* + variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ + min: 0, + max: #max_variant, + found: variant, + }) }) - }) - } + } + } + } + } else { + quote! { + impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { + fn decode(mut decoder: D) -> Result { + let i = decoder.decode_u32()?; + Ok(match i { + #(#match_arms)* + variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ + min: 0, + max: #max_variant, + found: variant, + }) + }) + } + + } } }; @@ -199,12 +224,18 @@ fn fields_to_constructable_names(fields: &Fields) -> Vec { } } -fn field_names_to_decodable(names: &[TokenStream2]) -> Vec { +fn field_names_to_decodable(names: &[TokenStream2], borrowed: bool) -> Vec { names .iter() .map(|field| { - quote! { - #field: bincode::de::Decodable::decode(&mut decoder)?, + if borrowed { + quote! { + #field: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?, + } + } else { + quote! { + #field: bincode::de::Decodable::decode(&mut decoder)?, + } } }) .collect::>() diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 1c43796..881545f 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -26,6 +26,7 @@ impl DeriveStruct { .collect(), syn::Fields::Unit => Vec::new(), }; + Ok(Self { name, generics, @@ -72,28 +73,30 @@ impl DeriveStruct { let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - // check if we don't already have a '__de lifetime - let mut should_insert_lifetime = true; + // check if the type has lifetimes + let mut should_insert_lifetime = false; for param in &generics.params { - if let GenericParam::Lifetime(lt) = param { - if lt.lifetime.ident == "__de" { - should_insert_lifetime = false; - break; - } + if let GenericParam::Lifetime(_) = param { + should_insert_lifetime = true; + break; } } - // if we don't have a '__de lifetime, insert it + // if the type has lifetimes, insert '__de and bound it to the lifetimes let mut generics_with_decode_lifetime; if should_insert_lifetime { generics_with_decode_lifetime = generics.clone(); + let mut new_lifetime = LifetimeDef::new(Lifetime::new("'__de", Span::call_site())); + + for param in &generics.params { + if let GenericParam::Lifetime(lt) = param { + new_lifetime.bounds.push(lt.lifetime.clone()) + } + } generics_with_decode_lifetime .params - .push(GenericParam::Lifetime(LifetimeDef::new(Lifetime::new( - "'__de", - Span::call_site(), - )))); + .push(GenericParam::Lifetime(new_lifetime)); impl_generics = generics_with_decode_lifetime.split_for_impl().0; } @@ -101,20 +104,39 @@ impl DeriveStruct { let fields = fields .into_iter() .map(|field| { - quote! { - #field: bincode::de::Decodable::decode(&mut decoder)?, + if should_insert_lifetime { + quote! { + #field: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?, + } + } else { + quote! { + #field: bincode::de::Decodable::decode(&mut decoder)?, + } } }) .collect::>(); - let result = quote! { - impl #impl_generics bincode::de::Decodable< '__de > for #name #ty_generics #where_clause { - fn decode>(mut decoder: D) -> Result { - Ok(#name { - #(#fields)* - }) - } + let result = if should_insert_lifetime { + quote! { + impl #impl_generics bincode::de::BorrowDecodable<'__de> for #name #ty_generics #where_clause { + fn borrow_decode>(mut decoder: D) -> Result { + Ok(#name { + #(#fields)* + }) + } + } + } + } else { + quote! { + impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { + fn decode(mut decoder: D) -> Result { + Ok(#name { + #(#fields)* + }) + } + + } } }; diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 2599112..ff10d37 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -32,7 +32,7 @@ impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Dec } } -impl<'a, 'de, R: Reader<'de>, C: Config> Decode<'de> for &'a mut Decoder { +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { fn decode_u8(&mut self) -> Result { let mut bytes = [0u8; 1]; self.reader.read(&mut bytes)?; diff --git a/src/de/impls.rs b/src/de/impls.rs index afbb55f..21164be 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,86 +1,86 @@ use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; use crate::error::DecodeError; -impl<'de> Decodable<'de> for u8 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for u8 { + fn decode(mut decoder: D) -> Result { decoder.decode_u8() } } -impl<'de> Decodable<'de> for u16 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for u16 { + fn decode(mut decoder: D) -> Result { decoder.decode_u16() } } -impl<'de> Decodable<'de> for u32 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for u32 { + fn decode(mut decoder: D) -> Result { decoder.decode_u32() } } -impl<'de> Decodable<'de> for u64 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for u64 { + fn decode(mut decoder: D) -> Result { decoder.decode_u64() } } -impl<'de> Decodable<'de> for u128 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for u128 { + fn decode(mut decoder: D) -> Result { decoder.decode_u128() } } -impl<'de> Decodable<'de> for usize { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for usize { + fn decode(mut decoder: D) -> Result { decoder.decode_usize() } } -impl<'de> Decodable<'de> for i8 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for i8 { + fn decode(mut decoder: D) -> Result { decoder.decode_i8() } } -impl<'de> Decodable<'de> for i16 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for i16 { + fn decode(mut decoder: D) -> Result { decoder.decode_i16() } } -impl<'de> Decodable<'de> for i32 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for i32 { + fn decode(mut decoder: D) -> Result { decoder.decode_i32() } } -impl<'de> Decodable<'de> for i64 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for i64 { + fn decode(mut decoder: D) -> Result { decoder.decode_i64() } } -impl<'de> Decodable<'de> for i128 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for i128 { + fn decode(mut decoder: D) -> Result { decoder.decode_i128() } } -impl<'de> Decodable<'de> for isize { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for isize { + fn decode(mut decoder: D) -> Result { decoder.decode_isize() } } -impl<'de> Decodable<'de> for f32 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for f32 { + fn decode(mut decoder: D) -> Result { decoder.decode_f32() } } -impl<'de> Decodable<'de> for f64 { - fn decode>(mut decoder: D) -> Result { +impl<'de> Decodable for f64 { + fn decode(mut decoder: D) -> Result { decoder.decode_f64() } } @@ -99,21 +99,21 @@ impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a str { } } -impl<'de, const N: usize> Decodable<'de> for [u8; N] { - fn decode>(mut decoder: D) -> Result { +impl<'de, const N: usize> Decodable for [u8; N] { + fn decode(mut decoder: D) -> Result { decoder.decode_array() } } -impl<'de, T> Decodable<'de> for core::marker::PhantomData { - fn decode>(_: D) -> Result { +impl<'de, T> Decodable for core::marker::PhantomData { + fn decode(_: D) -> Result { Ok(core::marker::PhantomData) } } -impl<'a, 'de, T> Decode<'de> for &'a mut T +impl<'a, 'de, T> Decode for &'a mut T where - T: Decode<'de>, + T: Decode, { fn decode_u8(&mut self) -> Result { T::decode_u8(self) @@ -175,3 +175,12 @@ where T::decode_array::(self) } } + +impl<'a, 'de, T> BorrowDecode<'de> for &'a mut T +where + T: BorrowDecode<'de>, +{ + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + T::decode_slice(self, len) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index d0dc730..199889e 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -6,21 +6,21 @@ mod impls; pub mod read; pub use self::decoder::Decoder; -pub trait Decodable<'de>: Sized + BorrowDecodable<'de> { - fn decode>(decoder: D) -> Result; +pub trait Decodable: for<'de> BorrowDecodable<'de> { + fn decode(decoder: D) -> Result; } pub trait BorrowDecodable<'de>: Sized { fn borrow_decode>(decoder: D) -> Result; } -impl<'de, T: Decodable<'de>> BorrowDecodable<'de> for T { - fn borrow_decode>(decoder: D) -> Result { +impl<'de, T: Decodable> BorrowDecodable<'de> for T { + fn borrow_decode(decoder: D) -> Result { Decodable::decode(decoder) } } -pub trait Decode<'de> { +pub trait Decode { fn decode_u8(&mut self) -> Result; fn decode_u16(&mut self) -> Result; fn decode_u32(&mut self) -> Result; @@ -40,6 +40,6 @@ pub trait Decode<'de> { fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; } -pub trait BorrowDecode<'de>: Decode<'de> { +pub trait BorrowDecode<'de>: Decode { fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; } diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 9cb3463..22b0ac1 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -4,13 +4,13 @@ use crate::{ error::DecodeError, }; -pub fn decode_from<'__de, D: Decodable<'__de>, R: std::io::Read>( +pub fn decode_from<'__de, D: Decodable, R: std::io::Read>( src: &'__de mut R, ) -> Result { decode_from_with_config(src, config::Default) } -pub fn decode_from_with_config<'__de, D: Decodable<'__de>, C: Config, R: std::io::Read>( +pub fn decode_from_with_config<'__de, D: Decodable, C: Config, R: std::io::Read>( src: &'__de mut R, _config: C, ) -> Result { diff --git a/tests/derive.rs b/tests/derive.rs index 2bf0606..c32701b 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,7 +1,6 @@ #![cfg(feature = "derive")] use bincode::{de::Decodable, enc::Encodeable}; -use core::marker::PhantomData; #[derive(bincode::Encodable, PartialEq, Debug)] pub struct Test { @@ -11,11 +10,17 @@ pub struct Test { } #[derive(bincode::Decodable, PartialEq, Debug, Eq)] -pub struct Test2<'__de, T: Decodable<'__de>> { +pub struct Test2 { a: T, b: u32, c: u32, - pd: PhantomData<&'__de ()>, +} + +#[derive(bincode::Decodable, PartialEq, Debug, Eq)] +pub struct Test3<'a> { + a: &'a str, + b: u32, + c: u32, } #[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] @@ -28,6 +33,13 @@ pub enum TestEnum { Baz(u32, u32, u32), } +#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +pub enum TestEnum2<'a> { + Foo, + Bar { name: &'a str }, + Baz(u32, u32, u32), +} + #[test] fn test_encodable() { let start = Test { @@ -47,10 +59,9 @@ fn test_decodable() { a: 5u32, b: 10u32, c: 1024u32, - pd: PhantomData, }; - let mut slice = [5, 10, 251, 0, 4]; - let result: Test2 = bincode::decode(&mut slice).unwrap(); + let slice = [5, 10, 251, 0, 4]; + let result: Test2 = bincode::decode_from(&mut slice.as_ref()).unwrap(); assert_eq!(result, start); } diff --git a/tests/test.rs b/tests/test.rs index f09625c..b0ca166 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -4,7 +4,7 @@ use core::fmt::Debug; fn the_same_with_config(element: V, config: C) where V: bincode::enc::Encodeable - + for<'de> bincode::de::Decodable<'de> + + for<'de> bincode::de::Decodable + PartialEq + Debug + Clone @@ -20,7 +20,7 @@ where fn the_same(element: V) where V: bincode::enc::Encodeable - + for<'de> bincode::de::Decodable<'de> + + for<'de> bincode::de::Decodable + PartialEq + Debug + Clone From 8e99d580b80d7e0970611f3dc05ad3e627a29e00 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 25 Sep 2021 09:25:50 +0200 Subject: [PATCH 31/80] Removed `allow` attributes, fixed some warnings --- src/features/impl_std.rs | 8 +++----- src/varint/decode_signed.rs | 7 ------- src/varint/decode_unsigned.rs | 5 ----- tests/derive.rs | 1 + 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 22b0ac1..31d9758 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -4,14 +4,12 @@ use crate::{ error::DecodeError, }; -pub fn decode_from<'__de, D: Decodable, R: std::io::Read>( - src: &'__de mut R, -) -> Result { +pub fn decode_from(src: &mut R) -> Result { decode_from_with_config(src, config::Default) } -pub fn decode_from_with_config<'__de, D: Decodable, C: Config, R: std::io::Read>( - src: &'__de mut R, +pub fn decode_from_with_config( + src: &mut R, _config: C, ) -> Result { let mut decoder = Decoder::<_, C>::new(src, _config); diff --git a/src/varint/decode_signed.rs b/src/varint/decode_signed.rs index 1eae254..d762344 100644 --- a/src/varint/decode_signed.rs +++ b/src/varint/decode_signed.rs @@ -1,8 +1,5 @@ -#![allow(unused_variables)] - use crate::{config::Endian, de::read::Reader, error::DecodeError}; -#[allow(dead_code)] pub fn varint_decode_i16<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -22,7 +19,6 @@ pub fn varint_decode_i16<'a, R: Reader<'a>>( }) } -#[allow(dead_code)] pub fn varint_decode_i32<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -42,7 +38,6 @@ pub fn varint_decode_i32<'a, R: Reader<'a>>( }) } -#[allow(dead_code)] pub fn varint_decode_i64<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -62,7 +57,6 @@ pub fn varint_decode_i64<'a, R: Reader<'a>>( }) } -#[allow(dead_code)] pub fn varint_decode_i128<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -82,7 +76,6 @@ pub fn varint_decode_i128<'a, R: Reader<'a>>( }) } -#[allow(dead_code)] pub fn varint_decode_isize<'a, R: Reader<'a>>( read: &mut R, endian: Endian, diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index 24d60d6..53ac0e7 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -5,7 +5,6 @@ use crate::{ error::{DecodeError, IntegerType}, }; -#[allow(dead_code)] pub fn varint_decode_u16<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -37,7 +36,6 @@ pub fn varint_decode_u16<'a, R: Reader<'a>>( } } -#[allow(dead_code)] pub fn varint_decode_u32<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -73,7 +71,6 @@ pub fn varint_decode_u32<'a, R: Reader<'a>>( } } -#[allow(dead_code)] pub fn varint_decode_u64<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -113,7 +110,6 @@ pub fn varint_decode_u64<'a, R: Reader<'a>>( } } -#[allow(dead_code)] pub fn varint_decode_usize<'a, R: Reader<'a>>( read: &mut R, endian: Endian, @@ -153,7 +149,6 @@ pub fn varint_decode_usize<'a, R: Reader<'a>>( } } -#[allow(dead_code)] pub fn varint_decode_u128<'a, R: Reader<'a>>( read: &mut R, endian: Endian, diff --git a/tests/derive.rs b/tests/derive.rs index c32701b..b6aa2fe 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -53,6 +53,7 @@ fn test_encodable() { assert_eq!(&slice[..bytes_written], &[10, 10, 20]); } +#[cfg(feature = "std")] #[test] fn test_decodable() { let start = Test2 { From a27b63b7fa8bf4122e166bd9715bd62538f19bec Mon Sep 17 00:00:00 2001 From: Trangar Date: Tue, 12 Oct 2021 15:53:02 +0200 Subject: [PATCH 32/80] Make bincode_derive 0 dependencies (#409) Removed `syn`, `quote` and `proc_macro2` dependency --- .github/workflows/rust.yml | 2 +- .gitignore | 1 + Cargo.toml | 9 +- derive/Cargo.toml | 33 +- derive/readme.md | 28 ++ derive/src/derive_enum.rs | 389 ++++++++++-------------- derive/src/derive_struct.rs | 208 +++++-------- derive/src/error.rs | 60 +++- derive/src/generate/generate_fn.rs | 134 ++++++++ derive/src/generate/generator.rs | 53 ++++ derive/src/generate/impl_for.rs | 73 +++++ derive/src/generate/mod.rs | 9 + derive/src/generate/stream_builder.rs | 95 ++++++ derive/src/lib.rs | 132 ++++++-- derive/src/parse/attributes.rs | 56 ++++ derive/src/parse/body.rs | 421 ++++++++++++++++++++++++++ derive/src/parse/data_type.rs | 77 +++++ derive/src/parse/generics.rs | 417 +++++++++++++++++++++++++ derive/src/parse/mod.rs | 142 +++++++++ derive/src/parse/visibility.rs | 68 +++++ src/de/mod.rs | 90 +++--- src/features/impl_alloc.rs | 27 ++ src/lib.rs | 122 ++++---- tests/derive.rs | 2 +- tests/serde.rs | 28 ++ 25 files changed, 2165 insertions(+), 511 deletions(-) create mode 100644 derive/readme.md create mode 100644 derive/src/generate/generate_fn.rs create mode 100644 derive/src/generate/generator.rs create mode 100644 derive/src/generate/impl_for.rs create mode 100644 derive/src/generate/mod.rs create mode 100644 derive/src/generate/stream_builder.rs create mode 100644 derive/src/parse/attributes.rs create mode 100644 derive/src/parse/body.rs create mode 100644 derive/src/parse/data_type.rs create mode 100644 derive/src/parse/generics.rs create mode 100644 derive/src/parse/mod.rs create mode 100644 derive/src/parse/visibility.rs create mode 100644 tests/serde.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fcd150f..8765a33 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -162,7 +162,7 @@ "uses": "actions-rs/tarpaulin@v0.1", "with": { "version": "0.18.2", - "args": "--exclude-files derive/" + "args": "--all" } }, { diff --git a/.gitignore b/.gitignore index 19231ce..29c90d8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .cargo .vscode rls*.log +tarpaulin-report.html diff --git a/Cargo.toml b/Cargo.toml index f2ef9eb..c188eb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ [package] name = "bincode" version = "2.0.0-dev" # remember to update html_root_url and bincode_derive -authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan "] +authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan ", "Victor Koenders "] exclude = ["logo.png", "examples/*", ".gitignore", ".github/"] publish = true @@ -30,4 +30,9 @@ derive = ["bincode_derive"] [dependencies] bincode_derive = { path = "derive", version = "2.0.0-dev", optional = true } -# serde = { version = "1.0.130", optional = true } +serde = { version = "1.0.130", optional = true } + +# Used for derive tests +[dev-dependencies] +serde_derive = "1.0.130" +serde_json = "1.0.68" diff --git a/derive/Cargo.toml b/derive/Cargo.toml index b4379a8..609a1df 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,16 +1,17 @@ -[package] -name = "bincode_derive" -version = "2.0.0-dev" # remember to update bincode -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] -quote = "1.0.9" -proc-macro2 = "1.0" - -[dependencies.syn] -version = "1.0.74" -default-features = false -features = ["parsing", "derive", "proc-macro", "printing", "clone-impls"] +[package] +name = "bincode_derive" +version = "2.0.0-dev" # remember to update bincode +authors = ["Zoey Riordan ", "Victor Koenders "] +edition = "2018" + +repository = "https://github.com/bincode-org/bincode" +documentation = "https://docs.rs/bincode_derive" +readme = "./readme.md" +categories = ["encoding", "network-programming"] +keywords = ["binary", "encode", "decode", "serialize", "deserialize"] + +[lib] +proc-macro = true + +[dev-dependencies] +proc-macro2 = "1.0" diff --git a/derive/readme.md b/derive/readme.md new file mode 100644 index 0000000..5dd5498 --- /dev/null +++ b/derive/readme.md @@ -0,0 +1,28 @@ +# Bincode-derive + +The derive crate for bincode. Implements `bincode::Encodable` and `bincode::Decodable`. + +This crate is roughly split into 2 parts: + +# Parsing + +Most of parsing is done in the `src/parse/` folder. This will generate the following types: +- `Attributes`, not being used currently +- `Visibility`, not being used currently +- `DataType` either `Struct` or `Enum`, with the name of the data type being parsed +- `Generics` the generics part of the type, e.g. `struct Foo<'a>` +- `GenericConstraints` the "where" part of the type + +# Generate + +Generating the code implementation is done in either `src/derive_enum.rs` and `src/derive_struct.rs`. + +This is supported by the structs in `src/generate`. The most notable points of this module are: +- `StreamBuilder` is a thin but friendly wrapper around `TokenStream` +- `Generator` is the base type of the code generator. This has helper methods to generate implementations: + - `ImplFor` is a helper struct for a single `impl A for B` construction. In this functions can be defined: + - `GenerateFnBody` is a helper struct for a single function in the above `impl`. This is created with a callback to `FnBuilder` which helps set some properties. `GenerateFnBody` has a `stream()` function which returns ` StreamBuilder` for the function. + +For additional derive testing, see the test cases in `../tests` + +For testing purposes, all generated code is outputted to the current `target` folder, under file name `_Encodeable.rs` and `_Decodeable.rs`. This can help with debugging. diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index e08c63c..6e06319 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,242 +1,187 @@ +use crate::generate::{FnSelfArg, Generator}; +use crate::parse::{EnumVariant, Fields}; +use crate::prelude::*; use crate::Result; -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{quote, ToTokens}; -use syn::{ - spanned::Spanned, Fields, GenericParam, Generics, Ident, Index, Lifetime, LifetimeDef, Variant, -}; + +const TUPLE_FIELD_PREFIX: &str = "field_"; + pub struct DeriveEnum { - name: Ident, - generics: Generics, - variants: Vec, + pub variants: Vec, } impl DeriveEnum { - pub fn parse(name: Ident, generics: Generics, en: syn::DataEnum) -> Result { - let variants = en.variants.into_iter().collect(); + pub fn generate_encodable(self, generator: &mut Generator) -> Result<()> { + let DeriveEnum { variants } = self; - Ok(DeriveEnum { - name, - generics, - variants, - }) + generator + .impl_for("bincode::enc::Encodeable") + .generate_fn("encode") + .with_generic("E", ["bincode::enc::Encode"]) + .with_self_arg(FnSelfArg::RefSelf) + .with_arg("mut encoder", "E") + .with_return_type("core::result::Result<(), bincode::error::EncodeError>") + .body(|fn_body| { + fn_body.ident_str("match"); + fn_body.ident_str("self"); + fn_body.group(Delimiter::Brace, |match_body| { + for (variant_index, variant) in variants.into_iter().enumerate() { + // Self::Variant + match_body.ident_str("Self"); + match_body.puncts("::"); + match_body.ident(variant.name.clone()); + + // if we have any fields, declare them here + // Self::Variant { a, b, c } + if let Some(delimiter) = variant.fields.delimiter() { + match_body.group(delimiter, |field_body| { + for (idx, field_name) in + variant.fields.names().into_iter().enumerate() + { + if idx != 0 { + field_body.punct(','); + } + field_body.push( + field_name.to_token_tree_with_prefix(TUPLE_FIELD_PREFIX), + ); + } + }); + } + + // Arrow + // Self::Variant { a, b, c } => + match_body.puncts("=>"); + + // Body of this variant + // Note that the fields are available as locals because of the match destructuring above + // { + // encoder.encode_u32(n)?; + // bincode::enc::Encodeable::encode(a, &mut encoder)?; + // bincode::enc::Encodeable::encode(b, &mut encoder)?; + // bincode::enc::Encodeable::encode(c, &mut encoder)?; + // } + match_body.group(Delimiter::Brace, |body| { + // variant index + body.push_parsed(format!("encoder.encode_u32({})?;", variant_index)); + // If we have any fields, encode them all one by one + for field_name in variant.fields.names() { + body.push_parsed(format!( + "bincode::enc::Encodeable::encode({}, &mut encoder)?;", + field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), + )); + } + }); + match_body.punct(','); + } + }); + fn_body.push_parsed("Ok(())"); + }); + Ok(()) } - pub fn generate_encodable(self) -> Result { - let DeriveEnum { - name, - generics, - variants, - } = self; + pub fn generate_decodable(self, generator: &mut Generator) -> Result<()> { + let DeriveEnum { variants } = self; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + if generator.has_lifetimes() { + // enum has a lifetime, implement BorrowDecodable - let match_arms = variants.iter().enumerate().map(|(index, variant)| { - let fields_section = fields_to_match_arm(&variant.fields); - let encode_statements = field_names_to_encodable(&fields_to_names(&variant.fields)); - let variant_name = variant.ident.clone(); - quote! { - #name :: #variant_name #fields_section => { - encoder.encode_u32(#index as u32)?; - #(#encode_statements)* - } - } - }); - let result = quote! { - impl #impl_generics bincode::enc::Encodeable for #name #ty_generics #where_clause { - fn encode(&self, mut encoder: E) -> Result<(), bincode::error::EncodeError> { - match self { - #(#match_arms)* - } - Ok(()) - } + generator.impl_for_with_de_lifetime("bincode::de::BorrowDecodable<'__de>") + .generate_fn("borrow_decode") + .with_generic("D", ["bincode::de::BorrowDecode<'__de>"]) + .with_arg("mut decoder", "D") + .with_return_type("Result") + .body(|fn_builder| { + fn_builder + .push_parsed("let variant_index = bincode::de::Decode::decode_u32(&mut decoder)?;"); + fn_builder.push_parsed("match variant_index"); + fn_builder.group(Delimiter::Brace, |variant_case| { + for (idx, variant) in variants.iter().enumerate() { + // idx => Ok(..) + variant_case.lit_u32(idx as u32); + variant_case.puncts("=>"); + variant_case.ident_str("Ok"); + variant_case.group(Delimiter::Parenthesis, |variant_case_body| { + // Self::Variant { } + // Self::Variant { 0: ..., 1: ... 2: ... }, + // Self::Variant { a: ..., b: ... c: ... }, + variant_case_body.ident_str("Self"); + variant_case_body.puncts("::"); + variant_case_body.ident(variant.name.clone()); - } - }; - - Ok(result.into()) - } - - pub fn generate_decodable(self) -> Result { - let DeriveEnum { - name, - generics, - variants, - } = self; - - let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - // check if the type has lifetimes - let mut should_insert_lifetime = false; - - for param in &generics.params { - if let GenericParam::Lifetime(_) = param { - should_insert_lifetime = true; - break; - } - } - - // if we don't have a '__de lifetime, insert it - let mut generics_with_decode_lifetime; - if should_insert_lifetime { - generics_with_decode_lifetime = generics.clone(); - - let mut new_lifetime = LifetimeDef::new(Lifetime::new("'__de", Span::call_site())); - - for param in &generics.params { - if let GenericParam::Lifetime(lt) = param { - new_lifetime.bounds.push(lt.lifetime.clone()) - } - } - - generics_with_decode_lifetime - .params - .push(GenericParam::Lifetime(new_lifetime)); - - impl_generics = generics_with_decode_lifetime.split_for_impl().0; - } - - let max_variant = (variants.len() - 1) as u32; - let match_arms = variants.iter().enumerate().map(|(index, variant)| { - let index = index as u32; - let decode_statements = field_names_to_decodable( - &fields_to_constructable_names(&variant.fields), - should_insert_lifetime, - ); - let variant_name = variant.ident.clone(); - quote! { - #index => { - #name :: #variant_name { - #(#decode_statements)* - } - } - } - }); - let result = if should_insert_lifetime { - quote! { - impl #impl_generics bincode::de::BorrowDecodable<'__de> for #name #ty_generics #where_clause { - fn borrow_decode>(mut decoder: D) -> Result { - let i = decoder.decode_u32()?; - Ok(match i { - #(#match_arms)* - variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ - min: 0, - max: #max_variant, - found: variant, - }) - }) + variant_case_body.group(Delimiter::Brace, |variant_body| { + let is_tuple = matches!(variant.fields, Fields::Tuple(_)); + for (idx, field) in variant.fields.names().into_iter().enumerate() { + if is_tuple { + variant_body.lit_usize(idx); + } else { + variant_body.ident(field.unwrap_ident().clone()); + } + variant_body.punct(':'); + variant_body.push_parsed("bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?,"); + } + }); + }); + variant_case.punct(','); } - } - } + // invalid idx + variant_case.push_parsed(format!( + "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant }})", + variants.len() - 1 + )); + }); + }); } else { - quote! { - impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { - fn decode(mut decoder: D) -> Result { - let i = decoder.decode_u32()?; - Ok(match i { - #(#match_arms)* - variant => return Err(bincode::error::DecodeError::UnexpectedVariant{ - min: 0, - max: #max_variant, - found: variant, - }) - }) - } + // enum has no lifetimes, implement Decodable + generator.impl_for("bincode::de::Decodable") + .generate_fn("decode") + .with_generic("D", ["bincode::de::Decode"]) + .with_arg("mut decoder", "D") + .with_return_type("Result") + .body(|fn_builder| { + + fn_builder + .push_parsed("let variant_index = bincode::de::Decode::decode_u32(&mut decoder)?;"); + fn_builder.push_parsed("match variant_index"); + fn_builder.group(Delimiter::Brace, |variant_case| { + for (idx, variant) in variants.iter().enumerate() { + // idx => Ok(..) + variant_case.lit_u32(idx as u32); + variant_case.puncts("=>"); + variant_case.ident_str("Ok"); + variant_case.group(Delimiter::Parenthesis, |variant_case_body| { + // Self::Variant { } + // Self::Variant { 0: ..., 1: ... 2: ... }, + // Self::Variant { a: ..., b: ... c: ... }, + variant_case_body.ident_str("Self"); + variant_case_body.puncts("::"); + variant_case_body.ident(variant.name.clone()); + + variant_case_body.group(Delimiter::Brace, |variant_body| { + let is_tuple = matches!(variant.fields, Fields::Tuple(_)); + for (idx, field) in variant.fields.names().into_iter().enumerate() { + if is_tuple { + variant_body.lit_usize(idx); + } else { + variant_body.ident(field.unwrap_ident().clone()); + } + variant_body.punct(':'); + variant_body.push_parsed("bincode::de::Decodable::decode(&mut decoder)?,"); + } + }); + }); + variant_case.punct(','); } - } - }; - Ok(result.into()) - } -} - -fn fields_to_match_arm(fields: &Fields) -> TokenStream2 { - match fields { - syn::Fields::Named(fields) => { - let fields: Vec<_> = fields - .named - .iter() - .map(|f| f.ident.clone().unwrap().to_token_stream()) - .collect(); - quote! { - {#(#fields),*} - } + // invalid idx + variant_case.push_parsed(format!( + "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant }})", + variants.len() - 1 + )); + }); + }); } - syn::Fields::Unnamed(fields) => { - let fields: Vec<_> = fields - .unnamed - .iter() - .enumerate() - .map(|(i, f)| Ident::new(&format!("_{}", i), f.span())) - .collect(); - quote! { - (#(#fields),*) - } - } - syn::Fields::Unit => quote! {}, + + Ok(()) } } - -fn fields_to_names(fields: &Fields) -> Vec { - match fields { - syn::Fields::Named(fields) => fields - .named - .iter() - .map(|f| f.ident.clone().unwrap().to_token_stream()) - .collect(), - syn::Fields::Unnamed(fields) => fields - .unnamed - .iter() - .enumerate() - .map(|(i, f)| Ident::new(&format!("_{}", i), f.span()).to_token_stream()) - .collect(), - syn::Fields::Unit => Vec::new(), - } -} - -fn field_names_to_encodable(names: &[TokenStream2]) -> Vec { - names - .iter() - .map(|field| { - quote! { - bincode::enc::Encodeable::encode(#field, &mut encoder)?; - } - }) - .collect::>() -} - -fn fields_to_constructable_names(fields: &Fields) -> Vec { - match fields { - syn::Fields::Named(fields) => fields - .named - .iter() - .map(|f| f.ident.clone().unwrap().to_token_stream()) - .collect(), - syn::Fields::Unnamed(fields) => fields - .unnamed - .iter() - .enumerate() - .map(|(i, _)| Index::from(i).to_token_stream()) - .collect(), - syn::Fields::Unit => Vec::new(), - } -} - -fn field_names_to_decodable(names: &[TokenStream2], borrowed: bool) -> Vec { - names - .iter() - .map(|field| { - if borrowed { - quote! { - #field: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?, - } - } else { - quote! { - #field: bincode::de::Decodable::decode(&mut decoder)?, - } - } - }) - .collect::>() -} diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 881545f..549f7d4 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,145 +1,97 @@ +use crate::generate::Generator; +use crate::parse::Fields; +use crate::prelude::Delimiter; use crate::Result; -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{quote, ToTokens}; -use syn::{GenericParam, Generics, Ident, Index, Lifetime, LifetimeDef}; pub struct DeriveStruct { - name: Ident, - generics: Generics, - fields: Vec, + pub fields: Fields, } impl DeriveStruct { - pub fn parse(name: Ident, generics: Generics, str: syn::DataStruct) -> Result { - let fields = match str.fields { - syn::Fields::Named(fields) => fields - .named - .iter() - .map(|f| f.ident.clone().unwrap().to_token_stream()) - .collect(), - syn::Fields::Unnamed(fields) => fields - .unnamed - .iter() - .enumerate() - .map(|(i, _)| Index::from(i).to_token_stream()) - .collect(), - syn::Fields::Unit => Vec::new(), - }; + pub fn generate_encodable(self, generator: &mut Generator) -> Result<()> { + let DeriveStruct { fields } = self; - Ok(Self { - name, - generics, - fields, - }) + let mut impl_for = generator.impl_for("bincode::enc::Encodeable"); + impl_for + .generate_fn("encode") + .with_generic("E", ["bincode::enc::Encode"]) + .with_self_arg(crate::generate::FnSelfArg::RefSelf) + .with_arg("mut encoder", "E") + .with_return_type("Result<(), bincode::error::EncodeError>") + .body(|fn_body| { + for field in fields.names() { + fn_body.push_parsed(format!( + "bincode::enc::Encodeable::encode(&self.{}, &mut encoder)?;", + field.to_string() + )); + } + fn_body.push_parsed("Ok(())"); + }); + + Ok(()) } - pub fn generate_encodable(self) -> Result { - let DeriveStruct { - name, - generics, - fields, - } = self; + pub fn generate_decodable(self, generator: &mut Generator) -> Result<()> { + let DeriveStruct { fields } = self; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + if generator.has_lifetimes() { + // struct has a lifetime, implement BorrowDecodable - let fields = fields - .into_iter() - .map(|field| { - quote! { - bincode::enc::Encodeable::encode(&self. #field, &mut encoder)?; - } - }) - .collect::>(); + generator + .impl_for_with_de_lifetime("bincode::de::BorrowDecodable<'__de>") + .generate_fn("borrow_decode") + .with_generic("D", ["bincode::de::BorrowDecode<'__de>"]) + .with_arg("mut decoder", "D") + .with_return_type("Result") + .body(|fn_body| { + // Ok(Self { + fn_body.ident_str("Ok"); + fn_body.group(Delimiter::Parenthesis, |ok_group| { + ok_group.ident_str("Self"); + ok_group.group(Delimiter::Brace, |struct_body| { + for field in fields.names() { + struct_body.push_parsed(format!( + "{}: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?,", + field.to_string() + )); + } + }); + }); + }); - let result = quote! { - impl #impl_generics bincode::enc::Encodeable for #name #ty_generics #where_clause { - fn encode(&self, mut encoder: E) -> Result<(), bincode::error::EncodeError> { - #(#fields)* - Ok(()) - } - - } - }; - Ok(result.into()) - } - - pub fn generate_decodable(self) -> Result { - let DeriveStruct { - name, - generics, - fields, - } = self; - - let (mut impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - // check if the type has lifetimes - let mut should_insert_lifetime = false; - - for param in &generics.params { - if let GenericParam::Lifetime(_) = param { - should_insert_lifetime = true; - break; - } - } - - // if the type has lifetimes, insert '__de and bound it to the lifetimes - let mut generics_with_decode_lifetime; - if should_insert_lifetime { - generics_with_decode_lifetime = generics.clone(); - let mut new_lifetime = LifetimeDef::new(Lifetime::new("'__de", Span::call_site())); - - for param in &generics.params { - if let GenericParam::Lifetime(lt) = param { - new_lifetime.bounds.push(lt.lifetime.clone()) - } - } - generics_with_decode_lifetime - .params - .push(GenericParam::Lifetime(new_lifetime)); - - impl_generics = generics_with_decode_lifetime.split_for_impl().0; - } - - let fields = fields - .into_iter() - .map(|field| { - if should_insert_lifetime { - quote! { - #field: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?, - } - } else { - quote! { - #field: bincode::de::Decodable::decode(&mut decoder)?, - } - } - }) - .collect::>(); - - let result = if should_insert_lifetime { - quote! { - impl #impl_generics bincode::de::BorrowDecodable<'__de> for #name #ty_generics #where_clause { - fn borrow_decode>(mut decoder: D) -> Result { - Ok(#name { - #(#fields)* - }) - } - - } - } + Ok(()) } else { - quote! { - impl #impl_generics bincode::de::Decodable for #name #ty_generics #where_clause { - fn decode(mut decoder: D) -> Result { - Ok(#name { - #(#fields)* - }) - } + // struct has no lifetimes, implement Decodable - } - } - }; + let mut impl_for = generator.impl_for("bincode::de::Decodable"); + impl_for + .generate_fn("decode") + .with_generic("D", ["bincode::de::Decode"]) + .with_arg("mut decoder", "D") + .with_return_type("Result") + .body(|fn_body| { + // Ok(Self { + fn_body.ident_str("Ok"); + fn_body.group(Delimiter::Parenthesis, |ok_group| { + ok_group.ident_str("Self"); + ok_group.group(Delimiter::Brace, |struct_body| { + // Fields + // { + // a: bincode::de::Decodable::decode(&mut decoder)?, + // b: bincode::de::Decodable::decode(&mut decoder)?, + // ... + // } + for field in fields.names() { + struct_body.push_parsed(format!( + "{}: bincode::de::Decodable::decode(&mut decoder)?,", + field.to_string() + )); + } + }); + }); + }); - Ok(result.into()) + Ok(()) + } } } diff --git a/derive/src/error.rs b/derive/src/error.rs index ff1abee..724c372 100644 --- a/derive/src/error.rs +++ b/derive/src/error.rs @@ -1,24 +1,70 @@ -use proc_macro::TokenStream; -use quote::__private::Span; +use crate::prelude::*; use std::fmt; +#[derive(Debug)] pub enum Error { - UnionNotSupported, + UnknownDataType(Span), + InvalidRustSyntax(Span), + ExpectedIdent(Span), +} + +// helper functions for the unit tests +#[cfg(test)] +impl Error { + pub fn is_unknown_data_type(&self) -> bool { + matches!(self, Error::UnknownDataType(_)) + } + + pub fn is_invalid_rust_syntax(&self) -> bool { + matches!(self, Error::InvalidRustSyntax(_)) + } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { - Self::UnionNotSupported => write!(fmt, "Unions are not supported"), + Self::UnknownDataType(_) => { + write!(fmt, "Unknown data type, only enum and struct are supported") + } + Self::InvalidRustSyntax(_) => write!(fmt, "Invalid rust syntax"), + Self::ExpectedIdent(_) => write!(fmt, "Expected ident"), } } } impl Error { pub fn into_token_stream(self) -> TokenStream { - self.into_token_stream_with_span(Span::call_site()) + let maybe_span = match &self { + Error::UnknownDataType(span) + | Error::ExpectedIdent(span) + | Error::InvalidRustSyntax(span) => Some(*span), + }; + self.throw_with_span(maybe_span.unwrap_or_else(Span::call_site)) } - pub fn into_token_stream_with_span(self, span: Span) -> TokenStream { - syn::Error::new(span, self).into_compile_error().into() + + pub fn throw_with_span(self, span: Span) -> TokenStream { + // compile_error!($message) + vec![ + TokenTree::Ident(Ident::new("compile_error", span)), + TokenTree::Punct({ + let mut punct = Punct::new('!', Spacing::Alone); + punct.set_span(span); + punct + }), + TokenTree::Group({ + let mut group = Group::new(Delimiter::Brace, { + TokenTree::Literal({ + let mut string = Literal::string(&self.to_string()); + string.set_span(span); + string + }) + .into() + }); + group.set_span(span); + group + }), + ] + .into_iter() + .collect() } } diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs new file mode 100644 index 0000000..53428ca --- /dev/null +++ b/derive/src/generate/generate_fn.rs @@ -0,0 +1,134 @@ +use super::{ImplFor, StreamBuilder}; +use crate::prelude::Delimiter; +pub struct FnBuilder<'a, 'b> { + generate: &'b mut ImplFor<'a>, + name: String, + + lifetime_and_generics: Vec<(String, Vec)>, + self_arg: FnSelfArg, + args: Vec<(String, String)>, + return_type: Option, +} + +impl<'a, 'b> FnBuilder<'a, 'b> { + pub(super) fn new(generate: &'b mut ImplFor<'a>, name: impl Into) -> Self { + Self { + generate, + name: name.into(), + lifetime_and_generics: Vec::new(), + self_arg: FnSelfArg::None, + args: Vec::new(), + return_type: None, + } + } + + pub fn with_generic(mut self, name: T, dependencies: U) -> Self + where + T: Into, + U: IntoIterator, + V: Into, + { + self.lifetime_and_generics.push(( + name.into(), + dependencies.into_iter().map(|d| d.into()).collect(), + )); + self + } + + pub fn with_self_arg(mut self, self_arg: FnSelfArg) -> Self { + self.self_arg = self_arg; + self + } + + pub fn with_arg(mut self, name: impl Into, ty: impl Into) -> Self { + self.args.push((name.into(), ty.into())); + self + } + + pub fn with_return_type(mut self, ret_type: impl Into) -> Self { + self.return_type = Some(ret_type.into()); + self + } + + pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) { + let FnBuilder { + generate, + name, + lifetime_and_generics, + self_arg, + args, + return_type, + } = self; + + let mut builder = StreamBuilder::new(); + + // function name; `fn name` + builder.ident_str("fn"); + builder.ident_str(name); + + // lifetimes; `<'a: 'b, D: Display>` + if !lifetime_and_generics.is_empty() { + builder.punct('<'); + for (idx, (lifetime_and_generic, dependencies)) in + lifetime_and_generics.into_iter().enumerate() + { + if idx != 0 { + builder.punct(','); + } + builder.ident_str(&lifetime_and_generic); + if !dependencies.is_empty() { + for (idx, dependency) in dependencies.into_iter().enumerate() { + builder.punct(if idx == 0 { ':' } else { '+' }); + builder.push_parsed(&dependency); + } + } + } + builder.punct('>'); + } + + // Arguments; `(&self, foo: &Bar)` + builder.group(Delimiter::Parenthesis, |arg_stream| { + if let Some(self_arg) = self_arg.into_token_tree() { + arg_stream.append(self_arg); + arg_stream.punct(','); + } + for (idx, (arg_name, arg_ty)) in args.into_iter().enumerate() { + if idx != 0 { + arg_stream.punct(','); + } + arg_stream.push_parsed(&arg_name); + arg_stream.punct(':'); + arg_stream.push_parsed(&arg_ty); + } + }); + + // Return type: `-> ResultType` + if let Some(return_type) = return_type { + builder.puncts("->"); + builder.push_parsed(&return_type); + } + + generate.group.append(builder); + + generate.group.group(Delimiter::Brace, body_builder); + } +} + +pub enum FnSelfArg { + None, + RefSelf, +} + +impl FnSelfArg { + fn into_token_tree(self) -> Option { + let mut builder = StreamBuilder::new(); + match self { + Self::None => return None, + Self::RefSelf => { + builder.punct('&'); + builder.ident_str("self"); + } + } + Some(builder) + } +} diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs new file mode 100644 index 0000000..94edf7d --- /dev/null +++ b/derive/src/generate/generator.rs @@ -0,0 +1,53 @@ +use super::{ImplFor, StreamBuilder}; +use crate::parse::{GenericConstraints, Generics}; +use crate::prelude::{Ident, TokenStream}; + +#[must_use] +pub struct Generator { + pub(super) name: Ident, + pub(super) generics: Option, + pub(super) generic_constraints: Option, + pub(super) stream: StreamBuilder, +} + +impl Generator { + pub(crate) fn new( + name: Ident, + generics: Option, + generic_constraints: Option, + ) -> Self { + Self { + name, + generics, + generic_constraints, + stream: StreamBuilder::new(), + } + } + + pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { + ImplFor::new(self, trait_name) + } + + pub fn impl_for_with_de_lifetime<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { + ImplFor::new_with_de_lifetime(self, trait_name) + } + + pub fn has_lifetimes(&self) -> bool { + self.generics + .as_ref() + .map(|g| g.has_lifetime()) + .unwrap_or(false) + } + + pub fn take_stream(mut self) -> TokenStream { + std::mem::take(&mut self.stream.stream) + } +} + +impl Drop for Generator { + fn drop(&mut self) { + if !self.stream.stream.is_empty() && !std::thread::panicking() { + panic!("Generator dropped but the stream is not empty. Please call `.take_stream()` on the generator"); + } + } +} diff --git a/derive/src/generate/impl_for.rs b/derive/src/generate/impl_for.rs new file mode 100644 index 0000000..753f206 --- /dev/null +++ b/derive/src/generate/impl_for.rs @@ -0,0 +1,73 @@ +use super::{FnBuilder, Generator, StreamBuilder}; +use crate::prelude::Delimiter; + +#[must_use] +pub struct ImplFor<'a> { + pub(super) generator: &'a mut Generator, + pub(super) group: StreamBuilder, +} + +impl<'a> ImplFor<'a> { + pub(super) fn new(generator: &'a mut Generator, trait_name: &str) -> Self { + let mut builder = StreamBuilder::new(); + builder.ident_str("impl"); + + if let Some(generics) = &generator.generics { + builder.append(generics.impl_generics()); + } + builder.push_parsed(trait_name); + builder.ident_str("for"); + builder.ident(generator.name.clone()); + + if let Some(generics) = &generator.generics { + builder.append(generics.type_generics()); + } + if let Some(generic_constraints) = &generator.generic_constraints { + builder.append(generic_constraints.where_clause()); + } + generator.stream.append(builder); + + let group = StreamBuilder::new(); + Self { generator, group } + } + + pub(super) fn new_with_de_lifetime(generator: &'a mut Generator, trait_name: &str) -> Self { + let mut builder = StreamBuilder::new(); + builder.ident_str("impl"); + + if let Some(generics) = &generator.generics { + builder.append(generics.impl_generics_with_additional_lifetime("__de")); + } else { + builder.punct('<'); + builder.lifetime_str("__de"); + builder.punct('>'); + } + + builder.push_parsed(trait_name); + builder.ident_str("for"); + builder.ident(generator.name.clone()); + if let Some(generics) = &generator.generics { + builder.append(generics.type_generics()); + } + if let Some(generic_constraints) = &generator.generic_constraints { + builder.append(generic_constraints.where_clause()); + } + generator.stream.append(builder); + + let group = StreamBuilder::new(); + Self { generator, group } + } + + pub fn generate_fn<'b>(&'b mut self, name: &str) -> FnBuilder<'a, 'b> { + FnBuilder::new(self, name) + } +} + +impl Drop for ImplFor<'_> { + fn drop(&mut self) { + let stream = std::mem::take(&mut self.group); + self.generator + .stream + .group(Delimiter::Brace, |builder| builder.append(stream)) + } +} diff --git a/derive/src/generate/mod.rs b/derive/src/generate/mod.rs new file mode 100644 index 0000000..696464d --- /dev/null +++ b/derive/src/generate/mod.rs @@ -0,0 +1,9 @@ +mod generate_fn; +mod generator; +mod impl_for; +mod stream_builder; + +pub use self::generate_fn::{FnBuilder, FnSelfArg}; +pub use self::generator::Generator; +pub use self::impl_for::ImplFor; +pub use self::stream_builder::StreamBuilder; diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs new file mode 100644 index 0000000..a1a0854 --- /dev/null +++ b/derive/src/generate/stream_builder.rs @@ -0,0 +1,95 @@ +use crate::prelude::{ + Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, +}; +use std::str::FromStr; + +#[must_use] +#[derive(Default)] +pub struct StreamBuilder { + pub(super) stream: TokenStream, +} + +impl StreamBuilder { + pub fn new() -> Self { + Self { + stream: TokenStream::new(), + } + } + + pub fn extend(&mut self, item: impl IntoIterator) { + self.stream.extend(item); + } + + pub fn append(&mut self, builder: StreamBuilder) { + self.stream.extend(builder.stream); + } + + pub fn push(&mut self, item: impl Into) { + self.stream.extend([item.into()]); + } + + pub fn push_parsed(&mut self, item: impl AsRef) { + self.stream + .extend(TokenStream::from_str(item.as_ref()).unwrap_or_else(|e| { + panic!( + "Could not parse string as rust: {:?}\n{:?}", + item.as_ref(), + e + ) + })); + } + + pub fn ident(&mut self, ident: Ident) { + self.stream.extend([TokenTree::Ident(ident)]); + } + + pub fn ident_str(&mut self, ident: impl AsRef) { + self.stream.extend([TokenTree::Ident(Ident::new( + ident.as_ref(), + Span::call_site(), + ))]); + } + + pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder)) { + let mut stream = StreamBuilder::new(); + inner(&mut stream); + self.stream + .extend([TokenTree::Group(Group::new(delim, stream.stream))]); + } + + pub fn punct(&mut self, p: char) { + self.stream + .extend([TokenTree::Punct(Punct::new(p, Spacing::Alone))]); + } + + pub fn puncts(&mut self, puncts: &str) { + self.stream.extend( + puncts + .chars() + .map(|char| TokenTree::Punct(Punct::new(char, Spacing::Joint))), + ); + } + + pub fn lifetime(&mut self, lt: Ident) { + self.stream.extend([ + TokenTree::Punct(Punct::new('\'', Spacing::Joint)), + TokenTree::Ident(lt), + ]); + } + pub fn lifetime_str(&mut self, lt: &str) { + self.stream.extend([ + TokenTree::Punct(Punct::new('\'', Spacing::Joint)), + TokenTree::Ident(Ident::new(lt, Span::call_site())), + ]); + } + + pub fn lit_u32(&mut self, val: u32) { + self.stream + .extend([TokenTree::Literal(Literal::u32_unsuffixed(val))]); + } + + pub fn lit_usize(&mut self, val: usize) { + self.stream + .extend([TokenTree::Literal(Literal::usize_unsuffixed(val))]); + } +} diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 2e91110..493f143 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -3,51 +3,127 @@ extern crate proc_macro; mod derive_enum; mod derive_struct; mod error; +mod generate; +mod parse; + +#[cfg(test)] +pub(crate) mod prelude { + pub use proc_macro2::*; +} +#[cfg(not(test))] +pub(crate) mod prelude { + pub use proc_macro::*; +} -use derive_enum::DeriveEnum; -use derive_struct::DeriveStruct; use error::Error; -use proc_macro::TokenStream; -use syn::{parse_macro_input, DeriveInput}; +use prelude::TokenStream; type Result = std::result::Result; #[proc_macro_derive(Encodable)] -pub fn derive_encodable(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - derive_encodable_inner(input).unwrap_or_else(|e| e.into_token_stream()) +pub fn derive_encodable(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + #[allow(clippy::useless_conversion)] + derive_encodable_inner(input.into()) + .unwrap_or_else(|e| e.into_token_stream()) + .into() } -fn derive_encodable_inner(input: DeriveInput) -> Result { - match input.data { - syn::Data::Struct(struct_definition) => { - DeriveStruct::parse(input.ident, input.generics, struct_definition) - .and_then(|str| str.generate_encodable()) +fn derive_encodable_inner(input: TokenStream) -> Result { + let source = &mut input.into_iter().peekable(); + + let _attributes = parse::Attributes::try_take(source)?; + let _visibility = parse::Visibility::try_take(source)?; + let (datatype, name) = parse::DataType::take(source)?; + let generics = parse::Generics::try_take(source)?; + let generic_constraints = parse::GenericConstraints::try_take(source)?; + + let mut generator = generate::Generator::new(name.clone(), generics, generic_constraints); + + match datatype { + parse::DataType::Struct => { + let body = parse::StructBody::take(source)?; + derive_struct::DeriveStruct { + fields: body.fields, + } + .generate_encodable(&mut generator)?; } - syn::Data::Enum(enum_definition) => { - DeriveEnum::parse(input.ident, input.generics, enum_definition) - .and_then(|str| str.generate_encodable()) + parse::DataType::Enum => { + let body = parse::EnumBody::take(source)?; + derive_enum::DeriveEnum { + variants: body.variants, + } + .generate_encodable(&mut generator)?; } - syn::Data::Union(_) => Err(Error::UnionNotSupported), } + + let stream = generator.take_stream(); + dump_output(name, "Encodeable", &stream); + Ok(stream) } #[proc_macro_derive(Decodable)] -pub fn derive_decodable(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - derive_decodable_inner(input).unwrap_or_else(|e| e.into_token_stream()) +pub fn derive_decodable(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + #[allow(clippy::useless_conversion)] + derive_decodable_inner(input.into()) + .unwrap_or_else(|e| e.into_token_stream()) + .into() } -fn derive_decodable_inner(input: DeriveInput) -> Result { - match input.data { - syn::Data::Struct(struct_definition) => { - DeriveStruct::parse(input.ident, input.generics, struct_definition) - .and_then(|str| str.generate_decodable()) +fn derive_decodable_inner(input: TokenStream) -> Result { + let source = &mut input.into_iter().peekable(); + + let _attributes = parse::Attributes::try_take(source)?; + let _visibility = parse::Visibility::try_take(source)?; + let (datatype, name) = parse::DataType::take(source)?; + let generics = parse::Generics::try_take(source)?; + let generic_constraints = parse::GenericConstraints::try_take(source)?; + + let mut generator = generate::Generator::new(name.clone(), generics, generic_constraints); + + match datatype { + parse::DataType::Struct => { + let body = parse::StructBody::take(source)?; + derive_struct::DeriveStruct { + fields: body.fields, + } + .generate_decodable(&mut generator)?; } - syn::Data::Enum(enum_definition) => { - DeriveEnum::parse(input.ident, input.generics, enum_definition) - .and_then(|str| str.generate_decodable()) + parse::DataType::Enum => { + let body = parse::EnumBody::take(source)?; + derive_enum::DeriveEnum { + variants: body.variants, + } + .generate_decodable(&mut generator)?; + } + } + + let stream = generator.take_stream(); + dump_output(name, "Decodeable", &stream); + Ok(stream) +} + +fn dump_output(name: crate::prelude::Ident, derive: &str, stream: &crate::prelude::TokenStream) { + use std::io::Write; + + if let Ok(var) = std::env::var("CARGO_MANIFEST_DIR") { + let mut path = std::path::PathBuf::from(var); + path.push("target"); + if path.exists() { + path.push(format!("{}_{}.rs", name, derive)); + if let Ok(mut file) = std::fs::File::create(path) { + let _ = file.write_all(stream.to_string().as_bytes()); + } } - syn::Data::Union(_) => Err(Error::UnionNotSupported), } } + +#[cfg(test)] +pub(crate) fn token_stream( + s: &str, +) -> std::iter::Peekable> { + use std::str::FromStr; + + let stream = proc_macro2::TokenStream::from_str(s) + .unwrap_or_else(|e| panic!("Could not parse code: {:?}\n{:?}", s, e)); + stream.into_iter().peekable() +} diff --git a/derive/src/parse/attributes.rs b/derive/src/parse/attributes.rs new file mode 100644 index 0000000..74d194f --- /dev/null +++ b/derive/src/parse/attributes.rs @@ -0,0 +1,56 @@ +use super::assume_group; +use crate::parse::consume_punct_if; +use crate::prelude::{Delimiter, Group, Punct, TokenTree}; +use crate::{Error, Result}; +use std::iter::Peekable; + +#[derive(Debug)] +pub struct Attributes { + // we don't use these fields yet + #[allow(dead_code)] + punct: Punct, + #[allow(dead_code)] + tokens: Group, +} + +impl Attributes { + pub fn try_take(input: &mut Peekable>) -> Result> { + if let Some(punct) = consume_punct_if(input, '#') { + // found attributes, next token should be a [] group + if let Some(TokenTree::Group(g)) = input.peek() { + if g.delimiter() != Delimiter::Bracket { + return Err(Error::InvalidRustSyntax(g.span())); + } + return Ok(Some(Attributes { + punct, + tokens: assume_group(input.next()), + })); + } + // expected [] group, found something else + return Err(Error::InvalidRustSyntax(match input.peek() { + Some(next_token) => next_token.span(), + None => punct.span(), + })); + } + Ok(None) + } +} + +#[test] +fn test_attributes_try_take() { + use crate::token_stream; + + let stream = &mut token_stream("struct Foo;"); + assert!(Attributes::try_take(stream).unwrap().is_none()); + match stream.next().unwrap() { + TokenTree::Ident(i) => assert_eq!(i, "struct"), + x => panic!("Expected ident, found {:?}", x), + } + + let stream = &mut token_stream("#[cfg(test)] struct Foo;"); + assert!(Attributes::try_take(stream).unwrap().is_some()); + match stream.next().unwrap() { + TokenTree::Ident(i) => assert_eq!(i, "struct"), + x => panic!("Expected ident, found {:?}", x), + } +} diff --git a/derive/src/parse/body.rs b/derive/src/parse/body.rs new file mode 100644 index 0000000..ff9689d --- /dev/null +++ b/derive/src/parse/body.rs @@ -0,0 +1,421 @@ +use super::{assume_group, assume_ident, read_tokens_until_punct, Attributes, Visibility}; +use crate::parse::consume_punct_if; +use crate::prelude::{Delimiter, Ident, Span, TokenTree}; +use crate::{Error, Result}; +use std::iter::Peekable; + +#[derive(Debug)] +pub struct StructBody { + pub fields: Fields, +} + +impl StructBody { + pub fn take(input: &mut Peekable>) -> Result { + match input.peek() { + Some(TokenTree::Group(_)) => {} + Some(TokenTree::Punct(p)) if p.as_char() == ';' => { + return Ok(StructBody { + fields: Fields::Unit, + }) + } + Some(t) => { + return Err(Error::InvalidRustSyntax(t.span())); + } + _ => { + return Err(Error::InvalidRustSyntax(Span::call_site())); + } + } + let group = assume_group(input.next()); + let mut stream = group.stream().into_iter().peekable(); + let fields = match group.delimiter() { + Delimiter::Brace => Fields::Struct(UnnamedField::parse_with_name(&mut stream)?), + Delimiter::Parenthesis => Fields::Tuple(UnnamedField::parse(&mut stream)?), + _ => return Err(Error::InvalidRustSyntax(group.span())), + }; + Ok(StructBody { fields }) + } +} + +#[test] +fn test_struct_body_take() { + use crate::token_stream; + + let stream = &mut token_stream( + "struct Foo { pub bar: u8, pub(crate) baz: u32, bla: Vec>> }", + ); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let body = StructBody::take(stream).unwrap(); + + assert_eq!(body.fields.len(), 3); + let (ident, field) = body.fields.get(0).unwrap(); + assert_eq!(ident.unwrap(), "bar"); + assert_eq!(field.vis, Visibility::Pub); + assert_eq!(field.type_string(), "u8"); + + let (ident, field) = body.fields.get(1).unwrap(); + assert_eq!(ident.unwrap(), "baz"); + assert_eq!(field.vis, Visibility::Pub); + assert_eq!(field.type_string(), "u32"); + + let (ident, field) = body.fields.get(2).unwrap(); + assert_eq!(ident.unwrap(), "bla"); + assert_eq!(field.vis, Visibility::Default); + assert_eq!(field.type_string(), "Vec>>"); + + let stream = &mut token_stream( + "struct Foo ( pub u8, pub(crate) u32, Vec>> )", + ); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let body = StructBody::take(stream).unwrap(); + + assert_eq!(body.fields.len(), 3); + + let (ident, field) = body.fields.get(0).unwrap(); + assert!(ident.is_none()); + assert_eq!(field.vis, Visibility::Pub); + assert_eq!(field.type_string(), "u8"); + + let (ident, field) = body.fields.get(1).unwrap(); + assert!(ident.is_none()); + assert_eq!(field.vis, Visibility::Pub); + assert_eq!(field.type_string(), "u32"); + + let (ident, field) = body.fields.get(2).unwrap(); + assert!(ident.is_none()); + assert_eq!(field.vis, Visibility::Default); + assert_eq!(field.type_string(), "Vec>>"); + + let stream = &mut token_stream("struct Foo;"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let body = StructBody::take(stream).unwrap(); + assert_eq!(body.fields.len(), 0); + + let stream = &mut token_stream("struct Foo {}"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let body = StructBody::take(stream).unwrap(); + assert_eq!(body.fields.len(), 0); + + let stream = &mut token_stream("struct Foo ()"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + assert_eq!(body.fields.len(), 0); +} + +#[derive(Debug)] +pub struct EnumBody { + pub variants: Vec, +} + +impl EnumBody { + pub fn take(input: &mut Peekable>) -> Result { + match input.peek() { + Some(TokenTree::Group(_)) => {} + Some(TokenTree::Punct(p)) if p.as_char() == ';' => { + return Ok(EnumBody { + variants: Vec::new(), + }) + } + Some(t) => { + return Err(Error::InvalidRustSyntax(t.span())); + } + _ => { + return Err(Error::InvalidRustSyntax(Span::call_site())); + } + } + let group = assume_group(input.next()); + let mut variants = Vec::new(); + let stream = &mut group.stream().into_iter().peekable(); + while stream.peek().is_some() { + let attributes = Attributes::try_take(stream)?; + let ident = match stream.peek() { + Some(TokenTree::Ident(_)) => assume_ident(stream.next()), + Some(x) => return Err(Error::InvalidRustSyntax(x.span())), + None => return Err(Error::InvalidRustSyntax(Span::call_site())), + }; + + let mut fields = Fields::Unit; + + if let Some(TokenTree::Group(_)) = stream.peek() { + let group = assume_group(stream.next()); + let stream = &mut group.stream().into_iter().peekable(); + match group.delimiter() { + Delimiter::Brace => { + fields = Fields::Struct(UnnamedField::parse_with_name(stream)?) + } + Delimiter::Parenthesis => fields = Fields::Tuple(UnnamedField::parse(stream)?), + _ => return Err(Error::InvalidRustSyntax(group.span())), + } + } + consume_punct_if(stream, ','); + + variants.push(EnumVariant { + name: ident, + fields, + attributes, + }); + } + + Ok(EnumBody { variants }) + } +} + +#[test] +fn test_enum_body_take() { + use crate::token_stream; + + let stream = &mut token_stream("enum Foo { }"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Enum); + assert_eq!(ident, "Foo"); + let body = EnumBody::take(stream).unwrap(); + assert_eq!(0, body.variants.len()); + + let stream = &mut token_stream("enum Foo { Bar, Baz(u8), Blah { a: u32, b: u128 } }"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Enum); + assert_eq!(ident, "Foo"); + let body = EnumBody::take(stream).unwrap(); + assert_eq!(3, body.variants.len()); + + assert_eq!(body.variants[0].name, "Bar"); + assert!(body.variants[0].fields.is_unit()); + + assert_eq!(body.variants[1].name, "Baz"); + assert_eq!(1, body.variants[1].fields.len()); + let (ident, field) = body.variants[1].fields.get(0).unwrap(); + assert!(ident.is_none()); + assert_eq!(field.type_string(), "u8"); + + assert_eq!(body.variants[2].name, "Blah"); + assert_eq!(2, body.variants[2].fields.len()); + let (ident, field) = body.variants[2].fields.get(0).unwrap(); + assert_eq!(ident.unwrap(), "a"); + assert_eq!(field.type_string(), "u32"); + let (ident, field) = body.variants[2].fields.get(1).unwrap(); + assert_eq!(ident.unwrap(), "b"); + assert_eq!(field.type_string(), "u128"); +} + +#[derive(Debug)] +pub struct EnumVariant { + pub name: Ident, + pub fields: Fields, + pub attributes: Option, +} + +#[derive(Debug)] +pub enum Fields { + /// Empty variant. + /// ```rs + /// enum Foo { + /// Baz, + /// } + /// struct Bar { } + /// ``` + Unit, + + /// Tuple-like variant + /// ```rs + /// enum Foo { + /// Baz(u32) + /// } + /// struct Bar(u32); + /// ``` + Tuple(Vec), + + /// Struct-like variant + /// ```rs + /// enum Foo { + /// Baz { + /// baz: u32 + /// } + /// } + /// struct Bar { + /// baz: u32 + /// } + /// ``` + Struct(Vec<(Ident, UnnamedField)>), +} + +impl Fields { + pub fn names(&self) -> Vec { + match self { + Self::Tuple(fields) => fields + .iter() + .enumerate() + .map(|(idx, field)| IdentOrIndex::Index(idx, field.span())) + .collect(), + Self::Struct(fields) => fields + .iter() + .map(|(ident, _)| IdentOrIndex::Ident(ident)) + .collect(), + Self::Unit => Vec::new(), + } + } + + pub fn delimiter(&self) -> Option { + match self { + Self::Tuple(_) => Some(Delimiter::Parenthesis), + Self::Struct(_) => Some(Delimiter::Brace), + Self::Unit => None, + } + } +} + +#[cfg(test)] +impl Fields { + pub fn is_unit(&self) -> bool { + matches!(self, Self::Unit) + } + + pub fn len(&self) -> usize { + match self { + Self::Tuple(fields) => fields.len(), + Self::Struct(fields) => fields.len(), + Self::Unit => 0, + } + } + + pub fn get(&self, index: usize) -> Option<(Option<&Ident>, &UnnamedField)> { + match self { + Self::Tuple(fields) => fields.get(index).map(|f| (None, f)), + Self::Struct(fields) => fields.get(index).map(|(ident, field)| (Some(ident), field)), + Self::Unit => None, + } + } +} + +#[derive(Debug)] +pub struct UnnamedField { + pub vis: Visibility, + pub r#type: Vec, + pub attributes: Option, +} + +impl UnnamedField { + pub fn parse_with_name( + input: &mut Peekable>, + ) -> Result> { + let mut result = Vec::new(); + loop { + let attributes = Attributes::try_take(input)?; + let vis = Visibility::try_take(input)?; + + let ident = match input.peek() { + Some(TokenTree::Ident(_)) => assume_ident(input.next()), + Some(x) => return Err(Error::InvalidRustSyntax(x.span())), + None => break, + }; + match input.peek() { + Some(TokenTree::Punct(p)) if p.as_char() == ':' => { + input.next(); + } + Some(x) => return Err(Error::InvalidRustSyntax(x.span())), + None => return Err(Error::InvalidRustSyntax(Span::call_site())), + } + let r#type = read_tokens_until_punct(input, &[','])?; + consume_punct_if(input, ','); + result.push(( + ident, + Self { + vis, + r#type, + attributes, + }, + )); + } + Ok(result) + } + + pub fn parse(input: &mut Peekable>) -> Result> { + let mut result = Vec::new(); + while input.peek().is_some() { + let attributes = Attributes::try_take(input)?; + let vis = Visibility::try_take(input)?; + + let r#type = read_tokens_until_punct(input, &[','])?; + consume_punct_if(input, ','); + result.push(Self { + vis, + r#type, + attributes, + }); + } + Ok(result) + } + + #[cfg(test)] + pub fn type_string(&self) -> String { + self.r#type.iter().map(|t| t.to_string()).collect() + } + + pub fn span(&self) -> Span { + // BlockedTODO: https://github.com/rust-lang/rust/issues/54725 + // Span::join is unstable + // if let Some(first) = self.r#type.first() { + // let mut span = first.span(); + // for token in self.r#type.iter().skip(1) { + // span = span.join(span).unwrap(); + // } + // span + // } else { + // Span::call_site() + // } + + match self.r#type.first() { + Some(first) => first.span(), + None => Span::call_site(), + } + } +} + +#[derive(Debug)] +pub enum IdentOrIndex<'a> { + Ident(&'a Ident), + Index(usize, Span), +} + +impl<'a> IdentOrIndex<'a> { + pub fn unwrap_ident(&self) -> &'a Ident { + match self { + Self::Ident(i) => i, + x => panic!("Expected ident, found {:?}", x), + } + } + + pub fn to_token_tree_with_prefix(&self, prefix: &str) -> TokenTree { + TokenTree::Ident(match self { + IdentOrIndex::Ident(i) => (*i).clone(), + IdentOrIndex::Index(idx, span) => { + let name = format!("{}{}", prefix, idx); + Ident::new(&name, *span) + } + }) + } + pub fn to_string_with_prefix(&self, prefix: &str) -> String { + match self { + IdentOrIndex::Ident(i) => i.to_string(), + IdentOrIndex::Index(idx, _) => { + format!("{}{}", prefix, idx) + } + } + } +} + +impl std::fmt::Display for IdentOrIndex<'_> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + IdentOrIndex::Ident(i) => write!(fmt, "{}", i), + IdentOrIndex::Index(idx, _) => write!(fmt, "{}", idx), + } + } +} diff --git a/derive/src/parse/data_type.rs b/derive/src/parse/data_type.rs new file mode 100644 index 0000000..64d0760 --- /dev/null +++ b/derive/src/parse/data_type.rs @@ -0,0 +1,77 @@ +use crate::prelude::{Ident, Span, TokenTree}; +use crate::{Error, Result}; +use std::iter::Peekable; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DataType { + Enum, + Struct, +} + +impl DataType { + pub fn take(input: &mut Peekable>) -> Result<(Self, Ident)> { + if let Some(TokenTree::Ident(ident)) = input.peek() { + let result = match ident.to_string().as_str() { + "struct" => DataType::Struct, + "enum" => DataType::Enum, + _ => return Err(Error::UnknownDataType(ident.span())), + }; + let ident = super::assume_ident(input.next()); + return match input.next() { + Some(TokenTree::Ident(ident)) => Ok((result, ident)), + Some(t) => Err(Error::InvalidRustSyntax(t.span())), + None => Err(Error::InvalidRustSyntax(ident.span())), + }; + } + let span = input + .peek() + .map(|t| t.span()) + .unwrap_or_else(Span::call_site); + Err(Error::InvalidRustSyntax(span)) + } +} + +#[test] +fn test_datatype_take() { + use crate::token_stream; + + fn validate_output_eq(input: &str, expected_dt: DataType, expected_ident: &str) { + let (dt, ident) = DataType::take(&mut token_stream(input)).unwrap_or_else(|e| { + panic!("Could not parse tokenstream {:?}: {:?}", input, e); + }); + if dt != expected_dt || ident != expected_ident { + println!("While parsing {:?}", input); + panic!( + "Expected {:?} {:?}, received {:?} {:?}", + dt, ident, expected_dt, expected_ident + ); + } + } + + assert!(DataType::take(&mut token_stream("enum")) + .unwrap_err() + .is_invalid_rust_syntax()); + validate_output_eq("enum Foo", DataType::Enum, "Foo"); + validate_output_eq("enum Foo { }", DataType::Enum, "Foo"); + validate_output_eq("enum Foo { bar, baz }", DataType::Enum, "Foo"); + validate_output_eq("enum Foo<'a, T> { bar, baz }", DataType::Enum, "Foo"); + + assert!(DataType::take(&mut token_stream("struct")) + .unwrap_err() + .is_invalid_rust_syntax()); + validate_output_eq("struct Foo { }", DataType::Struct, "Foo"); + validate_output_eq("struct Foo { bar: u32, baz: u32 }", DataType::Struct, "Foo"); + validate_output_eq("struct Foo<'a, T> { bar: &'a T }", DataType::Struct, "Foo"); + + assert!(DataType::take(&mut token_stream("fn foo() {}")) + .unwrap_err() + .is_unknown_data_type()); + + assert!(DataType::take(&mut token_stream("() {}")) + .unwrap_err() + .is_invalid_rust_syntax()); + + assert!(DataType::take(&mut token_stream("")) + .unwrap_err() + .is_invalid_rust_syntax()); +} diff --git a/derive/src/parse/generics.rs b/derive/src/parse/generics.rs new file mode 100644 index 0000000..3af1581 --- /dev/null +++ b/derive/src/parse/generics.rs @@ -0,0 +1,417 @@ +use super::assume_punct; +use crate::generate::StreamBuilder; +use crate::parse::{ident_eq, read_tokens_until_punct}; +use crate::prelude::{Ident, TokenTree}; +use crate::{Error, Result}; +use std::iter::Peekable; + +#[derive(Debug)] +pub struct Generics { + lifetimes_and_generics: Vec, +} + +impl Generics { + pub fn try_take(input: &mut Peekable>) -> Result> { + let maybe_punct = input.peek(); + if let Some(TokenTree::Punct(punct)) = maybe_punct { + if punct.as_char() == '<' { + let punct = super::assume_punct(input.next(), '<'); + let mut result = Generics { + lifetimes_and_generics: Vec::new(), + }; + loop { + match input.peek() { + Some(TokenTree::Punct(punct)) if punct.as_char() == '\'' => { + result + .lifetimes_and_generics + .push(Lifetime::take(input)?.into()); + super::consume_punct_if(input, ','); + } + Some(TokenTree::Punct(punct)) if punct.as_char() == '>' => { + assume_punct(input.next(), '>'); + break; + } + Some(TokenTree::Ident(_)) => { + result + .lifetimes_and_generics + .push(Generic::take(input)?.into()); + super::consume_punct_if(input, ','); + } + x => { + return Err(Error::InvalidRustSyntax( + x.map(|x| x.span()).unwrap_or_else(|| punct.span()), + )); + } + } + } + return Ok(Some(result)); + } + } + Ok(None) + } + + pub fn has_lifetime(&self) -> bool { + self.lifetimes_and_generics + .iter() + .any(|lt| lt.is_lifetime()) + } + + pub fn impl_generics(&self) -> StreamBuilder { + let mut result = StreamBuilder::new(); + result.punct('<'); + + for (idx, generic) in self.lifetimes_and_generics.iter().enumerate() { + if idx > 0 { + result.punct(','); + } + + if generic.is_lifetime() { + result.lifetime(generic.ident()); + } else { + result.ident(generic.ident()); + } + + if generic.has_constraints() { + result.punct(':'); + result.extend(generic.constraints()); + } + } + + result.punct('>'); + + result + } + + pub fn impl_generics_with_additional_lifetime(&self, lifetime: &str) -> StreamBuilder { + assert!(self.has_lifetime()); + + let mut result = StreamBuilder::new(); + result.punct('<'); + result.lifetime_str(lifetime); + + if self.has_lifetime() { + for (idx, lt) in self + .lifetimes_and_generics + .iter() + .filter_map(|lt| lt.as_lifetime()) + .enumerate() + { + result.punct(if idx == 0 { ':' } else { '+' }); + result.lifetime(lt.ident.clone()); + } + } + + for generic in &self.lifetimes_and_generics { + result.punct(','); + + if generic.is_lifetime() { + result.lifetime(generic.ident()); + } else { + result.ident(generic.ident()); + } + + if generic.has_constraints() { + result.punct(':'); + result.extend(generic.constraints()); + } + } + + result.punct('>'); + + result + } + + pub fn type_generics(&self) -> StreamBuilder { + let mut result = StreamBuilder::new(); + result.punct('<'); + + for (idx, generic) in self.lifetimes_and_generics.iter().enumerate() { + if idx > 0 { + result.punct(','); + } + if generic.is_lifetime() { + result.lifetime(generic.ident()); + } else { + result.ident(generic.ident()); + } + } + + result.punct('>'); + result + } +} + +#[derive(Debug)] +enum LifetimeOrGeneric { + Lifetime(Lifetime), + Generic(Generic), +} + +impl LifetimeOrGeneric { + fn is_lifetime(&self) -> bool { + matches!(self, LifetimeOrGeneric::Lifetime(_)) + } + + fn ident(&self) -> Ident { + match self { + Self::Lifetime(lt) => lt.ident.clone(), + Self::Generic(gen) => gen.ident.clone(), + } + } + + fn as_lifetime(&self) -> Option<&Lifetime> { + match self { + Self::Lifetime(lt) => Some(lt), + Self::Generic(_) => None, + } + } + + fn has_constraints(&self) -> bool { + match self { + Self::Lifetime(lt) => !lt.constraint.is_empty(), + Self::Generic(gen) => !gen.constraints.is_empty(), + } + } + + fn constraints(&self) -> Vec { + match self { + Self::Lifetime(lt) => lt.constraint.clone(), + Self::Generic(gen) => gen.constraints.clone(), + } + } +} + +impl From for LifetimeOrGeneric { + fn from(lt: Lifetime) -> Self { + Self::Lifetime(lt) + } +} + +impl From for LifetimeOrGeneric { + fn from(gen: Generic) -> Self { + Self::Generic(gen) + } +} + +#[test] +fn test_generics_try_take() { + use crate::token_stream; + + assert!(Generics::try_take(&mut token_stream("")).unwrap().is_none()); + assert!(Generics::try_take(&mut token_stream("foo")) + .unwrap() + .is_none()); + assert!(Generics::try_take(&mut token_stream("()")) + .unwrap() + .is_none()); + + let stream = &mut token_stream("struct Foo<'a, T>()"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let generics = Generics::try_take(stream).unwrap().unwrap(); + assert_eq!(generics.lifetimes_and_generics.len(), 2); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "a"); + assert_eq!(generics.lifetimes_and_generics[1].ident(), "T"); + + let stream = &mut token_stream("struct Foo()"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let generics = Generics::try_take(stream).unwrap().unwrap(); + assert_eq!(generics.lifetimes_and_generics.len(), 2); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "A"); + assert_eq!(generics.lifetimes_and_generics[1].ident(), "B"); + + let stream = &mut token_stream("struct Foo<'a, T: Display>()"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + let generics = Generics::try_take(stream).unwrap().unwrap(); + dbg!(&generics); + assert_eq!(generics.lifetimes_and_generics.len(), 2); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "a"); + assert_eq!(generics.lifetimes_and_generics[1].ident(), "T"); + + let stream = &mut token_stream("struct Foo<'a, T: for<'a> Bar<'a> + 'static>()"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Foo"); + dbg!(&generics); + assert_eq!(generics.lifetimes_and_generics.len(), 2); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "a"); + assert_eq!(generics.lifetimes_and_generics[1].ident(), "T"); + + let stream = &mut token_stream( + "struct Baz Bar<'a, for<'b> Bar<'b, for<'c> Bar<'c, u32>>>> {}", + ); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Baz"); + let generics = Generics::try_take(stream).unwrap().unwrap(); + dbg!(&generics); + assert_eq!(generics.lifetimes_and_generics.len(), 1); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "T"); + + let stream = &mut token_stream("struct Baz<()> {}"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Baz"); + assert!(Generics::try_take(stream) + .unwrap_err() + .is_invalid_rust_syntax()); + + let stream = &mut token_stream("struct Bar SomeStruct, B>"); + let (data_type, ident) = super::DataType::take(stream).unwrap(); + assert_eq!(data_type, super::DataType::Struct); + assert_eq!(ident, "Bar"); + let generics = Generics::try_take(stream).unwrap().unwrap(); + dbg!(&generics); + assert_eq!(generics.lifetimes_and_generics.len(), 2); + assert_eq!(generics.lifetimes_and_generics[0].ident(), "A"); + assert_eq!(generics.lifetimes_and_generics[1].ident(), "B"); +} + +#[derive(Debug)] +pub struct Lifetime { + ident: Ident, + constraint: Vec, +} + +impl Lifetime { + pub fn take(input: &mut Peekable>) -> Result { + let start = super::assume_punct(input.next(), '\''); + let ident = match input.peek() { + Some(TokenTree::Ident(_)) => super::assume_ident(input.next()), + Some(t) => return Err(Error::ExpectedIdent(t.span())), + None => return Err(Error::ExpectedIdent(start.span())), + }; + + let mut constraint = Vec::new(); + if let Some(TokenTree::Punct(p)) = input.peek() { + if p.as_char() == ':' { + assume_punct(input.next(), ':'); + constraint = super::read_tokens_until_punct(input, &[',', '>'])?; + } + } + + Ok(Self { ident, constraint }) + } + + #[cfg(test)] + fn is_ident(&self, s: &str) -> bool { + self.ident.to_string() == s + } +} + +#[test] +fn test_lifetime_take() { + use crate::token_stream; + use std::panic::catch_unwind; + assert!(Lifetime::take(&mut token_stream("'a")) + .unwrap() + .is_ident("a")); + assert!(catch_unwind(|| Lifetime::take(&mut token_stream("'0"))).is_err()); + assert!(catch_unwind(|| Lifetime::take(&mut token_stream("'("))).is_err()); + assert!(catch_unwind(|| Lifetime::take(&mut token_stream("')"))).is_err()); + assert!(catch_unwind(|| Lifetime::take(&mut token_stream("'0'"))).is_err()); + + let stream = &mut token_stream("'a: 'b>"); + let lifetime = Lifetime::take(stream).unwrap(); + assert_eq!(lifetime.ident, "a"); + assert_eq!(lifetime.constraint.len(), 2); + assume_punct(stream.next(), '>'); + assert!(stream.next().is_none()); +} + +#[derive(Debug)] +pub struct Generic { + ident: Ident, + constraints: Vec, +} + +impl Generic { + pub fn take(input: &mut Peekable>) -> Result { + let ident = super::assume_ident(input.next()); + let mut constraints = Vec::new(); + if let Some(TokenTree::Punct(punct)) = input.peek() { + if punct.as_char() == ':' { + super::assume_punct(input.next(), ':'); + constraints = super::read_tokens_until_punct(input, &['>', ','])?; + } + } + Ok(Generic { ident, constraints }) + } +} + +#[derive(Debug)] +pub struct GenericConstraints { + constraints: Vec, +} + +impl GenericConstraints { + pub fn try_take(input: &mut Peekable>) -> Result> { + match input.peek() { + Some(TokenTree::Ident(ident)) => { + if !ident_eq(ident, "where") { + return Ok(None); + } + } + _ => { + return Ok(None); + } + } + input.next(); + let constraints = read_tokens_until_punct(input, &['{', '('])?; + Ok(Some(Self { constraints })) + } + + pub fn where_clause(&self) -> StreamBuilder { + let mut result = StreamBuilder::new(); + result.ident_str("where"); + result.extend(self.constraints.clone()); + result + } +} + +#[test] +fn test_generic_constraints_try_take() { + use super::{DataType, StructBody, Visibility}; + use crate::token_stream; + + let stream = &mut token_stream("struct Foo where Foo: Bar { }"); + super::DataType::take(stream).unwrap(); + assert!(GenericConstraints::try_take(stream).unwrap().is_some()); + + let stream = &mut token_stream("struct Foo { }"); + super::DataType::take(stream).unwrap(); + assert!(GenericConstraints::try_take(stream).unwrap().is_none()); + + let stream = &mut token_stream("struct Foo where Foo: Bar(Foo)"); + super::DataType::take(stream).unwrap(); + assert!(GenericConstraints::try_take(stream).unwrap().is_some()); + + let stream = &mut token_stream("struct Foo()"); + super::DataType::take(stream).unwrap(); + assert!(GenericConstraints::try_take(stream).unwrap().is_none()); + + let stream = &mut token_stream("struct Foo()"); + assert!(GenericConstraints::try_take(stream).unwrap().is_none()); + + let stream = &mut token_stream("{}"); + assert!(GenericConstraints::try_take(stream).unwrap().is_none()); + + let stream = &mut token_stream(""); + assert!(GenericConstraints::try_take(stream).unwrap().is_none()); + + let stream = &mut token_stream("pub(crate) struct Test {}"); + assert_eq!(Visibility::Pub, Visibility::try_take(stream).unwrap()); + let (data_type, ident) = DataType::take(stream).unwrap(); + assert_eq!(data_type, DataType::Struct); + assert_eq!(ident, "Test"); + let constraints = Generics::try_take(stream).unwrap().unwrap(); + assert_eq!(constraints.lifetimes_and_generics.len(), 1); + assert_eq!(constraints.lifetimes_and_generics[0].ident(), "T"); + let body = StructBody::take(stream).unwrap(); + assert_eq!(body.fields.len(), 0); +} diff --git a/derive/src/parse/mod.rs b/derive/src/parse/mod.rs new file mode 100644 index 0000000..e888abb --- /dev/null +++ b/derive/src/parse/mod.rs @@ -0,0 +1,142 @@ +use crate::error::Error; +use crate::prelude::{Delimiter, Group, Ident, Punct, TokenTree}; +use std::iter::Peekable; + +mod attributes; +mod body; +mod data_type; +mod generics; +mod visibility; + +pub use self::attributes::Attributes; +pub use self::body::{EnumBody, EnumVariant, Fields, StructBody, UnnamedField}; +pub use self::data_type::DataType; +pub use self::generics::{Generic, GenericConstraints, Generics, Lifetime}; +pub use self::visibility::Visibility; + +pub(self) fn assume_group(t: Option) -> Group { + match t { + Some(TokenTree::Group(group)) => group, + _ => unreachable!(), + } +} +pub(self) fn assume_ident(t: Option) -> Ident { + match t { + Some(TokenTree::Ident(ident)) => ident, + _ => unreachable!(), + } +} +pub(self) fn assume_punct(t: Option, punct: char) -> Punct { + match t { + Some(TokenTree::Punct(p)) => { + debug_assert_eq!(punct, p.as_char()); + p + } + _ => unreachable!(), + } +} + +pub(self) fn consume_punct_if( + input: &mut Peekable>, + punct: char, +) -> Option { + if let Some(TokenTree::Punct(p)) = input.peek() { + if p.as_char() == punct { + match input.next() { + Some(TokenTree::Punct(p)) => return Some(p), + _ => unreachable!(), + } + } + } + None +} + +#[cfg(test)] +pub(self) fn ident_eq(ident: &Ident, text: &str) -> bool { + ident == text +} + +#[cfg(not(test))] +pub(self) fn ident_eq(ident: &Ident, text: &str) -> bool { + ident.to_string() == text +} + +fn check_if_arrow(tokens: &[TokenTree], punct: &Punct) -> bool { + if punct.as_char() == '>' { + if let Some(TokenTree::Punct(previous_punct)) = tokens.last() { + if previous_punct.as_char() == '-' { + return true; + } + } + } + false +} + +const OPEN_BRACKETS: &[char] = &['<', '(', '[', '{']; +const CLOSING_BRACKETS: &[char] = &['>', ')', ']', '}']; +const BRACKET_DELIMITER: &[Option] = &[ + None, + Some(Delimiter::Parenthesis), + Some(Delimiter::Bracket), + Some(Delimiter::Brace), +]; + +pub(self) fn read_tokens_until_punct( + input: &mut Peekable>, + expected_puncts: &[char], +) -> Result, Error> { + let mut result = Vec::new(); + let mut open_brackets = Vec::::new(); + 'outer: loop { + match input.peek() { + Some(TokenTree::Punct(punct)) => { + if check_if_arrow(&result, punct) { + // do nothing + } else if OPEN_BRACKETS.contains(&punct.as_char()) { + open_brackets.push(punct.as_char()); + } else if let Some(index) = + CLOSING_BRACKETS.iter().position(|c| c == &punct.as_char()) + { + let last_bracket = match open_brackets.pop() { + Some(bracket) => bracket, + None => { + if expected_puncts.contains(&punct.as_char()) { + break; + } + return Err(Error::InvalidRustSyntax(punct.span())); + } + }; + let expected = OPEN_BRACKETS[index]; + assert_eq!( + expected, + last_bracket, + "Unexpected closing bracket: found {}, expected {}", + punct.as_char(), + expected + ); + } else if expected_puncts.contains(&punct.as_char()) && open_brackets.is_empty() { + break; + } + result.push(input.next().unwrap()); + } + Some(TokenTree::Group(g)) if open_brackets.is_empty() => { + for punct in expected_puncts { + if let Some(idx) = OPEN_BRACKETS.iter().position(|c| c == punct) { + if let Some(delim) = BRACKET_DELIMITER[idx] { + if delim == g.delimiter() { + // we need to split on this delimiter + break 'outer; + } + } + } + } + result.push(input.next().unwrap()); + } + Some(_) => result.push(input.next().unwrap()), + None => { + break; + } + } + } + Ok(result) +} diff --git a/derive/src/parse/visibility.rs b/derive/src/parse/visibility.rs new file mode 100644 index 0000000..49a7ebf --- /dev/null +++ b/derive/src/parse/visibility.rs @@ -0,0 +1,68 @@ +use crate::prelude::TokenTree; +use crate::Result; +use std::iter::Peekable; + +#[derive(Debug, PartialEq, Clone)] +pub enum Visibility { + Default, + Pub, +} + +impl Visibility { + pub fn try_take(input: &mut Peekable>) -> Result { + if let Some(TokenTree::Ident(ident)) = input.peek() { + if super::ident_eq(ident, "pub") { + // Consume this token + super::assume_ident(input.next()); + + // check if the next token is `pub(...)` + if let Some(TokenTree::Group(_)) = input.peek() { + // we just consume the visibility, we're not actually using it for generation + super::assume_group(input.next()); + } + + return Ok(Visibility::Pub); + } + } + Ok(Visibility::Default) + } +} + +#[test] +fn test_visibility_try_take() { + use crate::token_stream; + + assert_eq!( + Visibility::Default, + Visibility::try_take(&mut token_stream("")).unwrap() + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream("pub")).unwrap() + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream(" pub ")).unwrap(), + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream("\tpub\t")).unwrap() + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream("pub(crate)")).unwrap() + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream(" pub ( crate ) ")).unwrap() + ); + assert_eq!( + Visibility::Pub, + Visibility::try_take(&mut token_stream("\tpub\t(\tcrate\t)\t")).unwrap() + ); + + assert_eq!( + Visibility::Default, + Visibility::try_take(&mut token_stream("pb")).unwrap() + ); +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 199889e..71ef281 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,45 +1,45 @@ -use crate::error::DecodeError; - -mod decoder; -mod impls; - -pub mod read; -pub use self::decoder::Decoder; - -pub trait Decodable: for<'de> BorrowDecodable<'de> { - fn decode(decoder: D) -> Result; -} - -pub trait BorrowDecodable<'de>: Sized { - fn borrow_decode>(decoder: D) -> Result; -} - -impl<'de, T: Decodable> BorrowDecodable<'de> for T { - fn borrow_decode(decoder: D) -> Result { - Decodable::decode(decoder) - } -} - -pub trait Decode { - fn decode_u8(&mut self) -> Result; - fn decode_u16(&mut self) -> Result; - fn decode_u32(&mut self) -> Result; - fn decode_u64(&mut self) -> Result; - fn decode_u128(&mut self) -> Result; - fn decode_usize(&mut self) -> Result; - - fn decode_i8(&mut self) -> Result; - fn decode_i16(&mut self) -> Result; - fn decode_i32(&mut self) -> Result; - fn decode_i64(&mut self) -> Result; - fn decode_i128(&mut self) -> Result; - fn decode_isize(&mut self) -> Result; - - fn decode_f32(&mut self) -> Result; - fn decode_f64(&mut self) -> Result; - fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; -} - -pub trait BorrowDecode<'de>: Decode { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; -} +use crate::error::DecodeError; + +mod decoder; +mod impls; + +pub mod read; +pub use self::decoder::Decoder; + +pub trait Decodable: for<'de> BorrowDecodable<'de> { + fn decode(decoder: D) -> Result; +} + +pub trait BorrowDecodable<'de>: Sized { + fn borrow_decode>(decoder: D) -> Result; +} + +impl<'de, T: Decodable> BorrowDecodable<'de> for T { + fn borrow_decode(decoder: D) -> Result { + Decodable::decode(decoder) + } +} + +pub trait Decode { + fn decode_u8(&mut self) -> Result; + fn decode_u16(&mut self) -> Result; + fn decode_u32(&mut self) -> Result; + fn decode_u64(&mut self) -> Result; + fn decode_u128(&mut self) -> Result; + fn decode_usize(&mut self) -> Result; + + fn decode_i8(&mut self) -> Result; + fn decode_i16(&mut self) -> Result; + fn decode_i32(&mut self) -> Result; + fn decode_i64(&mut self) -> Result; + fn decode_i128(&mut self) -> Result; + fn decode_isize(&mut self) -> Result; + + fn decode_f32(&mut self) -> Result; + fn decode_f64(&mut self) -> Result; + fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; +} + +pub trait BorrowDecode<'de>: Decode { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; +} diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 8b13789..b770a3c 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -1 +1,28 @@ +use crate::{config, enc, error, Config}; +use alloc::vec::Vec; +#[derive(Default)] +struct VecWriter { + inner: Vec, +} + +impl enc::write::Writer for VecWriter { + fn write(&mut self, bytes: &[u8]) -> Result<(), error::EncodeError> { + self.inner.extend_from_slice(bytes); + Ok(()) + } +} + +pub fn encode_to_vec(val: E) -> Result, error::EncodeError> { + encode_to_vec_with_config(val, config::Default) +} + +pub fn encode_to_vec_with_config( + val: E, + _config: C, +) -> Result, error::EncodeError> { + let writer = VecWriter::default(); + let mut encoder = enc::Encoder::<_, C>::new(writer); + val.encode(&mut encoder)?; + Ok(encoder.into_writer().inner) +} diff --git a/src/lib.rs b/src/lib.rs index 35f8441..71e4cb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,61 +1,61 @@ -#![no_std] - -//! Bincode is a crate for encoding and decoding using a tiny binary -//! serialization strategy. Using it, you can easily go from having -//! an object in memory, quickly serialize it to bytes, and then -//! deserialize it back just as fast! - -#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] -#![crate_name = "bincode"] -#![crate_type = "rlib"] -#![crate_type = "dylib"] - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(any(feature = "std", test))] -extern crate std; - -mod features; -pub(crate) mod varint; - -pub use features::*; - -pub mod config; -pub mod de; -pub mod enc; -pub mod error; - -use config::Config; - -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::<_, C>::new(writer); - val.encode(&mut encoder)?; - Ok(encoder.into_writer().bytes_written()) -} - -pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( - src: &'__de mut [u8], -) -> Result { - decode_with_config(src, config::Default) -} - -pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( - src: &'__de mut [u8], - _config: C, -) -> Result { - let reader = de::read::SliceReader::new(src); - let mut decoder = de::Decoder::<_, C>::new(reader, _config); - D::borrow_decode(&mut decoder) -} +#![no_std] + +//! Bincode is a crate for encoding and decoding using a tiny binary +//! serialization strategy. Using it, you can easily go from having +//! an object in memory, quickly serialize it to bytes, and then +//! deserialize it back just as fast! + +#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] +#![crate_name = "bincode"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] + +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(any(feature = "std", test))] +extern crate std; + +mod features; +pub(crate) mod varint; + +pub use features::*; + +pub mod config; +pub mod de; +pub mod enc; +pub mod error; + +use config::Config; + +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::<_, C>::new(writer); + val.encode(&mut encoder)?; + Ok(encoder.into_writer().bytes_written()) +} + +pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( + src: &'__de [u8], +) -> Result { + decode_with_config(src, config::Default) +} + +pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( + src: &'__de [u8], + _config: C, +) -> Result { + let reader = de::read::SliceReader::new(src); + let mut decoder = de::Decoder::<_, C>::new(reader, _config); + D::borrow_decode(&mut decoder) +} diff --git a/tests/derive.rs b/tests/derive.rs index b6aa2fe..3738cf0 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -3,7 +3,7 @@ use bincode::{de::Decodable, enc::Encodeable}; #[derive(bincode::Encodable, PartialEq, Debug)] -pub struct Test { +pub(crate) struct Test { a: T, b: u32, c: u8, diff --git a/tests/serde.rs b/tests/serde.rs new file mode 100644 index 0000000..7cb083b --- /dev/null +++ b/tests/serde.rs @@ -0,0 +1,28 @@ +#![cfg(all(feature = "serde", feature = "alloc", feature = "derive"))] + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, bincode::Encodable, bincode::Decodable)] +pub struct SerdeRoundtrip { + pub a: u32, + #[serde(skip)] + pub b: u32, +} + +#[test] +fn test_serde_round_trip() { + // validate serde attribute working + let json = serde_json::to_string(&SerdeRoundtrip { a: 5, b: 5 }).unwrap(); + assert_eq!("{\"a\":5}", json); + + let result: SerdeRoundtrip = serde_json::from_str(&json).unwrap(); + assert_eq!(result.a, 5); + assert_eq!(result.b, 0); + + // validate bincode working + let bytes = bincode::encode_to_vec(SerdeRoundtrip { a: 15, b: 15 }).unwrap(); + assert_eq!(bytes, &[15, 15]); + let result: SerdeRoundtrip = bincode::decode(&bytes).unwrap(); + assert_eq!(result.a, 15); + assert_eq!(result.b, 15); +} From c96962238442440c23749d3e7909506b22674762 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 12 Oct 2021 16:13:21 +0200 Subject: [PATCH 33/80] Added alloc and std tests --- Cargo.toml | 1 + src/error.rs | 6 +++++ src/features/impl_std.rs | 42 ++++++++++++++++++++++++++++++++- tests/alloc.rs | 36 ++++++++++++++++++++++++++++ tests/std.rs | 51 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/alloc.rs create mode 100644 tests/std.rs diff --git a/Cargo.toml b/Cargo.toml index c188eb1..2fc5727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,4 @@ serde = { version = "1.0.130", optional = true } [dev-dependencies] serde_derive = "1.0.130" serde_json = "1.0.68" +tempfile = "3.2.0" diff --git a/src/error.rs b/src/error.rs index 04db286..b21c6df 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,12 @@ pub enum EncodeError { InvalidIntEncoding, UnexpectedEnd, + + #[cfg(feature = "std")] + Io { + error: std::io::Error, + index: usize, + }, } #[non_exhaustive] diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 31d9758..0cdca00 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -1,7 +1,8 @@ use crate::{ config::{self, Config}, de::{read::Reader, Decodable, Decoder}, - error::DecodeError, + enc::{write::Writer, Encodeable, Encoder}, + error::{DecodeError, EncodeError}, }; pub fn decode_from(src: &mut R) -> Result { @@ -25,3 +26,42 @@ impl<'storage, R: std::io::Read> Reader<'storage> for R { } } } + +pub fn encode_into_write( + val: E, + dst: &mut W, +) -> Result { + encode_into_write_with_config(val, dst, config::Default) +} + +pub fn encode_into_write_with_config( + val: E, + dst: &mut W, + _config: C, +) -> Result { + let writer = IoWriter { + writer: dst, + bytes_written: 0, + }; + let mut encoder = Encoder::<_, C>::new(writer); + val.encode(&mut encoder)?; + Ok(encoder.into_writer().bytes_written) +} + +struct IoWriter<'a, W: std::io::Write> { + writer: &'a mut W, + bytes_written: usize, +} + +impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> { + fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { + self.writer + .write_all(bytes) + .map_err(|error| EncodeError::Io { + error, + index: self.bytes_written, + })?; + self.bytes_written += bytes.len(); + Ok(()) + } +} diff --git a/tests/alloc.rs b/tests/alloc.rs new file mode 100644 index 0000000..1dee965 --- /dev/null +++ b/tests/alloc.rs @@ -0,0 +1,36 @@ +#![cfg(feature = "alloc")] + +struct Foo { + pub a: u32, + pub b: u32, +} + +impl bincode::enc::Encodeable for Foo { + fn encode( + &self, + mut encoder: E, + ) -> Result<(), bincode::error::EncodeError> { + self.a.encode(&mut encoder)?; + self.b.encode(&mut encoder)?; + Ok(()) + } +} + +impl bincode::de::Decodable for Foo { + fn decode(mut decoder: D) -> Result { + Ok(Self { + a: bincode::de::Decodable::decode(&mut decoder)?, + b: bincode::de::Decodable::decode(&mut decoder)?, + }) + } +} + +#[test] +fn test_vec() { + let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }).unwrap(); + assert_eq!(vec, &[5, 10]); + + let foo: Foo = bincode::decode(&vec).unwrap(); + assert_eq!(foo.a, 5); + assert_eq!(foo.b, 10); +} diff --git a/tests/std.rs b/tests/std.rs new file mode 100644 index 0000000..da8b984 --- /dev/null +++ b/tests/std.rs @@ -0,0 +1,51 @@ +#![cfg(feature = "std")] + +struct Foo { + pub a: u32, + pub b: u32, +} + +impl bincode::enc::Encodeable for Foo { + fn encode( + &self, + mut encoder: E, + ) -> Result<(), bincode::error::EncodeError> { + self.a.encode(&mut encoder)?; + self.b.encode(&mut encoder)?; + Ok(()) + } +} + +impl bincode::de::Decodable for Foo { + fn decode(mut decoder: D) -> Result { + Ok(Self { + a: bincode::de::Decodable::decode(&mut decoder)?, + b: bincode::de::Decodable::decode(&mut decoder)?, + }) + } +} + +#[test] +fn test_std_cursor() { + let mut cursor = std::io::Cursor::<&[u8]>::new(&[5, 10]); + let foo: Foo = bincode::decode_from(&mut cursor).unwrap(); + + assert_eq!(foo.a, 5); + assert_eq!(foo.b, 10); +} + +#[test] +fn test_std_file() { + use std::io::{Seek, SeekFrom}; + + let mut file = tempfile::tempfile().expect("Could not create temp file"); + + let bytes_written = bincode::encode_into_write(Foo { a: 30, b: 50 }, &mut file).unwrap(); + assert_eq!(bytes_written, 2); + file.seek(SeekFrom::Start(0)).unwrap(); + + let foo: Foo = bincode::decode_from(&mut file).unwrap(); + + assert_eq!(foo.a, 30); + assert_eq!(foo.b, 50); +} From a8680ce1d8f601754eea211c56c37d021fb0a3b3 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 12 Oct 2021 18:18:43 +0200 Subject: [PATCH 34/80] Started working on documentation --- src/config.rs | 87 +++++++++++++++++++++++++++++ src/error.rs | 19 ++++++- src/lib.rs | 151 ++++++++++++++++++++++++++++++-------------------- 3 files changed, 195 insertions(+), 62 deletions(-) diff --git a/src/config.rs b/src/config.rs index ad549c3..6531ab6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,16 +1,99 @@ +//! The config module is used to change the behavior of bincode's encoding and decoding logic. +//! +//! *Important* make sure you use the same config for encoding and decoding, or else bincode will not work properly. +//! +//! To use a config, first create a type of [struct@Default]. This type will implement trait [Config] for further configuration. +//! +//! ``` +//! use bincode::config::{Config, Default}; +//! let config = Default +//! // pick one of: +//! .with_big_endian() +//! .with_little_endian() +//! // pick one of: +//! .with_variable_int_encoding() +//! .with_fixed_int_encoding(); +//! ``` +//! +//! See [Config] for more information on the configuration options. + pub(crate) use self::internal::*; use core::marker::PhantomData; +/// The config trait that is implemented by all types returned by this function, as well as [struct@Default]. +/// +/// The following methods are mutually exclusive and will overwrite each other. The last call to one of these methods determines the behavior of the configuration: +/// +/// - [with_little_endian] and [with_big_endian] +/// - [with_fixed_int_encoding] and [with_variable_int_encoding] +/// +/// +/// [with_little_endian]: #method.with_little_endian +/// [with_big_endian]: #method.with_big_endian +/// [with_fixed_int_encoding]: #method.with_fixed_int_encoding +/// [with_variable_int_encoding]: #method.with_variable_int_encoding pub trait Config: InternalConfig + Copy + Clone + Sized { + /// Makes bincode encode all integer types in big endian. fn with_big_endian(self) -> BigEndian { BigEndian { _pd: PhantomData } } + + /// Makes bincode encode all integer types in little endian. fn with_little_endian(self) -> LittleEndian { LittleEndian { _pd: PhantomData } } + + /// Makes bincode encode all integer types with a variable integer encoding. + /// + /// Encoding an unsigned integer v (of any type excepting u8) works as follows: + /// + /// 1. If `u < 251`, encode it as a single byte with that value. + /// 2. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`. + /// 3. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`. + /// 4. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`. + /// 5. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a + /// u128 with value `u`. + /// + /// Then, for signed integers, we first convert to unsigned using the zigzag algorithm, + /// and then encode them as we do for unsigned integers generally. The reason we use this + /// algorithm is that it encodes those values which are close to zero in less bytes; the + /// obvious algorithm, where we encode the cast values, gives a very large encoding for all + /// negative values. + /// + /// The zigzag algorithm is defined as follows: + /// + /// ```ignore + /// fn zigzag(v: Signed) -> Unsigned { + /// match v { + /// 0 => 0, + /// v if v < 0 => |v| * 2 - 1 + /// v if v > 0 => v * 2 + /// } + /// } + /// ``` + /// + /// And works such that: + /// + /// ```ignore + /// assert_eq!(zigzag(0), 0); + /// assert_eq!(zigzag(-1), 1); + /// assert_eq!(zigzag(1), 2); + /// assert_eq!(zigzag(-2), 3); + /// assert_eq!(zigzag(2), 4); + /// assert_eq!(zigzag(i64::min_value()), u64::max_value()); + /// ``` + /// + /// Note that u256 and the like are unsupported by this format; if and when they are added to the + /// language, they may be supported via the extension point given by the 255 byte. fn with_variable_int_encoding(self) -> Varint { Varint { _pd: PhantomData } } + + /// Fixed-size integer encoding. + /// + /// * Fixed size integers are encoded directly + /// * Enum discriminants are encoded as u32 + /// * Lengths and usize are encoded as u64 fn with_fixed_int_encoding(self) -> Fixint { Fixint { _pd: PhantomData } } @@ -28,6 +111,7 @@ impl InternalConfig for Default { const ALLOW_TRAILING: bool = true; } +#[doc(hidden)] #[derive(Copy, Clone)] pub struct BigEndian { _pd: PhantomData, @@ -40,6 +124,7 @@ impl InternalConfig for BigEndian { const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; } +#[doc(hidden)] #[derive(Copy, Clone)] pub struct LittleEndian { _pd: PhantomData, @@ -52,6 +137,7 @@ impl InternalConfig for LittleEndian { const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; } +#[doc(hidden)] #[derive(Copy, Clone)] pub struct Fixint { _pd: PhantomData, @@ -64,6 +150,7 @@ impl InternalConfig for Fixint { const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; } +#[doc(hidden)] #[derive(Copy, Clone)] pub struct Varint { _pd: PhantomData, diff --git a/src/error.rs b/src/error.rs index b21c6df..7ff8824 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,20 +1,29 @@ +//! Errors that can be encounting by Encoding and Decoding. + +/// Errors that can be encountered by encoding a type #[non_exhaustive] #[derive(Debug)] pub enum EncodeError { - InvalidIntEncoding, + /// The writer ran out of storage. UnexpectedEnd, + /// The targetted writer encountered an `std::io::Error` #[cfg(feature = "std")] Io { + /// The encountered error error: std::io::Error, + /// The amount of bytes that were written before the error occured index: usize, }, } +/// Errors that can be encounted by decoding a type #[non_exhaustive] #[derive(Debug)] pub enum DecodeError { + /// The reader reached its end but more bytes were expected. UnexpectedEnd, + /// Invalid type was found. The decoder tried to read type `expected`, but found type `found` instead. InvalidIntegerType { /// The type that was being read from the reader @@ -22,12 +31,20 @@ pub enum DecodeError { /// The type that was encoded in the data found: IntegerType, }, + + /// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`. UnexpectedVariant { + /// The min index of the enum. Usually this is `0`. min: u32, + + /// the max index of the enum. max: u32, + + // The index of the enum that the decoder encountered found: u32, }, + /// The decoder tried to decode a `str`, but an utf8 error was encountered. Utf8(core::str::Utf8Error), } diff --git a/src/lib.rs b/src/lib.rs index 71e4cb9..2701499 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,61 +1,90 @@ -#![no_std] - -//! Bincode is a crate for encoding and decoding using a tiny binary -//! serialization strategy. Using it, you can easily go from having -//! an object in memory, quickly serialize it to bytes, and then -//! deserialize it back just as fast! - -#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] -#![crate_name = "bincode"] -#![crate_type = "rlib"] -#![crate_type = "dylib"] - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(any(feature = "std", test))] -extern crate std; - -mod features; -pub(crate) mod varint; - -pub use features::*; - -pub mod config; -pub mod de; -pub mod enc; -pub mod error; - -use config::Config; - -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::<_, C>::new(writer); - val.encode(&mut encoder)?; - Ok(encoder.into_writer().bytes_written()) -} - -pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( - src: &'__de [u8], -) -> Result { - decode_with_config(src, config::Default) -} - -pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( - src: &'__de [u8], - _config: C, -) -> Result { - let reader = de::read::SliceReader::new(src); - let mut decoder = de::Decoder::<_, C>::new(reader, _config); - D::borrow_decode(&mut decoder) -} +#![no_std] + +//! Bincode is a crate for encoding and decoding using a tiny binary +//! serialization strategy. Using it, you can easily go from having +//! an object in memory, quickly serialize it to bytes, and then +//! deserialize it back just as fast! +//! +//! # Serde +//! +//! Starting from bincode 2, serde is now an optional dependency. If you want to use serde, please enable the `serde` feature. See [Features](#features) for more information. +//! +//! # Features +//! +//! |Name |Default?|Supported types for Encodeable/Decodeable|Enabled methods |Other| +//! |------|--------|-----------------------------------------|-----------------------------------------------------------------|-----| +//! |std | Yes ||`decode_from[_with_config]` and `encode_into_write[_with_config]`| +//! |alloc | Yes |`Vec`, `HashMap`, `BinaryHeap`, `BTreeMap`, `BTreeSet`, `LinkedList`, `VecDeque`, `Box`, `Arc`, `Rc`, `Cow`|`encode_to_vec[_with_config]`| +//! |derive| Yes |||Enables the `Encodeable` and `Decodeable` derive macro| +//! |serde | No ||`serde_decode_from[_with_config]`, `serde_encode_into[_with_config]`|Also enables `_to_vec` when `alloc` is enabled| + +#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] +#![crate_name = "bincode"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] + +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(any(feature = "std", test))] +extern crate std; + +mod features; +pub(crate) mod varint; + +pub use features::*; + +pub mod config; +pub mod de; +pub mod enc; +pub mod error; + +use config::Config; + +/// Encode the given value into the given slice. Returns the amount of bytes that have been written. +/// +/// Will take the [Default] configuration. See the [config] module for more information. +/// +/// [Default]: config/struct.Default.html +pub fn encode_into_slice( + val: E, + dst: &mut [u8], +) -> Result { + encode_into_slice_with_config(val, dst, config::Default) +} + +/// Encode the given value into the given slice. Returns the amount of bytes that have been written. +/// +/// See the [config] module for more information on configurations. +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::<_, C>::new(writer); + val.encode(&mut encoder)?; + Ok(encoder.into_writer().bytes_written()) +} + +/// Attempt to decode a given type `D` from the given slice. +/// +/// Will take the [Default] configuration. See the [config] module for more information. +/// +/// [Default]: config/struct.Default.html +pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( + src: &'__de [u8], +) -> Result { + decode_with_config(src, config::Default) +} + +/// Attempt to decode a given type `D` from the given slice. +/// +/// See the [config] module for more information on configurations. +pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( + src: &'__de [u8], + _config: C, +) -> Result { + let reader = de::read::SliceReader::new(src); + let mut decoder = de::Decoder::<_, C>::new(reader, _config); + D::borrow_decode(&mut decoder) +} From 84344af2c6fe43dde9480a285dec47689429a2bd Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 12 Oct 2021 18:23:39 +0200 Subject: [PATCH 35/80] Removed unneeded Config trait constraints --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 6531ab6..7c709be 100644 --- a/src/config.rs +++ b/src/config.rs @@ -32,7 +32,7 @@ use core::marker::PhantomData; /// [with_big_endian]: #method.with_big_endian /// [with_fixed_int_encoding]: #method.with_fixed_int_encoding /// [with_variable_int_encoding]: #method.with_variable_int_encoding -pub trait Config: InternalConfig + Copy + Clone + Sized { +pub trait Config: InternalConfig { /// Makes bincode encode all integer types in big endian. fn with_big_endian(self) -> BigEndian { BigEndian { _pd: PhantomData } From ea75220cd044626ddfc280ed91fb0799d7ea9ec1 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 17:30:52 +0200 Subject: [PATCH 36/80] Added documentation for the src/de module --- src/de/decoder.rs | 449 ++++++++++++++++++++++++---------------------- src/de/mod.rs | 120 ++++++++----- src/de/read.rs | 22 ++- 3 files changed, 330 insertions(+), 261 deletions(-) diff --git a/src/de/decoder.rs b/src/de/decoder.rs index ff10d37..4991963 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,215 +1,234 @@ -use super::{ - read::{BorrowReader, Reader}, - BorrowDecode, Decode, -}; -use crate::{ - config::{Config, Endian, IntEncoding}, - error::DecodeError, -}; -use core::marker::PhantomData; - -pub struct Decoder { - reader: R, - config: PhantomData, -} - -impl<'de, R: Reader<'de>, C: Config> Decoder { - pub fn new(reader: R, _config: C) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } - - pub fn into_reader(self) -> R { - self.reader - } -} - -impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - self.reader.take_bytes(len) - } -} - -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0]) - } - - fn decode_u16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u16::from_le_bytes(bytes), - Endian::Big => u16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u128::from_le_bytes(bytes), - Endian::Big => u128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_usize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - } as usize) - } - } - } - - fn decode_i8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0] as i8) - } - - fn decode_i16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i16::from_le_bytes(bytes), - Endian::Big => i16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i32::from_le_bytes(bytes), - Endian::Big => i32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i128::from_le_bytes(bytes), - Endian::Big => i128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_isize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - } as isize) - } - } - } - - fn decode_f32(&mut self) -> Result { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f32::from_le_bytes(bytes), - Endian::Big => f32::from_be_bytes(bytes), - }) - } - - fn decode_f64(&mut self) -> Result { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f64::from_le_bytes(bytes), - Endian::Big => f64::from_be_bytes(bytes), - }) - } - - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { - let mut array = [0u8; N]; - self.reader.read(&mut array)?; - Ok(array) - } -} +use super::{ + read::{BorrowReader, Reader}, + BorrowDecode, Decode, +}; +use crate::{ + config::{Config, Endian, IntEncoding}, + error::DecodeError, +}; +use core::marker::PhantomData; + +/// A Decoder that reads bytes from a given reader `R`. +/// +/// This struct should rarely be used. +/// In most cases, prefer any of the `decode` functions. +/// +/// The ByteOrder that is chosen will impact the endianness that +/// is used to read integers out of the reader. +/// +/// ``` +/// # let slice: &[u8] = &[0, 0, 0, 0]; +/// # let some_reader = bincode::de::read::SliceReader::new(slice); +/// use bincode::de::{Decoder, Decodable}; +/// use bincode::config; +/// let mut decoder = Decoder::new(some_reader, config::Default); +/// // this u32 can be any Decodable +/// let value = u32::decode(&mut decoder).unwrap(); +/// ``` +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + /// Construct a new Decoder + pub fn new(reader: R, _config: C) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } + + /// Consume the decoder and return the inner reader + pub fn into_reader(self) -> R { + self.reader + } +} + +impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + self.reader.take_bytes(len) + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0]) + } + + fn decode_u16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u16::from_le_bytes(bytes), + Endian::Big => u16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u128::from_le_bytes(bytes), + Endian::Big => u128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_usize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + } as usize) + } + } + } + + fn decode_i8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0] as i8) + } + + fn decode_i16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i16::from_le_bytes(bytes), + Endian::Big => i16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i32::from_le_bytes(bytes), + Endian::Big => i32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i128::from_le_bytes(bytes), + Endian::Big => i128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_isize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + } as isize) + } + } + } + + fn decode_f32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f32::from_le_bytes(bytes), + Endian::Big => f32::from_be_bytes(bytes), + }) + } + + fn decode_f64(&mut self) -> Result { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f64::from_le_bytes(bytes), + Endian::Big => f64::from_be_bytes(bytes), + }) + } + + fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { + let mut array = [0u8; N]; + self.reader.read(&mut array)?; + Ok(array) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 71ef281..eed91f3 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,45 +1,75 @@ -use crate::error::DecodeError; - -mod decoder; -mod impls; - -pub mod read; -pub use self::decoder::Decoder; - -pub trait Decodable: for<'de> BorrowDecodable<'de> { - fn decode(decoder: D) -> Result; -} - -pub trait BorrowDecodable<'de>: Sized { - fn borrow_decode>(decoder: D) -> Result; -} - -impl<'de, T: Decodable> BorrowDecodable<'de> for T { - fn borrow_decode(decoder: D) -> Result { - Decodable::decode(decoder) - } -} - -pub trait Decode { - fn decode_u8(&mut self) -> Result; - fn decode_u16(&mut self) -> Result; - fn decode_u32(&mut self) -> Result; - fn decode_u64(&mut self) -> Result; - fn decode_u128(&mut self) -> Result; - fn decode_usize(&mut self) -> Result; - - fn decode_i8(&mut self) -> Result; - fn decode_i16(&mut self) -> Result; - fn decode_i32(&mut self) -> Result; - fn decode_i64(&mut self) -> Result; - fn decode_i128(&mut self) -> Result; - fn decode_isize(&mut self) -> Result; - - fn decode_f32(&mut self) -> Result; - fn decode_f64(&mut self) -> Result; - fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; -} - -pub trait BorrowDecode<'de>: Decode { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; -} +use crate::error::DecodeError; + +mod decoder; +mod impls; + +pub mod read; +pub use self::decoder::Decoder; + +/// Trait that makes a type able to be decoded, akin to serde's `DeserializeOwned` trait. +/// +/// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [BorrowDecodable] instead. +/// +/// Whenever you implement `Decodable` for your type, the base trait `BorrowDecodable` is automatically implemented. +pub trait Decodable: for<'de> BorrowDecodable<'de> { + /// Attempt to decode this type with the given [Decode]. + fn decode(decoder: D) -> Result; +} + +/// Trait that makes a type able to be decoded, akin to serde's `Deserialize` trait. +/// +/// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [Decodable] instead. +pub trait BorrowDecodable<'de>: Sized { + /// Attempt to decode this type with the given [BorrowDecode]. + fn borrow_decode>(decoder: D) -> Result; +} + +impl<'de, T: Decodable> BorrowDecodable<'de> for T { + fn borrow_decode(decoder: D) -> Result { + Decodable::decode(decoder) + } +} + +/// Any source that can decode basic types. This type is most notably implemented for [Decoder]. +pub trait Decode { + /// Attempt to decode a `u8` + fn decode_u8(&mut self) -> Result; + /// Attempt to decode a `u16` + fn decode_u16(&mut self) -> Result; + /// Attempt to decode a `u32` + fn decode_u32(&mut self) -> Result; + /// Attempt to decode a `u64` + fn decode_u64(&mut self) -> Result; + /// Attempt to decode a `u128` + fn decode_u128(&mut self) -> Result; + /// Attempt to decode a `usize` + fn decode_usize(&mut self) -> Result; + + /// Attempt to decode a `i8` + fn decode_i8(&mut self) -> Result; + /// Attempt to decode a `i16` + fn decode_i16(&mut self) -> Result; + /// Attempt to decode a `i32` + fn decode_i32(&mut self) -> Result; + /// Attempt to decode a `i64` + fn decode_i64(&mut self) -> Result; + /// Attempt to decode a `i128` + fn decode_i128(&mut self) -> Result; + /// Attempt to decode a `isize` + fn decode_isize(&mut self) -> Result; + + /// Attempt to decode a `f32` + fn decode_f32(&mut self) -> Result; + /// Attempt to decode a `f64` + fn decode_f64(&mut self) -> Result; + /// Attempt to decode an array of `N` entries. + fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; +} + +/// Any source that can decode basic types. This type is most notably implemented for [Decoder]. +/// +/// This is an extension of [Decode] that can also return borrowed data. +pub trait BorrowDecode<'de>: Decode { + /// Decode `len` bytes, returning the slice as borrowed data. + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; +} diff --git a/src/de/read.rs b/src/de/read.rs index 2b568da..6a0030a 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -1,20 +1,40 @@ +//! This module contains reader-based structs and traits. +//! +//! Because `std::io::Read` is only limited to `std` and not `core`, we provide 2 alternative readers. +//! +//! [Reader] is a reader for sources that do not own their data. It is assumed that the reader's data is dropped after the `read` method is called. This reader is incapable of reading borrowed data, like `&str` and `&[u8]`. +//! +//! [BorrowReader] is an extension of `Reader` that also allows returning borrowed data. A `BorrowReader` allows reading `&str` and `&[u8]`. +//! +//! Specifically the `Reader` trait is used by [Decodable] and the `BorrowReader` trait is used by `[BorrowDecodable]`. +//! +//! [Decodable]: ../trait.Decodable.html +//! [BorrowDecodable]: ../trait.BorrowDecodable.html + use crate::error::DecodeError; +/// A reader for owned data. See the module documentation for more information. pub trait Reader<'storage> { + /// Fill the given `bytes` argument with values. Exactly the length of the given slice must be filled, or else an error must be returned. fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>; } +/// A reader for borrowed data. Implementors of this must also implement the [Reader] trait. See the module documentation for more information. pub trait BorrowReader<'storage>: Reader<'storage> { + /// Read exactly `length` bytes and return a slice to this data. If not enough bytes could be read, an error should be returned. + /// + /// *note*: Exactly `length` bytes must be returned. If less bytes are returned, bincode may panic. If more bytes are returned, the excess bytes may be discarded. fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError>; } +/// A reader type for `&[u8]` slices. Implements both [Reader] and [BorrowReader], and thus can be used for borrowed data. pub struct SliceReader<'storage> { slice: &'storage [u8], } impl<'storage> SliceReader<'storage> { /// Constructs a slice reader - pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { + pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { SliceReader { slice: bytes } } From bb98b8fcbdbe089cc4045f19487edc287594f3e1 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 17:59:23 +0200 Subject: [PATCH 37/80] Added documentation for the src/enc module --- src/enc/encoder.rs | 25 ++++++++++++++++++++++++- src/enc/mod.rs | 23 +++++++++++++++++++++++ src/enc/write.rs | 26 ++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 5a15e4b..a308d2d 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,3 +1,5 @@ +//! Contains + use super::{write::Writer, Encode}; use crate::{ config::{Config, Endian, IntEncoding}, @@ -5,19 +7,40 @@ use crate::{ }; use core::marker::PhantomData; +/// An Encoder that writes bytes into a given writer `W`. +/// +/// This struct should rarely be used. +/// In most cases, prefer any of the `encode` functions. +/// +/// The ByteOrder that is chosen will impact the endianness that +/// is used to write integers to the writer. +/// +/// ``` +/// # use bincode::enc::{write::SliceWriter, Encoder, Encodeable}; +/// # use bincode::config::{self, Config}; +/// # let config = config::Default.with_fixed_int_encoding().with_big_endian(); +/// let slice: &mut [u8] = &mut [0, 0, 0, 0]; +/// let mut encoder = Encoder::new(SliceWriter::new(slice), config); +/// // this u32 can be any Encodable +/// 5u32.encode(&mut encoder).unwrap(); +/// assert_eq!(encoder.into_writer().bytes_written(), 4); +/// assert_eq!(slice, [0, 0, 0, 5]); +/// ``` pub struct Encoder { writer: W, config: PhantomData, } impl Encoder { - pub fn new(writer: W) -> Encoder { + /// Create a new Encoder + pub fn new(writer: W, _config: C) -> Encoder { Encoder { writer, config: PhantomData, } } + /// Return the underlying writer pub fn into_writer(self) -> W { self.writer } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index ad997a3..d5e9db9 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -1,3 +1,5 @@ +//! Encoder-based structs and traits. + mod encoder; mod impls; @@ -7,27 +9,48 @@ pub mod write; pub use self::encoder::Encoder; +/// Any source that can encode types. This type is most notably implemented for [Encoder]. +/// +/// [Encoder]: ../struct.Encoder.html pub trait Encodeable { + /// Encode a given type. fn encode(&self, encoder: E) -> Result<(), EncodeError>; } +/// Helper trait to encode basic types into. pub trait Encode { + /// Encode an `u8` fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError>; + /// Encode an `u16` fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError>; + /// Encode an `u32` fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError>; + /// Encode an `u64` fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError>; + /// Encode an `u128` fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError>; + /// Encode an `usize` fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError>; + /// Encode an `i8` fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError>; + /// Encode an `i16` fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError>; + /// Encode an `i32` fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError>; + /// Encode an `i64` fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError>; + /// Encode an `i128` fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError>; + /// Encode an `isize` fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError>; + /// Encode an `f32` fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError>; + /// Encode an `f64` fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError>; + /// Encode a slice. Exactly `val.len()` bytes must be encoded, else an error should be thrown. fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError>; + /// Encode an array. Exactly `N` bytes must be encoded, else an error should be thrown. fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError>; } diff --git a/src/enc/write.rs b/src/enc/write.rs index 1b6e8f7..589f79d 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -1,23 +1,45 @@ +//! This module contains writer-based structs and traits. +//! +//! Because `std::io::Write` is only limited to `std` and not `core`, we provide our own [Writer]. + use crate::error::EncodeError; +/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encodeable] +/// +/// [Encodeable]: ../trait.Encodeable.html pub trait Writer { + /// Write `bytes` to the underlying writer. Exactly `bytes.len()` bytes must be written, or else an error should be returned. fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>; } +/// A helper struct that implements `Writer` for a `&[u8]` slice. +/// +/// ``` +/// use bincode::enc::write::{Writer, SliceWriter}; +/// +/// let destination = &mut [0u8; 100]; +/// let mut writer = SliceWriter::new(destination); +/// writer.write(&[1, 2, 3, 4, 5]).unwrap(); +/// +/// assert_eq!(writer.bytes_written(), 5); +/// assert_eq!(destination[0..6], [1, 2, 3, 4, 5, 0]); +/// ``` pub struct SliceWriter<'storage> { slice: &'storage mut [u8], idx: usize, } impl<'storage> SliceWriter<'storage> { - pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { + /// Create a new instance of `SliceWriter` with the given byte array. + pub fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { SliceWriter { slice: bytes, idx: 0, } } - pub(crate) fn bytes_written(&self) -> usize { + /// Return the amount of bytes written so far. + pub fn bytes_written(&self) -> usize { self.idx } } From 7b85fc168e4d7edd438fd5fb982f9acd75e31846 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 18:01:41 +0200 Subject: [PATCH 38/80] Added documentation for the src/featyres module --- src/features/impl_alloc.rs | 6 ++++-- src/features/impl_std.rs | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index b770a3c..c31bf18 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -13,16 +13,18 @@ impl enc::write::Writer for VecWriter { } } +/// Encode the given value into a `Vec`. pub fn encode_to_vec(val: E) -> Result, error::EncodeError> { encode_to_vec_with_config(val, config::Default) } +/// Encode the given value into a `Vec` with the given `Config`. See the [config] module for more information. pub fn encode_to_vec_with_config( val: E, - _config: C, + config: C, ) -> Result, error::EncodeError> { let writer = VecWriter::default(); - let mut encoder = enc::Encoder::<_, C>::new(writer); + let mut encoder = enc::Encoder::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().inner) } diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 0cdca00..9bfde7c 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -5,10 +5,14 @@ use crate::{ error::{DecodeError, EncodeError}, }; +/// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. pub fn decode_from(src: &mut R) -> Result { decode_from_with_config(src, config::Default) } +/// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. +/// +/// See the [config] module for more information about config options. pub fn decode_from_with_config( src: &mut R, _config: C, @@ -27,6 +31,7 @@ impl<'storage, R: std::io::Read> Reader<'storage> for R { } } +/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`. pub fn encode_into_write( val: E, dst: &mut W, @@ -34,16 +39,17 @@ pub fn encode_into_write( encode_into_write_with_config(val, dst, config::Default) } +/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. pub fn encode_into_write_with_config( val: E, dst: &mut W, - _config: C, + config: C, ) -> Result { let writer = IoWriter { writer: dst, bytes_written: 0, }; - let mut encoder = Encoder::<_, C>::new(writer); + let mut encoder = Encoder::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written) } From b480d2b3b355344f13440442f4cc0f378df455fa Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 18:04:13 +0200 Subject: [PATCH 39/80] Added documentation for the src/ module. Added warning for missing docs, fixed missing docs in src/de/mod.rs --- src/config.rs | 3 +++ src/de/mod.rs | 2 ++ src/error.rs | 4 +++- src/lib.rs | 5 +++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7c709be..8d2fc93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -101,6 +101,9 @@ pub trait Config: InternalConfig { impl Config for T {} +/// The default config. By default this will be: +/// - Little endian +/// - Variable int encoding #[derive(Copy, Clone)] pub struct Default; diff --git a/src/de/mod.rs b/src/de/mod.rs index eed91f3..b6ea6e5 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,3 +1,5 @@ +//! Decoder-based structs and traits. + use crate::error::DecodeError; mod decoder; diff --git a/src/error.rs b/src/error.rs index 7ff8824..4a7a6f2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -40,7 +40,7 @@ pub enum DecodeError { /// the max index of the enum. max: u32, - // The index of the enum that the decoder encountered + /// The index of the enum that the decoder encountered found: u32, }, @@ -48,8 +48,10 @@ pub enum DecodeError { Utf8(core::str::Utf8Error), } +/// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. #[non_exhaustive] #[derive(Debug)] +#[allow(missing_docs)] pub enum IntegerType { U16, U32, diff --git a/src/lib.rs b/src/lib.rs index 2701499..59e3dd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![warn(missing_docs)] //! Bincode is a crate for encoding and decoding using a tiny binary //! serialization strategy. Using it, you can easily go from having @@ -58,10 +59,10 @@ pub fn encode_into_slice( pub fn encode_into_slice_with_config( val: E, dst: &mut [u8], - _config: C, + config: C, ) -> Result { let writer = enc::write::SliceWriter::new(dst); - let mut encoder = enc::Encoder::<_, C>::new(writer); + let mut encoder = enc::Encoder::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written()) } From c4cb220fb2c4f96f7dbbb7d6f73b197526e37033 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 19:28:28 +0200 Subject: [PATCH 40/80] Added support for char encoding/decoding --- src/de/decoder.rs | 47 +++++++++++++++++++++++++++++++ src/de/impls.rs | 10 +++++++ src/de/mod.rs | 3 ++ src/enc/encoder.rs | 38 +++++++++++++++++++++++++ src/enc/impls.rs | 10 +++++++ src/enc/mod.rs | 3 ++ src/error.rs | 3 ++ tests/{test.rs => basic_types.rs} | 13 ++++++++- 8 files changed, 126 insertions(+), 1 deletion(-) rename tests/{test.rs => basic_types.rs} (86%) diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 4991963..cff80d1 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -231,4 +231,51 @@ impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { self.reader.read(&mut array)?; Ok(array) } + + fn decode_char(&mut self) -> Result { + let mut array = [0u8; 4]; + + // Look at the first byte to see how many bytes must be read + self.reader.read(&mut array[..1])?; + + let width = utf8_char_width(array[0]); + if width == 0 { + return Err(DecodeError::InvalidCharEncoding(array)); + } + if width == 1 { + return Ok(array[0] as char); + } + + // read the remaining pain + self.reader.read(&mut array[1..width])?; + let res = core::str::from_utf8(&array[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or(DecodeError::InvalidCharEncoding(array))?; + Ok(res) + } +} + +const UTF8_CHAR_WIDTH: [u8; 256] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x7F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0x9F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; + +// This function is a copy of core::str::utf8_char_width +const fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize } diff --git a/src/de/impls.rs b/src/de/impls.rs index 21164be..3fee1ac 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -85,6 +85,12 @@ impl<'de> Decodable for f64 { } } +impl<'de> Decodable for char { + fn decode(mut decoder: D) -> Result { + decoder.decode_char() + } +} + impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a [u8] { fn borrow_decode>(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; @@ -174,6 +180,10 @@ where fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { T::decode_array::(self) } + + fn decode_char(&mut self) -> Result { + T::decode_char(self) + } } impl<'a, 'de, T> BorrowDecode<'de> for &'a mut T diff --git a/src/de/mod.rs b/src/de/mod.rs index b6ea6e5..49407e4 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -66,6 +66,9 @@ pub trait Decode { fn decode_f64(&mut self) -> Result; /// Attempt to decode an array of `N` entries. fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; + + /// Attempt to decode a `char` + fn decode_char(&mut self) -> Result; } /// Any source that can decode basic types. This type is most notably implemented for [Decoder]. diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index a308d2d..09ac901 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -197,4 +197,42 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { self.writer.write(&val) } + + fn encode_char(&mut self, val: char) -> Result<(), EncodeError> { + encode_utf8(&mut self.writer, val) + } +} + +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +fn encode_utf8(writer: &mut impl Writer, c: char) -> Result<(), EncodeError> { + let code = c as u32; + + if code < MAX_ONE_B { + writer.write(&[c as u8]) + } else if code < MAX_TWO_B { + let mut buf = [0u8; 2]; + buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + buf[1] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) + } else if code < MAX_THREE_B { + let mut buf = [0u8; 3]; + buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[2] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) + } else { + let mut buf = [0u8; 4]; + buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; + buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) + } } diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 5d199e0..eed2f03 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -85,6 +85,12 @@ impl Encodeable for f64 { } } +impl Encodeable for char { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.encode_char(*self) + } +} + impl Encodeable for &'_ [u8] { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_slice(*self) @@ -157,4 +163,8 @@ where fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { T::encode_array(self, val) } + + fn encode_char(&mut self, val: char) -> Result<(), EncodeError> { + T::encode_char(self, val) + } } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index d5e9db9..f4d76a8 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -53,4 +53,7 @@ pub trait Encode { fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError>; /// Encode an array. Exactly `N` bytes must be encoded, else an error should be thrown. fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError>; + + /// Encode a single utf8 char + fn encode_char(&mut self, val: char) -> Result<(), EncodeError>; } diff --git a/src/error.rs b/src/error.rs index 4a7a6f2..e5279db 100644 --- a/src/error.rs +++ b/src/error.rs @@ -46,6 +46,9 @@ pub enum DecodeError { /// The decoder tried to decode a `str`, but an utf8 error was encountered. Utf8(core::str::Utf8Error), + + /// The decoder tried to decode a `char` and failed. The given buffer contains the bytes that are read at the moment of failure. + InvalidCharEncoding([u8; 4]), } /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. diff --git a/tests/test.rs b/tests/basic_types.rs similarity index 86% rename from tests/test.rs rename to tests/basic_types.rs index b0ca166..b8c5132 100644 --- a/tests/test.rs +++ b/tests/basic_types.rs @@ -12,7 +12,13 @@ where C: Config, { let mut buffer = [0u8; 32]; - bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + println!( + "{:?}: {:?} ({:?})", + element, + &buffer[..len], + core::any::type_name::() + ); let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); assert_eq!(element, decoded); @@ -68,6 +74,11 @@ fn test_numbers() { the_same(5.0f32); the_same(5.0f64); + + for char in "aÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö文".chars() + { + the_same(char); + } } #[test] From e4e12c984ba1b90a06906c78978c466d0e661447 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 19:34:35 +0200 Subject: [PATCH 41/80] Added support for the bool type --- src/de/impls.rs | 10 ++++++++++ src/enc/impls.rs | 6 ++++++ src/error.rs | 3 +++ tests/basic_types.rs | 3 +++ 4 files changed, 22 insertions(+) diff --git a/src/de/impls.rs b/src/de/impls.rs index 3fee1ac..7f683f0 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,6 +1,16 @@ use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; use crate::error::DecodeError; +impl<'de> Decodable for bool { + fn decode(mut decoder: D) -> Result { + match decoder.decode_u8()? { + 0 => Ok(false), + 1 => Ok(true), + x => Err(DecodeError::InvalidBooleanValue(x)), + } + } +} + impl<'de> Decodable for u8 { fn decode(mut decoder: D) -> Result { decoder.decode_u8() diff --git a/src/enc/impls.rs b/src/enc/impls.rs index eed2f03..5b57ea6 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,6 +1,12 @@ use super::{Encode, Encodeable}; use crate::error::EncodeError; +impl Encodeable for bool { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.encode_u8(if *self { 1 } else { 0 }) + } +} + impl Encodeable for u8 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u8(*self) diff --git a/src/error.rs b/src/error.rs index e5279db..86c36ee 100644 --- a/src/error.rs +++ b/src/error.rs @@ -49,6 +49,9 @@ pub enum DecodeError { /// The decoder tried to decode a `char` and failed. The given buffer contains the bytes that are read at the moment of failure. InvalidCharEncoding([u8; 4]), + + /// The decoder tried to decode a `bool` and failed. The given value is what is actually read. + InvalidBooleanValue(u8), } /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. diff --git a/tests/basic_types.rs b/tests/basic_types.rs index b8c5132..7b270a6 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -75,6 +75,9 @@ fn test_numbers() { the_same(5.0f32); the_same(5.0f64); + the_same(true); + the_same(false); + for char in "aÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö文".chars() { the_same(char); From 19fed15463a7c6f0cdfced41eeece8062352c6e4 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 20:33:03 +0200 Subject: [PATCH 42/80] Added support for tuples with up to 8 values --- src/de/impl_tuples.rs | 141 +++++++++++++++++++++++++++++++++++++++++ src/de/mod.rs | 1 + src/enc/impl_tuples.rs | 138 ++++++++++++++++++++++++++++++++++++++++ src/enc/mod.rs | 1 + tests/basic_types.rs | 13 ++++ 5 files changed, 294 insertions(+) create mode 100644 src/de/impl_tuples.rs create mode 100644 src/enc/impl_tuples.rs diff --git a/src/de/impl_tuples.rs b/src/de/impl_tuples.rs new file mode 100644 index 0000000..a384a2f --- /dev/null +++ b/src/de/impl_tuples.rs @@ -0,0 +1,141 @@ +use super::{Decodable, Decode}; +use crate::error::DecodeError; + +impl Decodable for (A,) +where + A: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok((A::decode(&mut decoder)?,)) + } +} + +impl Decodable for (A, B) +where + A: Decodable, + B: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok((A::decode(&mut decoder)?, B::decode(&mut decoder)?)) + } +} + +impl Decodable for (A, B, C) +where + A: Decodable, + B: Decodable, + C: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + )) + } +} + +impl Decodable for (A, B, C, D) +where + A: Decodable, + B: Decodable, + C: Decodable, + D: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + D::decode(&mut decoder)?, + )) + } +} + +impl Decodable for (A, B, C, D, E) +where + A: Decodable, + B: Decodable, + C: Decodable, + D: Decodable, + E: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + D::decode(&mut decoder)?, + E::decode(&mut decoder)?, + )) + } +} + +impl Decodable for (A, B, C, D, E, F) +where + A: Decodable, + B: Decodable, + C: Decodable, + D: Decodable, + E: Decodable, + F: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + D::decode(&mut decoder)?, + E::decode(&mut decoder)?, + F::decode(&mut decoder)?, + )) + } +} + +impl Decodable for (A, B, C, D, E, F, G) +where + A: Decodable, + B: Decodable, + C: Decodable, + D: Decodable, + E: Decodable, + F: Decodable, + G: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + D::decode(&mut decoder)?, + E::decode(&mut decoder)?, + F::decode(&mut decoder)?, + G::decode(&mut decoder)?, + )) + } +} + +impl Decodable for (A, B, C, D, E, F, G, H) +where + A: Decodable, + B: Decodable, + C: Decodable, + D: Decodable, + E: Decodable, + F: Decodable, + G: Decodable, + H: Decodable, +{ + fn decode<_D: Decode>(mut decoder: _D) -> Result { + Ok(( + A::decode(&mut decoder)?, + B::decode(&mut decoder)?, + C::decode(&mut decoder)?, + D::decode(&mut decoder)?, + E::decode(&mut decoder)?, + F::decode(&mut decoder)?, + G::decode(&mut decoder)?, + H::decode(&mut decoder)?, + )) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 49407e4..199f559 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -3,6 +3,7 @@ use crate::error::DecodeError; mod decoder; +mod impl_tuples; mod impls; pub mod read; diff --git a/src/enc/impl_tuples.rs b/src/enc/impl_tuples.rs new file mode 100644 index 0000000..b9cdb64 --- /dev/null +++ b/src/enc/impl_tuples.rs @@ -0,0 +1,138 @@ +use super::{Encode, Encodeable}; +use crate::error::EncodeError; + +impl Encodeable for (A,) +where + A: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B) +where + A: Encodeable, + B: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C, D) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, + D: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + self.3.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C, D, E) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, + D: Encodeable, + E: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + self.3.encode(&mut encoder)?; + self.4.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C, D, E, F) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, + D: Encodeable, + E: Encodeable, + F: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + self.3.encode(&mut encoder)?; + self.4.encode(&mut encoder)?; + self.5.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C, D, E, F, G) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, + D: Encodeable, + E: Encodeable, + F: Encodeable, + G: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + self.3.encode(&mut encoder)?; + self.4.encode(&mut encoder)?; + self.5.encode(&mut encoder)?; + self.6.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for (A, B, C, D, E, F, G, H) +where + A: Encodeable, + B: Encodeable, + C: Encodeable, + D: Encodeable, + E: Encodeable, + F: Encodeable, + G: Encodeable, + H: Encodeable, +{ + fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + self.0.encode(&mut encoder)?; + self.1.encode(&mut encoder)?; + self.2.encode(&mut encoder)?; + self.3.encode(&mut encoder)?; + self.4.encode(&mut encoder)?; + self.5.encode(&mut encoder)?; + self.6.encode(&mut encoder)?; + self.7.encode(&mut encoder)?; + Ok(()) + } +} diff --git a/src/enc/mod.rs b/src/enc/mod.rs index f4d76a8..be3dd27 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -1,6 +1,7 @@ //! Encoder-based structs and traits. mod encoder; +mod impl_tuples; mod impls; use crate::error::EncodeError; diff --git a/tests/basic_types.rs b/tests/basic_types.rs index 7b270a6..d7a48a4 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -58,6 +58,7 @@ where #[test] fn test_numbers() { + // integer types the_same(5u8); the_same(5u16); the_same(5u32); @@ -75,13 +76,25 @@ fn test_numbers() { the_same(5.0f32); the_same(5.0f64); + // bool the_same(true); the_same(false); + // utf8 characters for char in "aÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö文".chars() { the_same(char); } + + // tuples, up to 8 + the_same((1u8,)); + the_same((1u8, 2u8)); + the_same((1u8, 2u8, 3u8)); + the_same((1u8, 2u8, 3u8, 4u8)); + the_same((1u8, 2u8, 3u8, 4u8, 5u8)); + the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8)); + the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8)); + the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8)); } #[test] From 960b6066cdc5a8c0516e75390d86512f6786db14 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 14 Oct 2021 21:31:47 +0200 Subject: [PATCH 43/80] Added an option to encode a fixed array length or to skip it --- src/config.rs | 54 +++- src/de/decoder.rs | 571 ++++++++++++++++++++++--------------------- src/enc/encoder.rs | 3 + src/error.rs | 8 + tests/basic_types.rs | 66 ++++- 5 files changed, 415 insertions(+), 287 deletions(-) diff --git a/src/config.rs b/src/config.rs index 8d2fc93..f575ee7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,10 @@ //! .with_little_endian() //! // pick one of: //! .with_variable_int_encoding() -//! .with_fixed_int_encoding(); +//! .with_fixed_int_encoding() +//! // pick one of: +//! .skip_fixed_array_length() +//! .write_fixed_array_length(); //! ``` //! //! See [Config] for more information on the configuration options. @@ -26,12 +29,15 @@ use core::marker::PhantomData; /// /// - [with_little_endian] and [with_big_endian] /// - [with_fixed_int_encoding] and [with_variable_int_encoding] +/// - [skip_fixed_array_length] and [write_fixed_array_length] /// /// /// [with_little_endian]: #method.with_little_endian /// [with_big_endian]: #method.with_big_endian /// [with_fixed_int_encoding]: #method.with_fixed_int_encoding /// [with_variable_int_encoding]: #method.with_variable_int_encoding +/// [skip_fixed_array_length]: #method.skip_fixed_array_length +/// [write_fixed_array_length]: #method.write_fixed_array_length pub trait Config: InternalConfig { /// Makes bincode encode all integer types in big endian. fn with_big_endian(self) -> BigEndian { @@ -97,6 +103,16 @@ pub trait Config: InternalConfig { fn with_fixed_int_encoding(self) -> Fixint { Fixint { _pd: PhantomData } } + + /// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array + fn skip_fixed_array_length(self) -> SkipFixedArrayLength { + SkipFixedArrayLength { _pd: PhantomData } + } + + /// Write the length of fixed size arrays (`[u8; N]`) before writing the array + fn write_fixed_array_length(self) -> WriteFixedArrayLength { + WriteFixedArrayLength { _pd: PhantomData } + } } impl Config for T {} @@ -104,6 +120,7 @@ impl Config for T {} /// The default config. By default this will be: /// - Little endian /// - Variable int encoding +/// - Skip fixed array length #[derive(Copy, Clone)] pub struct Default; @@ -112,6 +129,7 @@ impl InternalConfig for Default { const INT_ENCODING: IntEncoding = IntEncoding::Variable; const LIMIT: Option = None; const ALLOW_TRAILING: bool = true; + const SKIP_FIXED_ARRAY_LENGTH: bool = true; } #[doc(hidden)] @@ -125,6 +143,7 @@ impl InternalConfig for BigEndian { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -138,6 +157,7 @@ impl InternalConfig for LittleEndian { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -151,6 +171,7 @@ impl InternalConfig for Fixint { const INT_ENCODING: IntEncoding = IntEncoding::Fixed; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -164,6 +185,35 @@ impl InternalConfig for Varint { const INT_ENCODING: IntEncoding = IntEncoding::Variable; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +pub struct SkipFixedArrayLength { + _pd: PhantomData, +} + +impl InternalConfig for SkipFixedArrayLength { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = true; +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +pub struct WriteFixedArrayLength { + _pd: PhantomData, +} + +impl InternalConfig for WriteFixedArrayLength { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = false; } mod internal { @@ -172,6 +222,7 @@ mod internal { const INT_ENCODING: IntEncoding; const LIMIT: Option; const ALLOW_TRAILING: bool; + const SKIP_FIXED_ARRAY_LENGTH: bool; } #[derive(PartialEq, Eq)] @@ -194,5 +245,6 @@ mod internal { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } } diff --git a/src/de/decoder.rs b/src/de/decoder.rs index cff80d1..8b29cfb 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,281 +1,290 @@ -use super::{ - read::{BorrowReader, Reader}, - BorrowDecode, Decode, -}; -use crate::{ - config::{Config, Endian, IntEncoding}, - error::DecodeError, -}; -use core::marker::PhantomData; - -/// A Decoder that reads bytes from a given reader `R`. -/// -/// This struct should rarely be used. -/// In most cases, prefer any of the `decode` functions. -/// -/// The ByteOrder that is chosen will impact the endianness that -/// is used to read integers out of the reader. -/// -/// ``` -/// # let slice: &[u8] = &[0, 0, 0, 0]; -/// # let some_reader = bincode::de::read::SliceReader::new(slice); -/// use bincode::de::{Decoder, Decodable}; -/// use bincode::config; -/// let mut decoder = Decoder::new(some_reader, config::Default); -/// // this u32 can be any Decodable -/// let value = u32::decode(&mut decoder).unwrap(); -/// ``` -pub struct Decoder { - reader: R, - config: PhantomData, -} - -impl<'de, R: Reader<'de>, C: Config> Decoder { - /// Construct a new Decoder - pub fn new(reader: R, _config: C) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } - - /// Consume the decoder and return the inner reader - pub fn into_reader(self) -> R { - self.reader - } -} - -impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - self.reader.take_bytes(len) - } -} - -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0]) - } - - fn decode_u16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u16::from_le_bytes(bytes), - Endian::Big => u16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u128::from_le_bytes(bytes), - Endian::Big => u128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_usize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - } as usize) - } - } - } - - fn decode_i8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0] as i8) - } - - fn decode_i16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i16::from_le_bytes(bytes), - Endian::Big => i16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i32::from_le_bytes(bytes), - Endian::Big => i32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i128::from_le_bytes(bytes), - Endian::Big => i128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_isize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - } as isize) - } - } - } - - fn decode_f32(&mut self) -> Result { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f32::from_le_bytes(bytes), - Endian::Big => f32::from_be_bytes(bytes), - }) - } - - fn decode_f64(&mut self) -> Result { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f64::from_le_bytes(bytes), - Endian::Big => f64::from_be_bytes(bytes), - }) - } - - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { - let mut array = [0u8; N]; - self.reader.read(&mut array)?; - Ok(array) - } - - fn decode_char(&mut self) -> Result { - let mut array = [0u8; 4]; - - // Look at the first byte to see how many bytes must be read - self.reader.read(&mut array[..1])?; - - let width = utf8_char_width(array[0]); - if width == 0 { - return Err(DecodeError::InvalidCharEncoding(array)); - } - if width == 1 { - return Ok(array[0] as char); - } - - // read the remaining pain - self.reader.read(&mut array[1..width])?; - let res = core::str::from_utf8(&array[..width]) - .ok() - .and_then(|s| s.chars().next()) - .ok_or(DecodeError::InvalidCharEncoding(array))?; - Ok(res) - } -} - -const UTF8_CHAR_WIDTH: [u8; 256] = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x7F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0x9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -// This function is a copy of core::str::utf8_char_width -const fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} +use super::{ + read::{BorrowReader, Reader}, + BorrowDecode, Decode, +}; +use crate::{ + config::{Config, Endian, IntEncoding}, + error::DecodeError, +}; +use core::marker::PhantomData; + +/// A Decoder that reads bytes from a given reader `R`. +/// +/// This struct should rarely be used. +/// In most cases, prefer any of the `decode` functions. +/// +/// The ByteOrder that is chosen will impact the endianness that +/// is used to read integers out of the reader. +/// +/// ``` +/// # let slice: &[u8] = &[0, 0, 0, 0]; +/// # let some_reader = bincode::de::read::SliceReader::new(slice); +/// use bincode::de::{Decoder, Decodable}; +/// use bincode::config; +/// let mut decoder = Decoder::new(some_reader, config::Default); +/// // this u32 can be any Decodable +/// let value = u32::decode(&mut decoder).unwrap(); +/// ``` +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + /// Construct a new Decoder + pub fn new(reader: R, _config: C) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } + + /// Consume the decoder and return the inner reader + pub fn into_reader(self) -> R { + self.reader + } +} + +impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + self.reader.take_bytes(len) + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0]) + } + + fn decode_u16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u16::from_le_bytes(bytes), + Endian::Big => u16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u128::from_le_bytes(bytes), + Endian::Big => u128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_usize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + } as usize) + } + } + } + + fn decode_i8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0] as i8) + } + + fn decode_i16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i16::from_le_bytes(bytes), + Endian::Big => i16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i32::from_le_bytes(bytes), + Endian::Big => i32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i128::from_le_bytes(bytes), + Endian::Big => i128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_isize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + } as isize) + } + } + } + + fn decode_f32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f32::from_le_bytes(bytes), + Endian::Big => f32::from_be_bytes(bytes), + }) + } + + fn decode_f64(&mut self) -> Result { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f64::from_le_bytes(bytes), + Endian::Big => f64::from_be_bytes(bytes), + }) + } + + fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { + let mut array = [0u8; N]; + if !C::SKIP_FIXED_ARRAY_LENGTH { + let length = self.decode_usize()?; + if length != N { + return Err(DecodeError::ArrayLengthMismatch { + found: length, + required: N, + }); + } + } + self.reader.read(&mut array)?; + Ok(array) + } + + fn decode_char(&mut self) -> Result { + let mut array = [0u8; 4]; + + // Look at the first byte to see how many bytes must be read + self.reader.read(&mut array[..1])?; + + let width = utf8_char_width(array[0]); + if width == 0 { + return Err(DecodeError::InvalidCharEncoding(array)); + } + if width == 1 { + return Ok(array[0] as char); + } + + // read the remaining pain + self.reader.read(&mut array[1..width])?; + let res = core::str::from_utf8(&array[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or(DecodeError::InvalidCharEncoding(array))?; + Ok(res) + } +} + +const UTF8_CHAR_WIDTH: [u8; 256] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x7F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0x9F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; + +// This function is a copy of core::str::utf8_char_width +const fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 09ac901..a942b2d 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -195,6 +195,9 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { + if !C::SKIP_FIXED_ARRAY_LENGTH { + self.encode_usize(N)?; + } self.writer.write(&val) } diff --git a/src/error.rs b/src/error.rs index 86c36ee..eb0c66c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,6 +52,14 @@ pub enum DecodeError { /// The decoder tried to decode a `bool` and failed. The given value is what is actually read. InvalidBooleanValue(u8), + + /// The decoder tried to decode an array of length `required`, but the binary data contained an array of length `found`. + ArrayLengthMismatch { + /// The length of the array required by the rust type. + required: usize, + /// The length of the array found in the binary format. + found: usize, + }, } /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. diff --git a/tests/basic_types.rs b/tests/basic_types.rs index d7a48a4..d5cc68d 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -11,7 +11,7 @@ where + 'static, C: Config, { - let mut buffer = [0u8; 32]; + let mut buffer = [0u8; 1024]; let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", @@ -32,27 +32,62 @@ where + Clone + 'static, { + // A matrix of each different config option possible the_same_with_config( element.clone(), config::Default .with_little_endian() - .with_fixed_int_encoding(), + .with_fixed_int_encoding() + .skip_fixed_array_length(), ); the_same_with_config( element.clone(), - config::Default.with_big_endian().with_fixed_int_encoding(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .skip_fixed_array_length(), ); the_same_with_config( element.clone(), config::Default .with_little_endian() - .with_variable_int_encoding(), + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_variable_int_encoding() + .write_fixed_array_length(), ); the_same_with_config( element, config::Default .with_big_endian() - .with_variable_int_encoding(), + .with_variable_int_encoding() + .write_fixed_array_length(), ); } @@ -95,6 +130,27 @@ fn test_numbers() { the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8)); the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8)); the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8)); + + // arrays + #[rustfmt::skip] + the_same([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + ]); } #[test] From 82924aa96ed4f0a1d9040daaf167bfb9d484949b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 11:03:25 +0200 Subject: [PATCH 44/80] Added support for Option and Result --- derive/src/derive_enum.rs | 12 ++++---- derive/src/generate/generator.rs | 4 +++ src/de/impls.rs | 48 ++++++++++++++++++++++++++++++++ src/enc/impls.rs | 33 ++++++++++++++++++++++ src/error.rs | 3 ++ tests/basic_types.rs | 7 +++++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 6e06319..394ae2f 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -80,6 +80,7 @@ impl DeriveEnum { pub fn generate_decodable(self, generator: &mut Generator) -> Result<()> { let DeriveEnum { variants } = self; + let enum_name = generator.target_name().to_string(); if generator.has_lifetimes() { // enum has a lifetime, implement BorrowDecodable @@ -125,14 +126,14 @@ impl DeriveEnum { // invalid idx variant_case.push_parsed(format!( - "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant }})", - variants.len() - 1 + "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})", + variants.len() - 1, + enum_name.to_string() )); }); }); } else { // enum has no lifetimes, implement Decodable - generator.impl_for("bincode::de::Decodable") .generate_fn("decode") .with_generic("D", ["bincode::de::Decode"]) @@ -175,8 +176,9 @@ impl DeriveEnum { // invalid idx variant_case.push_parsed(format!( - "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant }})", - variants.len() - 1 + "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})", + variants.len() - 1, + enum_name.to_string() )); }); }); diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs index 94edf7d..cf56fa6 100644 --- a/derive/src/generate/generator.rs +++ b/derive/src/generate/generator.rs @@ -24,6 +24,10 @@ impl Generator { } } + pub fn target_name(&self) -> &Ident { + &self.name + } + pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { ImplFor::new(self, trait_name) } diff --git a/src/de/impls.rs b/src/de/impls.rs index 7f683f0..b5b0933 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -127,6 +127,54 @@ impl<'de, T> Decodable for core::marker::PhantomData { } } +impl<'de, T> Decodable for Option +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let is_some = u8::decode(&mut decoder)?; + match is_some { + 0 => Ok(None), + 1 => { + let val = T::decode(decoder)?; + Ok(Some(val)) + } + x => Err(DecodeError::UnexpectedVariant { + found: x as u32, + max: 1, + min: 0, + type_name: core::any::type_name::>(), + }), + } + } +} + +impl<'de, T, U> Decodable for Result +where + T: Decodable, + U: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let is_ok = u8::decode(&mut decoder)?; + match is_ok { + 0 => { + let t = T::decode(decoder)?; + Ok(Ok(t)) + } + 1 => { + let u = U::decode(decoder)?; + Ok(Err(u)) + } + x => Err(DecodeError::UnexpectedVariant { + found: x as u32, + max: 1, + min: 0, + type_name: core::any::type_name::>(), + }), + } + } +} + impl<'a, 'de, T> Decode for &'a mut T where T: Decode, diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 5b57ea6..6f7c431 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -115,6 +115,39 @@ impl Encodeable for [u8; N] { } } +impl Encodeable for Option +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + if let Some(val) = self { + 1u8.encode(&mut encoder)?; + val.encode(encoder) + } else { + 0u8.encode(encoder) + } + } +} + +impl Encodeable for Result +where + T: Encodeable, + U: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match self { + Ok(val) => { + 0u8.encode(&mut encoder)?; + val.encode(encoder) + } + Err(err) => { + 1u8.encode(&mut encoder)?; + err.encode(encoder) + } + } + } +} + impl<'a, T> Encode for &'a mut T where T: Encode, diff --git a/src/error.rs b/src/error.rs index eb0c66c..e687cac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -34,6 +34,9 @@ pub enum DecodeError { /// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`. UnexpectedVariant { + /// The type name that was being decoded. + type_name: &'static str, + /// The min index of the enum. Usually this is `0`. min: u32, diff --git a/tests/basic_types.rs b/tests/basic_types.rs index d5cc68d..afe338d 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -151,6 +151,13 @@ fn test_numbers() { 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 ]); + + // Option and Result + the_same(Option::::None); + the_same(Option::::Some(1234)); + + the_same(Result::::Ok(1555)); + the_same(Result::::Err(15)); } #[test] From db963bd7052ae1dd23e5ca69c8036ed76857f551 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 11:04:06 +0200 Subject: [PATCH 45/80] Fixed newline issues in project --- .rustfmt.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..43d4840 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +newline_style = "Unix" From 07f49e878e5e74e4f66dbb4036b933851a8793a8 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 11:41:59 +0200 Subject: [PATCH 46/80] Added support for Vec, Box and Box<[T]> --- src/enc/impls.rs | 21 +++++++++ src/features/impl_alloc.rs | 85 ++++++++++++++++++++++++++++++++-- tests/alloc.rs | 11 +++++ tests/basic_types.rs | 93 +------------------------------------- tests/utils.rs | 93 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 207 insertions(+), 96 deletions(-) create mode 100644 tests/utils.rs diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 6f7c431..7a05569 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -103,6 +103,27 @@ impl Encodeable for &'_ [u8] { } } +// BlockedTODO: https://github.com/rust-lang/rust/issues/37653 +// +// We'll want to implement encoding for both &[u8] and &[T: Encodeable], +// but those implementations overlap because u8 also implements Encodeabl +// +// default impl Encodeable for &'_ [u8] { +// fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +// encoder.encode_slice(*self) +// } +// } +// +// impl Encodeable for &'_ [T] { +// fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +// self.len().encode(&mut encoder)?; +// for item in self.iter() { +// item.encode(&mut encoder)?; +// } +// Ok(()) +// } +// } + impl Encodeable for &'_ str { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_slice(self.as_bytes()) diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index c31bf18..bbe3d1f 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -1,5 +1,11 @@ -use crate::{config, enc, error, Config}; -use alloc::vec::Vec; +use crate::{ + config, + de::{Decodable, Decode}, + enc::{self, Encode, Encodeable}, + error::{DecodeError, EncodeError}, + Config, +}; +use alloc::{boxed::Box, vec::Vec}; #[derive(Default)] struct VecWriter { @@ -7,14 +13,14 @@ struct VecWriter { } impl enc::write::Writer for VecWriter { - fn write(&mut self, bytes: &[u8]) -> Result<(), error::EncodeError> { + fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { self.inner.extend_from_slice(bytes); Ok(()) } } /// Encode the given value into a `Vec`. -pub fn encode_to_vec(val: E) -> Result, error::EncodeError> { +pub fn encode_to_vec(val: E) -> Result, EncodeError> { encode_to_vec_with_config(val, config::Default) } @@ -22,9 +28,78 @@ pub fn encode_to_vec(val: E) -> Result, error::Encod pub fn encode_to_vec_with_config( val: E, config: C, -) -> Result, error::EncodeError> { +) -> Result, EncodeError> { let writer = VecWriter::default(); let mut encoder = enc::Encoder::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().inner) } + +impl<'de, T> Decodable for Vec +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + let mut vec = Vec::with_capacity(len); + for _ in 0..len { + vec.push(T::decode(&mut decoder)?); + } + Ok(vec) + } +} + +impl Encodeable for Vec +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for item in self.iter() { + item.encode(&mut encoder)?; + } + Ok(()) + } +} + +impl<'de, T> Decodable for Box +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Box::new(t)) + } +} + +impl Encodeable for Box +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(self, encoder) + } +} + +impl<'de, T> Decodable for Box<[T]> +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let vec = Vec::decode(decoder)?; + Ok(vec.into_boxed_slice()) + } +} + +impl Encodeable for Box<[T]> +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for item in self.iter() { + item.encode(&mut encoder)?; + } + Ok(()) + } +} diff --git a/tests/alloc.rs b/tests/alloc.rs index 1dee965..e051d77 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -1,5 +1,9 @@ #![cfg(feature = "alloc")] +mod utils; + +use utils::the_same; + struct Foo { pub a: u32, pub b: u32, @@ -34,3 +38,10 @@ fn test_vec() { assert_eq!(foo.a, 5); assert_eq!(foo.b, 10); } + +#[test] +fn test_alloc_commons() { + the_same::>(vec![1, 2, 3, 4, 5]); + the_same(Box::::new(5)); + the_same(Box::<[u32]>::from(vec![1, 2, 3, 4, 5])); +} diff --git a/tests/basic_types.rs b/tests/basic_types.rs index afe338d..8e7781f 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,95 +1,6 @@ -use bincode::config::{self, Config}; -use core::fmt::Debug; +mod utils; -fn the_same_with_config(element: V, config: C) -where - V: bincode::enc::Encodeable - + for<'de> bincode::de::Decodable - + PartialEq - + Debug - + Clone - + 'static, - C: Config, -{ - let mut buffer = [0u8; 1024]; - let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); - println!( - "{:?}: {:?} ({:?})", - element, - &buffer[..len], - core::any::type_name::() - ); - 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 - + for<'de> bincode::de::Decodable - + PartialEq - + Debug - + Clone - + 'static, -{ - // A matrix of each different config option possible - the_same_with_config( - element.clone(), - config::Default - .with_little_endian() - .with_fixed_int_encoding() - .skip_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_big_endian() - .with_fixed_int_encoding() - .skip_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_little_endian() - .with_variable_int_encoding() - .skip_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_big_endian() - .with_variable_int_encoding() - .skip_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_little_endian() - .with_fixed_int_encoding() - .write_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_big_endian() - .with_fixed_int_encoding() - .write_fixed_array_length(), - ); - the_same_with_config( - element.clone(), - config::Default - .with_little_endian() - .with_variable_int_encoding() - .write_fixed_array_length(), - ); - the_same_with_config( - element, - config::Default - .with_big_endian() - .with_variable_int_encoding() - .write_fixed_array_length(), - ); -} +use utils::the_same; #[test] fn test_numbers() { diff --git a/tests/utils.rs b/tests/utils.rs new file mode 100644 index 0000000..69955b6 --- /dev/null +++ b/tests/utils.rs @@ -0,0 +1,93 @@ +use bincode::config::{self, Config}; +use core::fmt::Debug; + +fn the_same_with_config(element: V, config: C) +where + V: bincode::enc::Encodeable + + for<'de> bincode::de::Decodable + + PartialEq + + Debug + + Clone + + 'static, + C: Config, +{ + let mut buffer = [0u8; 1024]; + let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + println!( + "{:?}: {:?} ({:?})", + element, + &buffer[..len], + core::any::type_name::() + ); + let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); + + assert_eq!(element, decoded); +} + +pub fn the_same(element: V) +where + V: bincode::enc::Encodeable + + for<'de> bincode::de::Decodable + + PartialEq + + Debug + + Clone + + 'static, +{ + // A matrix of each different config option possible + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_fixed_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_variable_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element, + config::Default + .with_big_endian() + .with_variable_int_encoding() + .write_fixed_array_length(), + ); +} From 1d6379e7158961a65592508086dee1a0e192b009 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 12:04:23 +0200 Subject: [PATCH 47/80] Added support for Cell and RefCell --- src/de/impls.rs | 22 ++++++++++++++++++++++ src/enc/impls.rs | 35 +++++++++++++++++++++++++++++++++++ src/error.rs | 8 ++++++++ tests/basic_types.rs | 23 ++++++++++++++++++++++- 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index b5b0933..fc6170d 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,3 +1,5 @@ +use core::cell::{Cell, RefCell}; + use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; use crate::error::DecodeError; @@ -175,6 +177,26 @@ where } } +impl<'de, T> Decodable for Cell +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Cell::new(t)) + } +} + +impl<'de, T> Decodable for RefCell +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(RefCell::new(t)) + } +} + impl<'a, 'de, T> Decode for &'a mut T where T: Decode, diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 7a05569..912f101 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,3 +1,5 @@ +use core::cell::{Cell, RefCell}; + use super::{Encode, Encodeable}; use crate::error::EncodeError; @@ -169,6 +171,39 @@ where } } +impl Encodeable for Cell +where + T: Encodeable + Copy, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(&self.get(), encoder) + } +} + +impl Encodeable for RefCell +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + let borrow_guard = self + .try_borrow() + .map_err(|e| EncodeError::RefCellAlreadyBorrowed { + inner: e, + type_name: core::any::type_name::>(), + })?; + T::encode(&borrow_guard, encoder) + } +} + +impl<'a, T> Encodeable for &'a T +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(self, encoder) + } +} + impl<'a, T> Encode for &'a mut T where T: Encode, diff --git a/src/error.rs b/src/error.rs index e687cac..e3e7969 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,14 @@ pub enum EncodeError { /// The writer ran out of storage. UnexpectedEnd, + /// The RefCell is already borrowed + RefCellAlreadyBorrowed { + /// The inner borrow error + inner: core::cell::BorrowError, + /// the type name of the RefCell being encoded that is currently borrowed. + type_name: &'static str, + }, + /// The targetted writer encountered an `std::io::Error` #[cfg(feature = "std")] Io { diff --git a/tests/basic_types.rs b/tests/basic_types.rs index 8e7781f..87adb15 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,5 +1,7 @@ mod utils; +use core::cell::Cell; +use std::cell::RefCell; use utils::the_same; #[test] @@ -63,12 +65,31 @@ fn test_numbers() { 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 ]); - // Option and Result + // Common types the_same(Option::::None); the_same(Option::::Some(1234)); the_same(Result::::Ok(1555)); the_same(Result::::Err(15)); + + the_same(Cell::::new(15)); + the_same(RefCell::::new(15)); +} + +#[test] +fn test_refcell_already_borrowed() { + let cell = RefCell::new(5u32); + // first get a mutable reference to the cell + let _mutable_guard = cell.borrow_mut(); + // now try to encode it + let mut slice = [0u8; 10]; + let result = bincode::encode_into_slice(&cell, &mut slice) + .expect_err("Encoding a borrowed refcell should fail"); + + match result { + bincode::error::EncodeError::RefCellAlreadyBorrowed { .. } => {} // ok + x => panic!("Expected a RefCellAlreadyBorrowed error, found {:?}", x), + } } #[test] From 4e1a72796c8390d76f42d3b4002ead1141317f7b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 12:08:29 +0200 Subject: [PATCH 48/80] Added support for Cow, Rc and Arc --- src/features/impl_alloc.rs | 65 +++++++++++++++++++++++++++++++++++--- tests/alloc.rs | 9 ++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index bbe3d1f..53fa85b 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -5,7 +5,7 @@ use crate::{ error::{DecodeError, EncodeError}, Config, }; -use alloc::{boxed::Box, vec::Vec}; +use alloc::{borrow::Cow, boxed::Box, rc::Rc, sync::Arc, vec::Vec}; #[derive(Default)] struct VecWriter { @@ -35,7 +35,7 @@ pub fn encode_to_vec_with_config( Ok(encoder.into_writer().inner) } -impl<'de, T> Decodable for Vec +impl Decodable for Vec where T: Decodable, { @@ -62,7 +62,7 @@ where } } -impl<'de, T> Decodable for Box +impl Decodable for Box where T: Decodable, { @@ -81,7 +81,7 @@ where } } -impl<'de, T> Decodable for Box<[T]> +impl Decodable for Box<[T]> where T: Decodable, { @@ -103,3 +103,60 @@ where Ok(()) } } + +impl<'cow, T> Decodable for Cow<'cow, T> +where + T: Decodable + Clone, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Cow::Owned(t)) + } +} + +impl<'cow, T> Encodeable for Cow<'cow, T> +where + T: Encodeable + Clone, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.as_ref().encode(encoder) + } +} + +impl Decodable for Rc +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Rc::new(t)) + } +} + +impl Encodeable for Rc +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(self, encoder) + } +} + +impl Decodable for Arc +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Arc::new(t)) + } +} + +impl Encodeable for Arc +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(self, encoder) + } +} diff --git a/tests/alloc.rs b/tests/alloc.rs index e051d77..2118b65 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -1,7 +1,12 @@ #![cfg(feature = "alloc")] +extern crate alloc; + mod utils; +use alloc::borrow::Cow; +use alloc::rc::Rc; +use alloc::sync::Arc; use utils::the_same; struct Foo { @@ -44,4 +49,8 @@ fn test_alloc_commons() { the_same::>(vec![1, 2, 3, 4, 5]); the_same(Box::::new(5)); the_same(Box::<[u32]>::from(vec![1, 2, 3, 4, 5])); + the_same(Cow::::Owned(5)); + the_same(Cow::::Borrowed(&5)); + the_same(Rc::::new(5)); + the_same(Arc::::new(5)); } From a322e0f1b3d2484b4728f6495d9dc09edd789b08 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 12:21:52 +0200 Subject: [PATCH 49/80] Added support for BinaryHeap, BTreeMap, BTreeSet and VecDeque --- src/features/impl_alloc.rs | 118 ++++++++++++++++++++++++++++++++++++- tests/alloc.rs | 17 ++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 53fa85b..30e707a 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -5,7 +5,7 @@ use crate::{ error::{DecodeError, EncodeError}, Config, }; -use alloc::{borrow::Cow, boxed::Box, rc::Rc, sync::Arc, vec::Vec}; +use alloc::{borrow::Cow, boxed::Box, collections::*, rc::Rc, sync::Arc, vec::Vec}; #[derive(Default)] struct VecWriter { @@ -35,6 +35,122 @@ pub fn encode_to_vec_with_config( Ok(encoder.into_writer().inner) } +impl Decodable for BinaryHeap +where + T: Decodable + Ord, +{ + fn decode(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + let mut map = BinaryHeap::with_capacity(len); + for _ in 0..len { + let key = T::decode(&mut decoder)?; + map.push(key); + } + Ok(map) + } +} + +impl Encodeable for BinaryHeap +where + T: Encodeable + Ord, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for val in self.iter() { + val.encode(&mut encoder)?; + } + Ok(()) + } +} + +impl Decodable for BTreeMap +where + K: Decodable + Ord, + V: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + let mut map = BTreeMap::new(); + for _ in 0..len { + let key = K::decode(&mut decoder)?; + let value = V::decode(&mut decoder)?; + map.insert(key, value); + } + Ok(map) + } +} + +impl Encodeable for BTreeMap +where + K: Encodeable + Ord, + V: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for (key, val) in self.iter() { + key.encode(&mut encoder)?; + val.encode(&mut encoder)?; + } + Ok(()) + } +} + +impl Decodable for BTreeSet +where + T: Decodable + Ord, +{ + fn decode(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + let mut map = BTreeSet::new(); + for _ in 0..len { + let key = T::decode(&mut decoder)?; + map.insert(key); + } + Ok(map) + } +} + +impl Encodeable for BTreeSet +where + T: Encodeable + Ord, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for item in self.iter() { + item.encode(&mut encoder)?; + } + Ok(()) + } +} + +impl Decodable for VecDeque +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let len = usize::decode(&mut decoder)?; + let mut map = VecDeque::with_capacity(len); + for _ in 0..len { + let key = T::decode(&mut decoder)?; + map.push_back(key); + } + Ok(map) + } +} + +impl Encodeable for VecDeque +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + for item in self.iter() { + item.encode(&mut encoder)?; + } + Ok(()) + } +} + impl Decodable for Vec where T: Decodable, diff --git a/tests/alloc.rs b/tests/alloc.rs index 2118b65..f096b5f 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -5,6 +5,7 @@ extern crate alloc; mod utils; use alloc::borrow::Cow; +use alloc::collections::*; use alloc::rc::Rc; use alloc::sync::Arc; use utils::the_same; @@ -53,4 +54,20 @@ fn test_alloc_commons() { the_same(Cow::::Borrowed(&5)); the_same(Rc::::new(5)); the_same(Arc::::new(5)); + the_same({ + let mut map = BTreeMap::::new(); + map.insert(5, -5); + map + }); + the_same({ + let mut set = BTreeSet::::new(); + set.insert(5); + set + }); + the_same({ + let mut set = VecDeque::::new(); + set.push_back(15); + set.push_front(5); + set + }); } From 33dd4f761de4bc92615aaef7ed70ce020e022f3d Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 12:59:38 +0200 Subject: [PATCH 50/80] Added support for CStr and CString --- src/error.rs | 7 +++++++ src/features/impl_std.rs | 38 ++++++++++++++++++++++++++++++++++++-- tests/std.rs | 18 ++++++++++++++++++ tests/utils.rs | 14 ++------------ 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/error.rs b/src/error.rs index e3e7969..5884c1b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -71,6 +71,13 @@ pub enum DecodeError { /// The length of the array found in the binary format. found: usize, }, + + /// The decoder tried to decode a `CStr` or `CString`, but the incoming data contained a 0 byte + #[cfg(feature = "std")] + CStrNulError { + /// The inner exception + inner: std::ffi::FromBytesWithNulError, + }, } /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 9bfde7c..4099208 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -1,9 +1,10 @@ use crate::{ config::{self, Config}, - de::{read::Reader, Decodable, Decoder}, - enc::{write::Writer, Encodeable, Encoder}, + de::{read::Reader, BorrowDecodable, BorrowDecode, Decodable, Decode, Decoder}, + enc::{write::Writer, Encode, Encodeable, Encoder}, error::{DecodeError, EncodeError}, }; +use std::ffi::{CStr, CString}; /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. pub fn decode_from(src: &mut R) -> Result { @@ -71,3 +72,36 @@ impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> { Ok(()) } } + +impl<'a> Encodeable for &'a CStr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.to_bytes_with_nul().encode(encoder) + } +} + +impl<'de> BorrowDecodable<'de> for &'de CStr { + fn borrow_decode>(decoder: D) -> Result { + let bytes = <&[u8]>::borrow_decode(decoder)?; + CStr::from_bytes_with_nul(bytes).map_err(|e| DecodeError::CStrNulError { inner: e }) + } +} + +impl Encodeable for CString { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.as_bytes_with_nul().encode(encoder) + } +} + +impl Decodable for CString { + fn decode(decoder: D) -> Result { + // BlockedTODO: https://github.com/rust-lang/rust/issues/73179 + // use `from_vec_with_nul` instead, combined with: + // let bytes = std::vec::Vec::::decode(decoder)?; + + // now we have to allocate twice unfortunately + let vec: std::vec::Vec = std::vec::Vec::decode(decoder)?; + let cstr = + CStr::from_bytes_with_nul(&vec).map_err(|e| DecodeError::CStrNulError { inner: e })?; + Ok(cstr.into()) + } +} diff --git a/tests/std.rs b/tests/std.rs index da8b984..d9365a2 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -1,5 +1,9 @@ #![cfg(feature = "std")] +mod utils; + +use utils::the_same; + struct Foo { pub a: u32, pub b: u32, @@ -49,3 +53,17 @@ fn test_std_file() { assert_eq!(foo.a, 30); assert_eq!(foo.b, 50); } + +#[test] +fn test_std_commons() { + use std::ffi::{CStr, CString}; + the_same(CString::new("Hello world").unwrap()); + + let config = bincode::config::Default; + let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); + let mut buffer = [0u8; 1024]; + let len = bincode::encode_into_slice_with_config(cstr, &mut buffer, config).unwrap(); + let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + + assert_eq!(cstr, decoded); +} diff --git a/tests/utils.rs b/tests/utils.rs index 69955b6..2823a6a 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -3,12 +3,7 @@ use core::fmt::Debug; fn the_same_with_config(element: V, config: C) where - V: bincode::enc::Encodeable - + for<'de> bincode::de::Decodable - + PartialEq - + Debug - + Clone - + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, C: Config, { let mut buffer = [0u8; 1024]; @@ -26,12 +21,7 @@ where pub fn the_same(element: V) where - V: bincode::enc::Encodeable - + for<'de> bincode::de::Decodable - + PartialEq - + Debug - + Clone - + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, { // A matrix of each different config option possible the_same_with_config( From 9cf577d9bcebc36e64660580c4b13a986f21b279 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 13:19:30 +0200 Subject: [PATCH 51/80] Added support for String, Mutex and RwLock --- src/error.rs | 7 ++++++ src/features/impl_alloc.rs | 15 +++++++++++- src/features/impl_std.rs | 49 +++++++++++++++++++++++++++++++++++++- tests/alloc.rs | 1 + tests/std.rs | 16 +++++++++++-- 5 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index 5884c1b..e466120 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,6 +23,13 @@ pub enum EncodeError { /// The amount of bytes that were written before the error occured index: usize, }, + + /// The encoder tried to encode a `Mutex` or `RwLock`, but the locking failed + #[cfg(feature = "std")] + LockFailed { + /// The type name of the mutex for debugging purposes + type_name: &'static str, + }, } /// Errors that can be encounted by decoding a type diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 30e707a..4132a2f 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -5,7 +5,7 @@ use crate::{ error::{DecodeError, EncodeError}, Config, }; -use alloc::{borrow::Cow, boxed::Box, collections::*, rc::Rc, sync::Arc, vec::Vec}; +use alloc::{borrow::Cow, boxed::Box, collections::*, rc::Rc, string::String, sync::Arc, vec::Vec}; #[derive(Default)] struct VecWriter { @@ -178,6 +178,19 @@ where } } +impl Decodable for String { + fn decode(decoder: D) -> Result { + let bytes = Vec::::decode(decoder)?; + String::from_utf8(bytes).map_err(|e| DecodeError::Utf8(e.utf8_error())) + } +} + +impl Encodeable for String { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.as_bytes().encode(encoder) + } +} + impl Decodable for Box where T: Decodable, diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 4099208..cd9bff4 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -4,7 +4,10 @@ use crate::{ enc::{write::Writer, Encode, Encodeable, Encoder}, error::{DecodeError, EncodeError}, }; -use std::ffi::{CStr, CString}; +use std::{ + ffi::{CStr, CString}, + sync::{Mutex, RwLock}, +}; /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. pub fn decode_from(src: &mut R) -> Result { @@ -105,3 +108,47 @@ impl Decodable for CString { Ok(cstr.into()) } } + +impl Encodeable for Mutex +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + let t = self.lock().map_err(|_| EncodeError::LockFailed { + type_name: core::any::type_name::>(), + })?; + t.encode(encoder) + } +} + +impl Decodable for Mutex +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(Mutex::new(t)) + } +} + +impl Encodeable for RwLock +where + T: Encodeable, +{ + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + let t = self.read().map_err(|_| EncodeError::LockFailed { + type_name: core::any::type_name::>(), + })?; + t.encode(encoder) + } +} + +impl Decodable for RwLock +where + T: Decodable, +{ + fn decode(decoder: D) -> Result { + let t = T::decode(decoder)?; + Ok(RwLock::new(t)) + } +} diff --git a/tests/alloc.rs b/tests/alloc.rs index f096b5f..211284a 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -48,6 +48,7 @@ fn test_vec() { #[test] fn test_alloc_commons() { the_same::>(vec![1, 2, 3, 4, 5]); + the_same(String::from("Hello world")); the_same(Box::::new(5)); the_same(Box::<[u32]>::from(vec![1, 2, 3, 4, 5])); the_same(Cow::::Owned(5)); diff --git a/tests/std.rs b/tests/std.rs index d9365a2..7646a4a 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -2,6 +2,8 @@ mod utils; +use std::sync::{Mutex, RwLock}; + use utils::the_same; struct Foo { @@ -60,10 +62,20 @@ fn test_std_commons() { the_same(CString::new("Hello world").unwrap()); let config = bincode::config::Default; - let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); let mut buffer = [0u8; 1024]; + + let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); let len = bincode::encode_into_slice_with_config(cstr, &mut buffer, config).unwrap(); let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); - assert_eq!(cstr, decoded); + + let mutex = Mutex::new("Hello world".to_string()); + let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); + let decoded: Mutex = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + assert_eq!(&*mutex.lock().unwrap(), &*decoded.lock().unwrap()); + + let rwlock = RwLock::new("Hello world".to_string()); + let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); + let decoded: RwLock = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + assert_eq!(&*rwlock.read().unwrap(), &*decoded.read().unwrap()); } From acbd3856490d243e66ef30f2d125848742abbc62 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 13:32:12 +0200 Subject: [PATCH 52/80] Added core::time::Duration and std::time::SystemTime --- src/de/impls.rs | 17 ++++++++++++++--- src/enc/impls.rs | 13 ++++++++++++- src/error.rs | 9 +++++++++ src/features/impl_std.rs | 21 +++++++++++++++++++++ tests/basic_types.rs | 6 ++++-- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index fc6170d..4d715f3 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,4 +1,7 @@ -use core::cell::{Cell, RefCell}; +use core::{ + cell::{Cell, RefCell}, + time::Duration, +}; use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; use crate::error::DecodeError; @@ -177,7 +180,7 @@ where } } -impl<'de, T> Decodable for Cell +impl Decodable for Cell where T: Decodable, { @@ -187,7 +190,7 @@ where } } -impl<'de, T> Decodable for RefCell +impl Decodable for RefCell where T: Decodable, { @@ -197,6 +200,14 @@ where } } +impl Decodable for Duration { + fn decode(mut decoder: D) -> Result { + let secs = Decodable::decode(&mut decoder)?; + let nanos = Decodable::decode(&mut decoder)?; + Ok(Duration::new(secs, nanos)) + } +} + impl<'a, 'de, T> Decode for &'a mut T where T: Decode, diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 912f101..3f1c63f 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,4 +1,7 @@ -use core::cell::{Cell, RefCell}; +use core::{ + cell::{Cell, RefCell}, + time::Duration, +}; use super::{Encode, Encodeable}; use crate::error::EncodeError; @@ -195,6 +198,14 @@ where } } +impl Encodeable for Duration { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.as_secs().encode(&mut encoder)?; + self.subsec_nanos().encode(&mut encoder)?; + Ok(()) + } +} + impl<'a, T> Encodeable for &'a T where T: Encodeable, diff --git a/src/error.rs b/src/error.rs index e466120..143d1f5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,6 +30,15 @@ pub enum EncodeError { /// The type name of the mutex for debugging purposes type_name: &'static str, }, + + /// The encoder tried to encode a `SystemTime`, but it was before `SystemTime::UNIX_EPOCH` + #[cfg(feature = "std")] + InvalidSystemTime { + /// The error that was thrown by the SystemTime + inner: std::time::SystemTimeError, + /// The SystemTime that caused the error + time: std::time::SystemTime, + }, } /// Errors that can be encounted by decoding a type diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index cd9bff4..e3f2a17 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -4,9 +4,11 @@ use crate::{ enc::{write::Writer, Encode, Encodeable, Encoder}, error::{DecodeError, EncodeError}, }; +use core::time::Duration; use std::{ ffi::{CStr, CString}, sync::{Mutex, RwLock}, + time::SystemTime, }; /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. @@ -152,3 +154,22 @@ where Ok(RwLock::new(t)) } } + +impl Encodeable for SystemTime { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + let duration = self.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| { + EncodeError::InvalidSystemTime { + inner: e, + time: *self, + } + })?; + duration.encode(encoder) + } +} + +impl Decodable for SystemTime { + fn decode(decoder: D) -> Result { + let duration = Duration::decode(decoder)?; + Ok(SystemTime::UNIX_EPOCH + duration) + } +} diff --git a/tests/basic_types.rs b/tests/basic_types.rs index 87adb15..c3cb4e1 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,7 +1,7 @@ mod utils; -use core::cell::Cell; -use std::cell::RefCell; +use core::cell::{Cell, RefCell}; +use core::time::Duration; use utils::the_same; #[test] @@ -74,6 +74,8 @@ fn test_numbers() { the_same(Cell::::new(15)); the_same(RefCell::::new(15)); + + the_same(Duration::new(5, 730023852)); } #[test] From 26d76837195225c395e457588c9461bb2129536d Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 13:47:48 +0200 Subject: [PATCH 53/80] Added support for Path and PathBuf --- src/error.rs | 3 +++ src/features/impl_std.rs | 30 ++++++++++++++++++++++++++++++ tests/std.rs | 13 ++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 143d1f5..77528df 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,9 @@ pub enum EncodeError { type_name: &'static str, }, + /// An uncommon error occured, see the inner text for more information + Other(&'static str), + /// The targetted writer encountered an `std::io::Error` #[cfg(feature = "std")] Io { diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index e3f2a17..4b1d8b7 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -7,6 +7,7 @@ use crate::{ use core::time::Duration; use std::{ ffi::{CStr, CString}, + path::{Path, PathBuf}, sync::{Mutex, RwLock}, time::SystemTime, }; @@ -173,3 +174,32 @@ impl Decodable for SystemTime { Ok(SystemTime::UNIX_EPOCH + duration) } } + +impl Encodeable for &'_ Path { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + match self.to_str() { + Some(str) => str.encode(encoder), + None => Err(EncodeError::Other("Path contains invalid UTF-8 characters")), + } + } +} + +impl<'de> BorrowDecodable<'de> for &'de Path { + fn borrow_decode>(decoder: D) -> Result { + let str = <&'de str>::borrow_decode(decoder)?; + Ok(Path::new(str)) + } +} + +impl Encodeable for PathBuf { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.as_path().encode(encoder) + } +} + +impl Decodable for PathBuf { + fn decode(decoder: D) -> Result { + let string = std::string::String::decode(decoder)?; + Ok(string.into()) + } +} diff --git a/tests/std.rs b/tests/std.rs index 7646a4a..fafde3a 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -59,23 +59,34 @@ fn test_std_file() { #[test] fn test_std_commons() { use std::ffi::{CStr, CString}; + use std::path::{Path, PathBuf}; the_same(CString::new("Hello world").unwrap()); + the_same(PathBuf::from("C:/Program Files/Foo")); let config = bincode::config::Default; let mut buffer = [0u8; 1024]; + // &CStr let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); let len = bincode::encode_into_slice_with_config(cstr, &mut buffer, config).unwrap(); let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); assert_eq!(cstr, decoded); + // Mutex let mutex = Mutex::new("Hello world".to_string()); let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); let decoded: Mutex = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); assert_eq!(&*mutex.lock().unwrap(), &*decoded.lock().unwrap()); + // RwLock let rwlock = RwLock::new("Hello world".to_string()); - let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); + let len = bincode::encode_into_slice_with_config(&rwlock, &mut buffer, config).unwrap(); let decoded: RwLock = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); assert_eq!(&*rwlock.read().unwrap(), &*decoded.read().unwrap()); + + // Path + let path = Path::new("C:/Program Files/Foo"); + let len = bincode::encode_into_slice_with_config(path, &mut buffer, config).unwrap(); + let decoded: &Path = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + assert_eq!(path, decoded); } From 9420d03762989c43bbb1d0b770fdca5fc197b8a4 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 13:59:48 +0200 Subject: [PATCH 54/80] Added support for Range, RangeInclusive and Bound --- src/de/impls.rs | 42 ++++++++++++++++++++++++++++++++++ src/enc/impls.rs | 54 ++++++++++++++++++++++++++++++++++++++++---- tests/basic_types.rs | 6 +++++ 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index 4d715f3..f7584c0 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,5 +1,6 @@ use core::{ cell::{Cell, RefCell}, + ops::{Bound, Range, RangeInclusive}, time::Duration, }; @@ -208,6 +209,47 @@ impl Decodable for Duration { } } +impl Decodable for Range +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let min = T::decode(&mut decoder)?; + let max = T::decode(&mut decoder)?; + Ok(min..max) + } +} + +impl Decodable for RangeInclusive +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + let min = T::decode(&mut decoder)?; + let max = T::decode(&mut decoder)?; + Ok(RangeInclusive::new(min, max)) + } +} + +impl Decodable for Bound +where + T: Decodable, +{ + fn decode(mut decoder: D) -> Result { + match u32::decode(&mut decoder)? { + 0 => Ok(Bound::Unbounded), + 1 => Ok(Bound::Included(T::decode(decoder)?)), + 2 => Ok(Bound::Excluded(T::decode(decoder)?)), + x => Err(DecodeError::UnexpectedVariant { + min: 0, + max: 2, + found: x, + type_name: core::any::type_name::>(), + }), + } + } +} + impl<'a, 'de, T> Decode for &'a mut T where T: Decode, diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 3f1c63f..a452eb9 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,10 +1,10 @@ -use core::{ - cell::{Cell, RefCell}, - time::Duration, -}; - use super::{Encode, Encodeable}; use crate::error::EncodeError; +use core::{ + cell::{Cell, RefCell}, + ops::{Bound, Range, RangeInclusive}, + time::Duration, +}; impl Encodeable for bool { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { @@ -206,6 +206,50 @@ impl Encodeable for Duration { } } +impl Encodeable for Range +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.start.encode(&mut encoder)?; + self.end.encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for RangeInclusive +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.start().encode(&mut encoder)?; + self.end().encode(&mut encoder)?; + Ok(()) + } +} + +impl Encodeable for Bound +where + T: Encodeable, +{ + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match self { + Self::Unbounded => { + 0u32.encode(encoder)?; + } + Self::Included(val) => { + 1u32.encode(&mut encoder)?; + val.encode(encoder)?; + } + Self::Excluded(val) => { + 2u32.encode(&mut encoder)?; + val.encode(encoder)?; + } + } + Ok(()) + } +} + impl<'a, T> Encodeable for &'a T where T: Encodeable, diff --git a/tests/basic_types.rs b/tests/basic_types.rs index c3cb4e1..a3c8d21 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,6 +1,7 @@ mod utils; use core::cell::{Cell, RefCell}; +use core::ops::Bound; use core::time::Duration; use utils::the_same; @@ -76,6 +77,11 @@ fn test_numbers() { the_same(RefCell::::new(15)); the_same(Duration::new(5, 730023852)); + the_same(5u8..10u8); + the_same(5u8..=10u8); + the_same(Bound::::Unbounded); + the_same(Bound::::Included(105)); + the_same(Bound::::Excluded(5)); } #[test] From a0469e08ef78389bf98c368993983f4b9356d43b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 14:14:15 +0200 Subject: [PATCH 55/80] Added support for NonZero* types --- src/de/impls.rs | 145 ++++++++++++++++++++++++++++------ src/enc/impls.rs | 76 ++++++++++++++++++ src/error.rs | 16 +++- src/varint/decode_unsigned.rs | 2 +- tests/basic_types.rs | 28 +++++++ 5 files changed, 242 insertions(+), 25 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index f7584c0..1b6bfc1 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,13 +1,16 @@ +use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; +use crate::error::{DecodeError, IntegerType}; use core::{ cell::{Cell, RefCell}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + }, ops::{Bound, Range, RangeInclusive}, time::Duration, }; -use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; -use crate::error::DecodeError; - -impl<'de> Decodable for bool { +impl Decodable for bool { fn decode(mut decoder: D) -> Result { match decoder.decode_u8()? { 0 => Ok(false), @@ -17,91 +20,187 @@ impl<'de> Decodable for bool { } } -impl<'de> Decodable for u8 { +impl Decodable for u8 { fn decode(mut decoder: D) -> Result { decoder.decode_u8() } } -impl<'de> Decodable for u16 { +impl Decodable for NonZeroU8 { + fn decode(mut decoder: D) -> Result { + NonZeroU8::new(decoder.decode_u8()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::U8, + }) + } +} + +impl Decodable for u16 { fn decode(mut decoder: D) -> Result { decoder.decode_u16() } } -impl<'de> Decodable for u32 { +impl Decodable for NonZeroU16 { + fn decode(mut decoder: D) -> Result { + NonZeroU16::new(decoder.decode_u16()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::U16, + }) + } +} + +impl Decodable for u32 { fn decode(mut decoder: D) -> Result { decoder.decode_u32() } } -impl<'de> Decodable for u64 { +impl Decodable for NonZeroU32 { + fn decode(mut decoder: D) -> Result { + NonZeroU32::new(decoder.decode_u32()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::U32, + }) + } +} + +impl Decodable for u64 { fn decode(mut decoder: D) -> Result { decoder.decode_u64() } } -impl<'de> Decodable for u128 { +impl Decodable for NonZeroU64 { + fn decode(mut decoder: D) -> Result { + NonZeroU64::new(decoder.decode_u64()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::U64, + }) + } +} + +impl Decodable for u128 { fn decode(mut decoder: D) -> Result { decoder.decode_u128() } } -impl<'de> Decodable for usize { +impl Decodable for NonZeroU128 { + fn decode(mut decoder: D) -> Result { + NonZeroU128::new(decoder.decode_u128()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::U128, + }) + } +} + +impl Decodable for usize { fn decode(mut decoder: D) -> Result { decoder.decode_usize() } } -impl<'de> Decodable for i8 { +impl Decodable for NonZeroUsize { + fn decode(mut decoder: D) -> Result { + NonZeroUsize::new(decoder.decode_usize()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::Usize, + }) + } +} + +impl Decodable for i8 { fn decode(mut decoder: D) -> Result { decoder.decode_i8() } } -impl<'de> Decodable for i16 { +impl Decodable for NonZeroI8 { + fn decode(mut decoder: D) -> Result { + NonZeroI8::new(decoder.decode_i8()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::I8, + }) + } +} + +impl Decodable for i16 { fn decode(mut decoder: D) -> Result { decoder.decode_i16() } } -impl<'de> Decodable for i32 { +impl Decodable for NonZeroI16 { + fn decode(mut decoder: D) -> Result { + NonZeroI16::new(decoder.decode_i16()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::I16, + }) + } +} + +impl Decodable for i32 { fn decode(mut decoder: D) -> Result { decoder.decode_i32() } } -impl<'de> Decodable for i64 { +impl Decodable for NonZeroI32 { + fn decode(mut decoder: D) -> Result { + NonZeroI32::new(decoder.decode_i32()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::I32, + }) + } +} + +impl Decodable for i64 { fn decode(mut decoder: D) -> Result { decoder.decode_i64() } } -impl<'de> Decodable for i128 { +impl Decodable for NonZeroI64 { + fn decode(mut decoder: D) -> Result { + NonZeroI64::new(decoder.decode_i64()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::I64, + }) + } +} + +impl Decodable for i128 { fn decode(mut decoder: D) -> Result { decoder.decode_i128() } } -impl<'de> Decodable for isize { +impl Decodable for NonZeroI128 { + fn decode(mut decoder: D) -> Result { + NonZeroI128::new(decoder.decode_i128()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::I128, + }) + } +} + +impl Decodable for isize { fn decode(mut decoder: D) -> Result { decoder.decode_isize() } } -impl<'de> Decodable for f32 { +impl Decodable for NonZeroIsize { + fn decode(mut decoder: D) -> Result { + NonZeroIsize::new(decoder.decode_isize()?).ok_or(DecodeError::NonZeroTypeIsZero { + non_zero_type: IntegerType::Isize, + }) + } +} + +impl Decodable for f32 { fn decode(mut decoder: D) -> Result { decoder.decode_f32() } } -impl<'de> Decodable for f64 { +impl Decodable for f64 { fn decode(mut decoder: D) -> Result { decoder.decode_f64() } } -impl<'de> Decodable for char { +impl Decodable for char { fn decode(mut decoder: D) -> Result { decoder.decode_char() } @@ -121,19 +220,19 @@ impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a str { } } -impl<'de, const N: usize> Decodable for [u8; N] { +impl Decodable for [u8; N] { fn decode(mut decoder: D) -> Result { decoder.decode_array() } } -impl<'de, T> Decodable for core::marker::PhantomData { +impl Decodable for core::marker::PhantomData { fn decode(_: D) -> Result { Ok(core::marker::PhantomData) } } -impl<'de, T> Decodable for Option +impl Decodable for Option where T: Decodable, { @@ -155,7 +254,7 @@ where } } -impl<'de, T, U> Decodable for Result +impl Decodable for Result where T: Decodable, U: Decodable, diff --git a/src/enc/impls.rs b/src/enc/impls.rs index a452eb9..3307474 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -2,6 +2,10 @@ use super::{Encode, Encodeable}; use crate::error::EncodeError; use core::{ cell::{Cell, RefCell}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + }, ops::{Bound, Range, RangeInclusive}, time::Duration, }; @@ -18,72 +22,144 @@ impl Encodeable for u8 { } } +impl Encodeable for NonZeroU8 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for u16 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u16(*self) } } +impl Encodeable for NonZeroU16 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for u32 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u32(*self) } } +impl Encodeable for NonZeroU32 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for u64 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u64(*self) } } +impl Encodeable for NonZeroU64 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for u128 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_u128(*self) } } +impl Encodeable for NonZeroU128 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for usize { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_usize(*self) } } +impl Encodeable for NonZeroUsize { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for i8 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i8(*self) } } +impl Encodeable for NonZeroI8 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for i16 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i16(*self) } } +impl Encodeable for NonZeroI16 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for i32 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i32(*self) } } +impl Encodeable for NonZeroI32 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for i64 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i64(*self) } } +impl Encodeable for NonZeroI64 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for i128 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_i128(*self) } } +impl Encodeable for NonZeroI128 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for isize { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_isize(*self) } } +impl Encodeable for NonZeroIsize { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.get().encode(encoder) + } +} + impl Encodeable for f32 { fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { encoder.encode_f32(*self) diff --git a/src/error.rs b/src/error.rs index 77528df..2b037db 100644 --- a/src/error.rs +++ b/src/error.rs @@ -59,6 +59,12 @@ pub enum DecodeError { found: IntegerType, }, + /// The decoder tried to decode any of the `NonZero*` types but the value is zero + NonZeroTypeIsZero { + /// The type that was being read from the reader + non_zero_type: IntegerType, + }, + /// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`. UnexpectedVariant { /// The type name that was being decoded. @@ -104,9 +110,17 @@ pub enum DecodeError { #[derive(Debug)] #[allow(missing_docs)] pub enum IntegerType { + U8, U16, U32, U64, U128, - USize, + Usize, + + I8, + I16, + I32, + I64, + I128, + Isize, } diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index 53ac0e7..9954832 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -142,7 +142,7 @@ pub fn varint_decode_usize<'a, R: Reader<'a>>( }) } U128_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::USize, + expected: IntegerType::Usize, found: IntegerType::U128, }), x => Ok(x as usize), diff --git a/tests/basic_types.rs b/tests/basic_types.rs index a3c8d21..7bb100b 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -3,6 +3,7 @@ mod utils; use core::cell::{Cell, RefCell}; use core::ops::Bound; use core::time::Duration; +use std::num::*; use utils::the_same; #[test] @@ -82,6 +83,33 @@ fn test_numbers() { the_same(Bound::::Unbounded); the_same(Bound::::Included(105)); the_same(Bound::::Excluded(5)); + + // NonZero* types + the_same(NonZeroU8::new(0)); + the_same(NonZeroU8::new(123)); + the_same(NonZeroU16::new(0)); + the_same(NonZeroU16::new(12345)); + the_same(NonZeroU32::new(0)); + the_same(NonZeroU32::new(12345)); + the_same(NonZeroU64::new(0)); + the_same(NonZeroU64::new(12345)); + the_same(NonZeroU128::new(0)); + the_same(NonZeroU128::new(12345)); + the_same(NonZeroUsize::new(0)); + the_same(NonZeroUsize::new(12345)); + + the_same(NonZeroI8::new(0)); + the_same(NonZeroI8::new(123)); + the_same(NonZeroI16::new(0)); + the_same(NonZeroI16::new(12345)); + the_same(NonZeroI32::new(0)); + the_same(NonZeroI32::new(12345)); + the_same(NonZeroI64::new(0)); + the_same(NonZeroI64::new(12345)); + the_same(NonZeroI128::new(0)); + the_same(NonZeroI128::new(12345)); + the_same(NonZeroIsize::new(0)); + the_same(NonZeroIsize::new(12345)); } #[test] From 8ab730eb8742a1fc35cf469c0acbe3811d0bbf40 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 14:28:06 +0200 Subject: [PATCH 56/80] Added support for IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6 --- src/features/impl_std.rs | 115 +++++++++++++++++++++++++++++++++++++++ tests/std.rs | 31 ++++++++--- 2 files changed, 139 insertions(+), 7 deletions(-) diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 4b1d8b7..ee30a86 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -7,6 +7,7 @@ use crate::{ use core::time::Duration; use std::{ ffi::{CStr, CString}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, path::{Path, PathBuf}, sync::{Mutex, RwLock}, time::SystemTime, @@ -203,3 +204,117 @@ impl Decodable for PathBuf { Ok(string.into()) } } + +impl Encodeable for IpAddr { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match self { + IpAddr::V4(v4) => { + 0u32.encode(&mut encoder)?; + v4.encode(encoder) + } + IpAddr::V6(v6) => { + 1u32.encode(&mut encoder)?; + v6.encode(encoder) + } + } + } +} + +impl Decodable for IpAddr { + fn decode(mut decoder: D) -> Result { + match u32::decode(&mut decoder)? { + 0 => Ok(IpAddr::V4(Ipv4Addr::decode(decoder)?)), + 1 => Ok(IpAddr::V6(Ipv6Addr::decode(decoder)?)), + found => Err(DecodeError::UnexpectedVariant { + min: 0, + max: 1, + found, + type_name: core::any::type_name::(), + }), + } + } +} + +impl Encodeable for Ipv4Addr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.octets().encode(encoder) + } +} + +impl Decodable for Ipv4Addr { + fn decode(mut decoder: D) -> Result { + Ok(Self::from(decoder.decode_array::<4>()?)) + } +} + +impl Encodeable for Ipv6Addr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.octets().encode(encoder) + } +} + +impl Decodable for Ipv6Addr { + fn decode(mut decoder: D) -> Result { + Ok(Self::from(decoder.decode_array::<16>()?)) + } +} + +impl Encodeable for SocketAddr { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match self { + SocketAddr::V4(v4) => { + 0u32.encode(&mut encoder)?; + v4.encode(encoder) + } + SocketAddr::V6(v6) => { + 1u32.encode(&mut encoder)?; + v6.encode(encoder) + } + } + } +} + +impl Decodable for SocketAddr { + fn decode(mut decoder: D) -> Result { + match u32::decode(&mut decoder)? { + 0 => Ok(SocketAddr::V4(SocketAddrV4::decode(decoder)?)), + 1 => Ok(SocketAddr::V6(SocketAddrV6::decode(decoder)?)), + found => Err(DecodeError::UnexpectedVariant { + min: 0, + max: 1, + found, + type_name: core::any::type_name::(), + }), + } + } +} + +impl Encodeable for SocketAddrV4 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.ip().encode(&mut encoder)?; + self.port().encode(encoder) + } +} + +impl Decodable for SocketAddrV4 { + fn decode(mut decoder: D) -> Result { + let ip = Ipv4Addr::decode(&mut decoder)?; + let port = u16::decode(decoder)?; + Ok(Self::new(ip, port)) + } +} + +impl Encodeable for SocketAddrV6 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.ip().encode(&mut encoder)?; + self.port().encode(encoder) + } +} + +impl Decodable for SocketAddrV6 { + fn decode(mut decoder: D) -> Result { + let ip = Ipv6Addr::decode(&mut decoder)?; + let port = u16::decode(decoder)?; + Ok(Self::new(ip, port, 0, 0)) + } +} diff --git a/tests/std.rs b/tests/std.rs index fafde3a..d94fe0a 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -2,8 +2,13 @@ mod utils; -use std::sync::{Mutex, RwLock}; - +use std::{ + ffi::{CStr, CString}, + io::{Cursor, Seek, SeekFrom}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, + path::{Path, PathBuf}, + sync::{Mutex, RwLock}, +}; use utils::the_same; struct Foo { @@ -33,7 +38,7 @@ impl bincode::de::Decodable for Foo { #[test] fn test_std_cursor() { - let mut cursor = std::io::Cursor::<&[u8]>::new(&[5, 10]); + let mut cursor = Cursor::<&[u8]>::new(&[5, 10]); let foo: Foo = bincode::decode_from(&mut cursor).unwrap(); assert_eq!(foo.a, 5); @@ -42,8 +47,6 @@ fn test_std_cursor() { #[test] fn test_std_file() { - use std::io::{Seek, SeekFrom}; - let mut file = tempfile::tempfile().expect("Could not create temp file"); let bytes_written = bincode::encode_into_write(Foo { a: 30, b: 50 }, &mut file).unwrap(); @@ -58,10 +61,24 @@ fn test_std_file() { #[test] fn test_std_commons() { - use std::ffi::{CStr, CString}; - use std::path::{Path, PathBuf}; the_same(CString::new("Hello world").unwrap()); the_same(PathBuf::from("C:/Program Files/Foo")); + the_same(Ipv4Addr::LOCALHOST); + the_same(Ipv6Addr::LOCALHOST); + the_same(IpAddr::V4(Ipv4Addr::LOCALHOST)); + the_same(IpAddr::V6(Ipv6Addr::LOCALHOST)); + the_same(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 12345)); + the_same(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 12345, 0, 0)); + the_same(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::LOCALHOST, + 12345, + ))); + the_same(SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::LOCALHOST, + 12345, + 0, + 0, + ))); let config = bincode::config::Default; let mut buffer = [0u8; 1024]; From 1f261cede30701c9c7111b8bd4b504ac3bf7cdbf Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 14:49:18 +0200 Subject: [PATCH 57/80] Added support for atomic integers --- Cargo.toml | 3 +- src/features/atomic.rs | 137 +++++++++++++++++++++++++++++++++++++++++ src/features/mod.rs | 5 ++ tests/alloc.rs | 14 ++++- tests/atomic.rs | 49 +++++++++++++++ tests/std.rs | 21 +++---- tests/utils.rs | 52 +++++++++++----- 7 files changed, 253 insertions(+), 28 deletions(-) create mode 100644 src/features/atomic.rs create mode 100644 tests/atomic.rs diff --git a/Cargo.toml b/Cargo.toml index 2fc5727..b195863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,10 @@ description = "A binary serialization / deserialization strategy for transformin edition = "2018" [features] -default = ["std", "derive"] +default = ["std", "derive", "atomic"] std = ["alloc"] alloc = [] +atomic = [] derive = ["bincode_derive"] [dependencies] diff --git a/src/features/atomic.rs b/src/features/atomic.rs new file mode 100644 index 0000000..dbbe2a0 --- /dev/null +++ b/src/features/atomic.rs @@ -0,0 +1,137 @@ +use crate::{de::Decodable, enc::Encodeable}; +use core::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU64, AtomicU8, AtomicUsize, Ordering, +}; + +impl Encodeable for AtomicBool { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicBool { + fn decode(decoder: D) -> Result { + Ok(AtomicBool::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU8 { + fn decode(decoder: D) -> Result { + Ok(AtomicU8::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU16 { + fn decode(decoder: D) -> Result { + Ok(AtomicU16::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU32 { + fn decode(decoder: D) -> Result { + Ok(AtomicU32::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU64 { + fn decode(decoder: D) -> Result { + Ok(AtomicU64::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicUsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicUsize { + fn decode(decoder: D) -> Result { + Ok(AtomicUsize::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI8 { + fn decode(decoder: D) -> Result { + Ok(AtomicI8::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI16 { + fn decode(decoder: D) -> Result { + Ok(AtomicI16::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI32 { + fn decode(decoder: D) -> Result { + Ok(AtomicI32::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI64 { + fn decode(decoder: D) -> Result { + Ok(AtomicI64::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicIsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicIsize { + fn decode(decoder: D) -> Result { + Ok(AtomicIsize::new(Decodable::decode(decoder)?)) + } +} diff --git a/src/features/mod.rs b/src/features/mod.rs index 25ba517..ab1b309 100644 --- a/src/features/mod.rs +++ b/src/features/mod.rs @@ -1,3 +1,8 @@ +#[cfg(feature = "atomic")] +mod atomic; +#[cfg(feature = "atomic")] +pub use self::atomic::*; + #[cfg(feature = "alloc")] mod impl_alloc; #[cfg(feature = "alloc")] diff --git a/tests/alloc.rs b/tests/alloc.rs index 211284a..5f561b8 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -8,7 +8,7 @@ use alloc::borrow::Cow; use alloc::collections::*; use alloc::rc::Rc; use alloc::sync::Arc; -use utils::the_same; +use utils::{the_same, the_same_with_comparer}; struct Foo { pub a: u32, @@ -55,6 +55,18 @@ fn test_alloc_commons() { the_same(Cow::::Borrowed(&5)); the_same(Rc::::new(5)); the_same(Arc::::new(5)); + the_same_with_comparer( + { + let mut map = BinaryHeap::::new(); + map.push(1); + map.push(2); + map.push(3); + map.push(4); + map.push(5); + map + }, + |a, b| a.into_iter().collect::>() == b.into_iter().collect::>(), + ); the_same({ let mut map = BTreeMap::::new(); map.insert(5, -5); diff --git a/tests/atomic.rs b/tests/atomic.rs new file mode 100644 index 0000000..41e53e8 --- /dev/null +++ b/tests/atomic.rs @@ -0,0 +1,49 @@ +#![cfg(feature = "atomic")] + +mod utils; + +use core::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU64, AtomicU8, AtomicUsize, Ordering, +}; +use utils::the_same_with_comparer; + +#[test] +fn test_atomic_commons() { + the_same_with_comparer(AtomicBool::new(true), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicBool::new(false), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU8::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU16::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU32::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU64::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicUsize::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI8::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI16::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI32::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI64::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicIsize::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); +} diff --git a/tests/std.rs b/tests/std.rs index d94fe0a..b804656 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -11,6 +11,8 @@ use std::{ }; use utils::the_same; +use crate::utils::the_same_with_comparer; + struct Foo { pub a: u32, pub b: u32, @@ -79,7 +81,14 @@ fn test_std_commons() { 0, 0, ))); + the_same_with_comparer(Mutex::new("Hello world".to_string()), |a, b| { + &*a.lock().unwrap() == &*b.lock().unwrap() + }); + the_same_with_comparer(RwLock::new("Hello world".to_string()), |a, b| { + &*a.read().unwrap() == &*b.read().unwrap() + }); + // Borrowed values let config = bincode::config::Default; let mut buffer = [0u8; 1024]; @@ -89,18 +98,6 @@ fn test_std_commons() { let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); assert_eq!(cstr, decoded); - // Mutex - let mutex = Mutex::new("Hello world".to_string()); - let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); - let decoded: Mutex = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); - assert_eq!(&*mutex.lock().unwrap(), &*decoded.lock().unwrap()); - - // RwLock - let rwlock = RwLock::new("Hello world".to_string()); - let len = bincode::encode_into_slice_with_config(&rwlock, &mut buffer, config).unwrap(); - let decoded: RwLock = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); - assert_eq!(&*rwlock.read().unwrap(), &*decoded.read().unwrap()); - // Path let path = Path::new("C:/Program Files/Foo"); let len = bincode::encode_into_slice_with_config(path, &mut buffer, config).unwrap(); diff --git a/tests/utils.rs b/tests/utils.rs index 2823a6a..3aa4e79 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,13 +1,14 @@ use bincode::config::{self, Config}; use core::fmt::Debug; -fn the_same_with_config(element: V, config: C) +fn the_same_with_config(element: &V, config: C, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, C: Config, + CMP: Fn(&V, &V) -> bool, { let mut buffer = [0u8; 1024]; - let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", element, @@ -16,68 +17,91 @@ where ); let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); - assert_eq!(element, decoded); + assert!( + cmp(&element, &decoded), + "Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}", + decoded, + element, + &buffer[..len], + ); } -pub fn the_same(element: V) +pub fn the_same_with_comparer(element: V, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, + CMP: Fn(&V, &V) -> bool, { // A matrix of each different config option possible the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_variable_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_variable_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_fixed_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_fixed_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_variable_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element, + &element, config::Default .with_big_endian() .with_variable_int_encoding() .write_fixed_array_length(), + &cmp, ); } + +#[allow(dead_code)] // This is not used in every test +pub fn the_same(element: V) +where + V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + 'static, +{ + the_same_with_comparer(element, |a, b| a == b); +} From 61c1e8a7cd225411a06a84c7d031226a1e4a4860 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 17 Oct 2021 15:00:14 +0200 Subject: [PATCH 58/80] Added badges to the functions to indicate which features they require --- Cargo.toml | 5 +++++ src/features/derive.rs | 1 + src/features/impl_alloc.rs | 4 ++++ src/features/impl_std.rs | 4 ++++ src/lib.rs | 4 +++- tests/alloc.rs | 1 + 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b195863..882ea80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,3 +38,8 @@ serde = { version = "1.0.130", optional = true } serde_derive = "1.0.130" serde_json = "1.0.68" tempfile = "3.2.0" + + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/src/features/derive.rs b/src/features/derive.rs index b55c1b5..a7cb5d1 100644 --- a/src/features/derive.rs +++ b/src/features/derive.rs @@ -1 +1,2 @@ +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use bincode_derive::{Decodable, Encodable}; diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 4132a2f..6d00bfb 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -20,11 +20,13 @@ impl enc::write::Writer for VecWriter { } /// Encode the given value into a `Vec`. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn encode_to_vec(val: E) -> Result, EncodeError> { encode_to_vec_with_config(val, config::Default) } /// Encode the given value into a `Vec` with the given `Config`. See the [config] module for more information. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn encode_to_vec_with_config( val: E, config: C, @@ -271,6 +273,7 @@ where } } +#[cfg(feature = "atomic")] impl Decodable for Arc where T: Decodable, @@ -281,6 +284,7 @@ where } } +#[cfg(feature = "atomic")] impl Encodeable for Arc where T: Encodeable, diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index ee30a86..5c6f245 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -14,6 +14,7 @@ use std::{ }; /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn decode_from(src: &mut R) -> Result { decode_from_with_config(src, config::Default) } @@ -21,6 +22,7 @@ pub fn decode_from(src: &mut R) -> Result( src: &mut R, _config: C, @@ -40,6 +42,7 @@ impl<'storage, R: std::io::Read> Reader<'storage> for R { } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`. +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn encode_into_write( val: E, dst: &mut W, @@ -48,6 +51,7 @@ pub fn encode_into_write( } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn encode_into_write_with_config( val: E, dst: &mut W, diff --git a/src/lib.rs b/src/lib.rs index 59e3dd7..3e066a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![warn(missing_docs)] +#![cfg_attr(docsrs, feature(doc_cfg))] //! Bincode is a crate for encoding and decoding using a tiny binary //! serialization strategy. Using it, you can easily go from having @@ -15,7 +16,8 @@ //! |Name |Default?|Supported types for Encodeable/Decodeable|Enabled methods |Other| //! |------|--------|-----------------------------------------|-----------------------------------------------------------------|-----| //! |std | Yes ||`decode_from[_with_config]` and `encode_into_write[_with_config]`| -//! |alloc | Yes |`Vec`, `HashMap`, `BinaryHeap`, `BTreeMap`, `BTreeSet`, `LinkedList`, `VecDeque`, `Box`, `Arc`, `Rc`, `Cow`|`encode_to_vec[_with_config]`| +//! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec[_with_config]`| +//! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`|| //! |derive| Yes |||Enables the `Encodeable` and `Decodeable` derive macro| //! |serde | No ||`serde_decode_from[_with_config]`, `serde_encode_into[_with_config]`|Also enables `_to_vec` when `alloc` is enabled| diff --git a/tests/alloc.rs b/tests/alloc.rs index 5f561b8..09c7edc 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -54,6 +54,7 @@ fn test_alloc_commons() { the_same(Cow::::Owned(5)); the_same(Cow::::Borrowed(&5)); the_same(Rc::::new(5)); + #[cfg(feature = "atomic")] the_same(Arc::::new(5)); the_same_with_comparer( { From e232454936b1ee5e93cc49bf07d4623e84860115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Sun, 17 Oct 2021 16:18:57 +0200 Subject: [PATCH 59/80] Refactor and rename encoders --- derive/readme.md | 4 +- derive/src/derive_enum.rs | 41 +-- derive/src/derive_struct.rs | 34 +-- derive/src/lib.rs | 28 +- derive/src/parse/generics.rs | 2 +- docs/spec.md | 2 +- src/de/decoder.rs | 285 ++----------------- src/de/impl_tuples.rs | 106 +++---- src/de/impls.rs | 512 +++++++++++++++++++++------------- src/de/mod.rs | 110 ++++---- src/de/read.rs | 12 +- src/enc/encoder.rs | 223 ++------------- src/enc/impl_tuples.rs | 106 +++---- src/enc/impls.rs | 413 +++++++++++++++------------ src/enc/mod.rs | 76 +++-- src/enc/write.rs | 4 +- src/features/atomic.rs | 112 ++++---- src/features/derive.rs | 2 +- src/features/impl_alloc.rs | 142 +++++----- src/features/impl_std.rs | 134 ++++----- src/lib.rs | 16 +- src/varint/decode_signed.rs | 25 +- src/varint/decode_unsigned.rs | 25 +- tests/alloc.rs | 14 +- tests/derive.rs | 38 +-- tests/serde.rs | 2 +- tests/std.rs | 14 +- tests/utils.rs | 6 +- 28 files changed, 1122 insertions(+), 1366 deletions(-) diff --git a/derive/readme.md b/derive/readme.md index 5dd5498..22f216a 100644 --- a/derive/readme.md +++ b/derive/readme.md @@ -1,6 +1,6 @@ # Bincode-derive -The derive crate for bincode. Implements `bincode::Encodable` and `bincode::Decodable`. +The derive crate for bincode. Implements `bincode::Encode` and `bincode::Decode`. This crate is roughly split into 2 parts: @@ -25,4 +25,4 @@ This is supported by the structs in `src/generate`. The most notable points of t For additional derive testing, see the test cases in `../tests` -For testing purposes, all generated code is outputted to the current `target` folder, under file name `_Encodeable.rs` and `_Decodeable.rs`. This can help with debugging. +For testing purposes, all generated code is outputted to the current `target` folder, under file name `_Encode.rs` and `_Decode.rs`. This can help with debugging. diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 394ae2f..fe3270f 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -10,13 +10,13 @@ pub struct DeriveEnum { } impl DeriveEnum { - pub fn generate_encodable(self, generator: &mut Generator) -> Result<()> { + pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { let DeriveEnum { variants } = self; generator - .impl_for("bincode::enc::Encodeable") + .impl_for("bincode::enc::Encode") .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encode"]) + .with_generic("E", ["bincode::enc::Encoder"]) .with_self_arg(FnSelfArg::RefSelf) .with_arg("mut encoder", "E") .with_return_type("core::result::Result<(), bincode::error::EncodeError>") @@ -55,17 +55,20 @@ impl DeriveEnum { // Note that the fields are available as locals because of the match destructuring above // { // encoder.encode_u32(n)?; - // bincode::enc::Encodeable::encode(a, &mut encoder)?; - // bincode::enc::Encodeable::encode(b, &mut encoder)?; - // bincode::enc::Encodeable::encode(c, &mut encoder)?; + // bincode::enc::Encode::encode(a, &mut encoder)?; + // bincode::enc::Encode::encode(b, &mut encoder)?; + // bincode::enc::Encode::encode(c, &mut encoder)?; // } match_body.group(Delimiter::Brace, |body| { // variant index - body.push_parsed(format!("encoder.encode_u32({})?;", variant_index)); + body.push_parsed(format!( + "::encode(&{}, &mut encoder)?;", + variant_index + )); // If we have any fields, encode them all one by one for field_name in variant.fields.names() { body.push_parsed(format!( - "bincode::enc::Encodeable::encode({}, &mut encoder)?;", + "bincode::enc::Encode::encode({}, &mut encoder)?;", field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), )); } @@ -78,21 +81,21 @@ impl DeriveEnum { Ok(()) } - pub fn generate_decodable(self, generator: &mut Generator) -> Result<()> { + pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { let DeriveEnum { variants } = self; let enum_name = generator.target_name().to_string(); if generator.has_lifetimes() { - // enum has a lifetime, implement BorrowDecodable + // enum has a lifetime, implement BorrowDecode - generator.impl_for_with_de_lifetime("bincode::de::BorrowDecodable<'__de>") + generator.impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>") .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecode<'__de>"]) + .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_builder| { fn_builder - .push_parsed("let variant_index = bincode::de::Decode::decode_u32(&mut decoder)?;"); + .push_parsed("let variant_index = ::decode(&mut decoder)?;"); fn_builder.push_parsed("match variant_index"); fn_builder.group(Delimiter::Brace, |variant_case| { for (idx, variant) in variants.iter().enumerate() { @@ -117,7 +120,7 @@ impl DeriveEnum { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); - variant_body.push_parsed("bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?,"); + variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,"); } }); }); @@ -133,16 +136,16 @@ impl DeriveEnum { }); }); } else { - // enum has no lifetimes, implement Decodable - generator.impl_for("bincode::de::Decodable") + // enum has no lifetimes, implement Decode + generator.impl_for("bincode::de::Decode") .generate_fn("decode") - .with_generic("D", ["bincode::de::Decode"]) + .with_generic("D", ["bincode::de::Decoder"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_builder| { fn_builder - .push_parsed("let variant_index = bincode::de::Decode::decode_u32(&mut decoder)?;"); + .push_parsed("let variant_index = ::decode(&mut decoder)?;"); fn_builder.push_parsed("match variant_index"); fn_builder.group(Delimiter::Brace, |variant_case| { for (idx, variant) in variants.iter().enumerate() { @@ -167,7 +170,7 @@ impl DeriveEnum { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); - variant_body.push_parsed("bincode::de::Decodable::decode(&mut decoder)?,"); + variant_body.push_parsed("bincode::de::Decode::decode(&mut decoder)?,"); } }); }); diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 549f7d4..c71b9c8 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -8,20 +8,20 @@ pub struct DeriveStruct { } impl DeriveStruct { - pub fn generate_encodable(self, generator: &mut Generator) -> Result<()> { + pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { let DeriveStruct { fields } = self; - let mut impl_for = generator.impl_for("bincode::enc::Encodeable"); + let mut impl_for = generator.impl_for("bincode::enc::Encode"); impl_for .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encode"]) + .with_generic("E", ["bincode::enc::Encoder"]) .with_self_arg(crate::generate::FnSelfArg::RefSelf) .with_arg("mut encoder", "E") .with_return_type("Result<(), bincode::error::EncodeError>") .body(|fn_body| { for field in fields.names() { fn_body.push_parsed(format!( - "bincode::enc::Encodeable::encode(&self.{}, &mut encoder)?;", + "bincode::enc::Encode::encode(&self.{}, &mut encoder)?;", field.to_string() )); } @@ -31,16 +31,16 @@ impl DeriveStruct { Ok(()) } - pub fn generate_decodable(self, generator: &mut Generator) -> Result<()> { + pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { let DeriveStruct { fields } = self; if generator.has_lifetimes() { - // struct has a lifetime, implement BorrowDecodable + // struct has a lifetime, implement BorrowDecode generator - .impl_for_with_de_lifetime("bincode::de::BorrowDecodable<'__de>") + .impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>") .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecode<'__de>"]) + .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_body| { @@ -51,9 +51,9 @@ impl DeriveStruct { ok_group.group(Delimiter::Brace, |struct_body| { for field in fields.names() { struct_body.push_parsed(format!( - "{}: bincode::de::BorrowDecodable::borrow_decode(&mut decoder)?,", - field.to_string() - )); + "{}: bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,", + field.to_string() + )); } }); }); @@ -61,12 +61,12 @@ impl DeriveStruct { Ok(()) } else { - // struct has no lifetimes, implement Decodable + // struct has no lifetimes, implement Decode - let mut impl_for = generator.impl_for("bincode::de::Decodable"); + let mut impl_for = generator.impl_for("bincode::de::Decode"); impl_for .generate_fn("decode") - .with_generic("D", ["bincode::de::Decode"]) + .with_generic("D", ["bincode::de::Decoder"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_body| { @@ -77,13 +77,13 @@ impl DeriveStruct { ok_group.group(Delimiter::Brace, |struct_body| { // Fields // { - // a: bincode::de::Decodable::decode(&mut decoder)?, - // b: bincode::de::Decodable::decode(&mut decoder)?, + // a: bincode::de::Decode::decode(&mut decoder)?, + // b: bincode::de::Decode::decode(&mut decoder)?, // ... // } for field in fields.names() { struct_body.push_parsed(format!( - "{}: bincode::de::Decodable::decode(&mut decoder)?,", + "{}: bincode::de::Decode::decode(&mut decoder)?,", field.to_string() )); } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 493f143..12c09cb 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -20,15 +20,15 @@ use prelude::TokenStream; type Result = std::result::Result; -#[proc_macro_derive(Encodable)] -pub fn derive_encodable(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +#[proc_macro_derive(Encode)] +pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { #[allow(clippy::useless_conversion)] - derive_encodable_inner(input.into()) + derive_encode_inner(input.into()) .unwrap_or_else(|e| e.into_token_stream()) .into() } -fn derive_encodable_inner(input: TokenStream) -> Result { +fn derive_encode_inner(input: TokenStream) -> Result { let source = &mut input.into_iter().peekable(); let _attributes = parse::Attributes::try_take(source)?; @@ -45,31 +45,31 @@ fn derive_encodable_inner(input: TokenStream) -> Result { derive_struct::DeriveStruct { fields: body.fields, } - .generate_encodable(&mut generator)?; + .generate_encode(&mut generator)?; } parse::DataType::Enum => { let body = parse::EnumBody::take(source)?; derive_enum::DeriveEnum { variants: body.variants, } - .generate_encodable(&mut generator)?; + .generate_encode(&mut generator)?; } } let stream = generator.take_stream(); - dump_output(name, "Encodeable", &stream); + dump_output(name, "Encode", &stream); Ok(stream) } -#[proc_macro_derive(Decodable)] -pub fn derive_decodable(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +#[proc_macro_derive(Decode)] +pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { #[allow(clippy::useless_conversion)] - derive_decodable_inner(input.into()) + derive_decode_inner(input.into()) .unwrap_or_else(|e| e.into_token_stream()) .into() } -fn derive_decodable_inner(input: TokenStream) -> Result { +fn derive_decode_inner(input: TokenStream) -> Result { let source = &mut input.into_iter().peekable(); let _attributes = parse::Attributes::try_take(source)?; @@ -86,19 +86,19 @@ fn derive_decodable_inner(input: TokenStream) -> Result { derive_struct::DeriveStruct { fields: body.fields, } - .generate_decodable(&mut generator)?; + .generate_decode(&mut generator)?; } parse::DataType::Enum => { let body = parse::EnumBody::take(source)?; derive_enum::DeriveEnum { variants: body.variants, } - .generate_decodable(&mut generator)?; + .generate_decode(&mut generator)?; } } let stream = generator.take_stream(); - dump_output(name, "Decodeable", &stream); + dump_output(name, "Decode", &stream); Ok(stream) } diff --git a/derive/src/parse/generics.rs b/derive/src/parse/generics.rs index 3af1581..9495c4c 100644 --- a/derive/src/parse/generics.rs +++ b/derive/src/parse/generics.rs @@ -404,7 +404,7 @@ fn test_generic_constraints_try_take() { let stream = &mut token_stream(""); assert!(GenericConstraints::try_take(stream).unwrap().is_none()); - let stream = &mut token_stream("pub(crate) struct Test {}"); + let stream = &mut token_stream("pub(crate) struct Test {}"); assert_eq!(Visibility::Pub, Visibility::try_take(stream).unwrap()); let (data_type, ident) = DataType::take(stream).unwrap(); assert_eq!(data_type, DataType::Struct); diff --git a/docs/spec.md b/docs/spec.md index 8313c47..58ab56c 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -57,7 +57,7 @@ Enums are encoded with their variant first, followed by optionally the variant f Both named and unnamed fields are serialized with their values only, and therefor encode to the same value. ```rs -#[derive(bincode::Encodable)] +#[derive(bincode::Encode)] pub enum SomeEnum { A, B(u32), diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 8b29cfb..7205f31 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,12 +1,9 @@ use super::{ read::{BorrowReader, Reader}, - BorrowDecode, Decode, + sealed::Sealed, + BorrowDecoder, Decoder, }; -use crate::{ - config::{Config, Endian, IntEncoding}, - error::DecodeError, -}; -use core::marker::PhantomData; +use crate::config::Config; /// A Decoder that reads bytes from a given reader `R`. /// @@ -19,272 +16,44 @@ use core::marker::PhantomData; /// ``` /// # let slice: &[u8] = &[0, 0, 0, 0]; /// # let some_reader = bincode::de::read::SliceReader::new(slice); -/// use bincode::de::{Decoder, Decodable}; +/// use bincode::de::{DecoderImpl, Decode}; /// use bincode::config; -/// let mut decoder = Decoder::new(some_reader, config::Default); -/// // this u32 can be any Decodable +/// let mut decoder = DecoderImpl::new(some_reader, config::Default); +/// // this u32 can be any Decode /// let value = u32::decode(&mut decoder).unwrap(); /// ``` -pub struct Decoder { +pub struct DecoderImpl { reader: R, - config: PhantomData, + config: C, } -impl<'de, R: Reader<'de>, C: Config> Decoder { +impl<'de, R: Reader, C: Config> DecoderImpl { /// Construct a new Decoder - pub fn new(reader: R, _config: C) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } - - /// Consume the decoder and return the inner reader - pub fn into_reader(self) -> R { - self.reader + pub fn new(reader: R, config: C) -> DecoderImpl { + DecoderImpl { reader, config } } } -impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - self.reader.take_bytes(len) +impl<'a, R, C: Config> Sealed for &'a mut DecoderImpl {} + +impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecoder<'de> for &'a mut DecoderImpl { + type BR = R; + + fn borrow_reader(&mut self) -> &mut Self::BR { + &mut self.reader } } -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0]) +impl<'a, 'de, R: Reader, C: Config> Decoder for &'a mut DecoderImpl { + type R = R; + + type C = C; + + fn reader(&mut self) -> &mut Self::R { + &mut self.reader } - fn decode_u16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u16::from_le_bytes(bytes), - Endian::Big => u16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u128::from_le_bytes(bytes), - Endian::Big => u128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_usize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - } as usize) - } - } - } - - fn decode_i8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0] as i8) - } - - fn decode_i16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i16::from_le_bytes(bytes), - Endian::Big => i16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i32::from_le_bytes(bytes), - Endian::Big => i32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i128::from_le_bytes(bytes), - Endian::Big => i128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_isize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - } as isize) - } - } - } - - fn decode_f32(&mut self) -> Result { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f32::from_le_bytes(bytes), - Endian::Big => f32::from_be_bytes(bytes), - }) - } - - fn decode_f64(&mut self) -> Result { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f64::from_le_bytes(bytes), - Endian::Big => f64::from_be_bytes(bytes), - }) - } - - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { - let mut array = [0u8; N]; - if !C::SKIP_FIXED_ARRAY_LENGTH { - let length = self.decode_usize()?; - if length != N { - return Err(DecodeError::ArrayLengthMismatch { - found: length, - required: N, - }); - } - } - self.reader.read(&mut array)?; - Ok(array) - } - - fn decode_char(&mut self) -> Result { - let mut array = [0u8; 4]; - - // Look at the first byte to see how many bytes must be read - self.reader.read(&mut array[..1])?; - - let width = utf8_char_width(array[0]); - if width == 0 { - return Err(DecodeError::InvalidCharEncoding(array)); - } - if width == 1 { - return Ok(array[0] as char); - } - - // read the remaining pain - self.reader.read(&mut array[1..width])?; - let res = core::str::from_utf8(&array[..width]) - .ok() - .and_then(|s| s.chars().next()) - .ok_or(DecodeError::InvalidCharEncoding(array))?; - Ok(res) + fn config(&self) -> &Self::C { + &self.config } } - -const UTF8_CHAR_WIDTH: [u8; 256] = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x7F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0x9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -// This function is a copy of core::str::utf8_char_width -const fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} diff --git a/src/de/impl_tuples.rs b/src/de/impl_tuples.rs index a384a2f..47ab21e 100644 --- a/src/de/impl_tuples.rs +++ b/src/de/impl_tuples.rs @@ -1,32 +1,32 @@ -use super::{Decodable, Decode}; +use super::{Decode, Decoder}; use crate::error::DecodeError; -impl Decodable for (A,) +impl Decode for (A,) where - A: Decodable, + A: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok((A::decode(&mut decoder)?,)) } } -impl Decodable for (A, B) +impl Decode for (A, B) where - A: Decodable, - B: Decodable, + A: Decode, + B: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok((A::decode(&mut decoder)?, B::decode(&mut decoder)?)) } } -impl Decodable for (A, B, C) +impl Decode for (A, B, C) where - A: Decodable, - B: Decodable, - C: Decodable, + A: Decode, + B: Decode, + C: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, @@ -35,14 +35,14 @@ where } } -impl Decodable for (A, B, C, D) +impl Decode for (A, B, C, D) where - A: Decodable, - B: Decodable, - C: Decodable, - D: Decodable, + A: Decode, + B: Decode, + C: Decode, + D: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, @@ -52,15 +52,15 @@ where } } -impl Decodable for (A, B, C, D, E) +impl Decode for (A, B, C, D, E) where - A: Decodable, - B: Decodable, - C: Decodable, - D: Decodable, - E: Decodable, + A: Decode, + B: Decode, + C: Decode, + D: Decode, + E: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, @@ -71,16 +71,16 @@ where } } -impl Decodable for (A, B, C, D, E, F) +impl Decode for (A, B, C, D, E, F) where - A: Decodable, - B: Decodable, - C: Decodable, - D: Decodable, - E: Decodable, - F: Decodable, + A: Decode, + B: Decode, + C: Decode, + D: Decode, + E: Decode, + F: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, @@ -92,17 +92,17 @@ where } } -impl Decodable for (A, B, C, D, E, F, G) +impl Decode for (A, B, C, D, E, F, G) where - A: Decodable, - B: Decodable, - C: Decodable, - D: Decodable, - E: Decodable, - F: Decodable, - G: Decodable, + A: Decode, + B: Decode, + C: Decode, + D: Decode, + E: Decode, + F: Decode, + G: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, @@ -115,18 +115,18 @@ where } } -impl Decodable for (A, B, C, D, E, F, G, H) +impl Decode for (A, B, C, D, E, F, G, H) where - A: Decodable, - B: Decodable, - C: Decodable, - D: Decodable, - E: Decodable, - F: Decodable, - G: Decodable, - H: Decodable, + A: Decode, + B: Decode, + C: Decode, + D: Decode, + E: Decode, + F: Decode, + G: Decode, + H: Decode, { - fn decode<_D: Decode>(mut decoder: _D) -> Result { + fn decode<_D: Decoder>(mut decoder: _D) -> Result { Ok(( A::decode(&mut decoder)?, B::decode(&mut decoder)?, diff --git a/src/de/impls.rs b/src/de/impls.rs index 1b6bfc1..39fbaa3 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -1,5 +1,11 @@ -use super::{BorrowDecodable, BorrowDecode, Decodable, Decode}; -use crate::error::{DecodeError, IntegerType}; +use super::{ + read::{BorrowReader, Reader}, + BorrowDecode, BorrowDecoder, Decode, Decoder, +}; +use crate::{ + config::{Endian, IntEncoding, InternalConfig}, + error::{DecodeError, IntegerType}, +}; use core::{ cell::{Cell, RefCell}, num::{ @@ -10,9 +16,9 @@ use core::{ time::Duration, }; -impl Decodable for bool { - fn decode(mut decoder: D) -> Result { - match decoder.decode_u8()? { +impl Decode for bool { + fn decode(decoder: D) -> Result { + match u8::decode(decoder)? { 0 => Ok(false), 1 => Ok(true), x => Err(DecodeError::InvalidBooleanValue(x)), @@ -20,223 +26,387 @@ impl Decodable for bool { } } -impl Decodable for u8 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u8() +impl Decode for u8 { + fn decode(mut decoder: D) -> Result { + let mut bytes = [0u8; 1]; + decoder.reader().read(&mut bytes)?; + Ok(bytes[0]) } } -impl Decodable for NonZeroU8 { - fn decode(mut decoder: D) -> Result { - NonZeroU8::new(decoder.decode_u8()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroU8 { + fn decode(decoder: D) -> Result { + NonZeroU8::new(u8::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::U8, }) } } -impl Decodable for u16 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u16() +impl Decode for u16 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_u16(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => u16::from_le_bytes(bytes), + Endian::Big => u16::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroU16 { - fn decode(mut decoder: D) -> Result { - NonZeroU16::new(decoder.decode_u16()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroU16 { + fn decode(decoder: D) -> Result { + NonZeroU16::new(u16::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::U16, }) } } -impl Decodable for u32 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u32() +impl Decode for u32 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_u32(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroU32 { - fn decode(mut decoder: D) -> Result { - NonZeroU32::new(decoder.decode_u32()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroU32 { + fn decode(decoder: D) -> Result { + NonZeroU32::new(u32::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::U32, }) } } -impl Decodable for u64 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u64() +impl Decode for u64 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_u64(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroU64 { - fn decode(mut decoder: D) -> Result { - NonZeroU64::new(decoder.decode_u64()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroU64 { + fn decode(decoder: D) -> Result { + NonZeroU64::new(u64::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::U64, }) } } -impl Decodable for u128 { - fn decode(mut decoder: D) -> Result { - decoder.decode_u128() +impl Decode for u128 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_u128(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => u128::from_le_bytes(bytes), + Endian::Big => u128::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroU128 { - fn decode(mut decoder: D) -> Result { - NonZeroU128::new(decoder.decode_u128()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroU128 { + fn decode(decoder: D) -> Result { + NonZeroU128::new(u128::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::U128, }) } } -impl Decodable for usize { - fn decode(mut decoder: D) -> Result { - decoder.decode_usize() +impl Decode for usize { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_usize(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + } as usize) + } + } } } -impl Decodable for NonZeroUsize { - fn decode(mut decoder: D) -> Result { - NonZeroUsize::new(decoder.decode_usize()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroUsize { + fn decode(decoder: D) -> Result { + NonZeroUsize::new(usize::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::Usize, }) } } -impl Decodable for i8 { - fn decode(mut decoder: D) -> Result { - decoder.decode_i8() +impl Decode for i8 { + fn decode(mut decoder: D) -> Result { + let mut bytes = [0u8; 1]; + decoder.reader().read(&mut bytes)?; + Ok(bytes[0] as i8) } } -impl Decodable for NonZeroI8 { - fn decode(mut decoder: D) -> Result { - NonZeroI8::new(decoder.decode_i8()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroI8 { + fn decode(decoder: D) -> Result { + NonZeroI8::new(i8::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::I8, }) } } -impl Decodable for i16 { - fn decode(mut decoder: D) -> Result { - decoder.decode_i16() +impl Decode for i16 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_i16(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => i16::from_le_bytes(bytes), + Endian::Big => i16::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroI16 { - fn decode(mut decoder: D) -> Result { - NonZeroI16::new(decoder.decode_i16()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroI16 { + fn decode(decoder: D) -> Result { + NonZeroI16::new(i16::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::I16, }) } } -impl Decodable for i32 { - fn decode(mut decoder: D) -> Result { - decoder.decode_i32() +impl Decode for i32 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_i32(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => i32::from_le_bytes(bytes), + Endian::Big => i32::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroI32 { - fn decode(mut decoder: D) -> Result { - NonZeroI32::new(decoder.decode_i32()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroI32 { + fn decode(decoder: D) -> Result { + NonZeroI32::new(i32::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::I32, }) } } -impl Decodable for i64 { - fn decode(mut decoder: D) -> Result { - decoder.decode_i64() +impl Decode for i64 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_i64(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroI64 { - fn decode(mut decoder: D) -> Result { - NonZeroI64::new(decoder.decode_i64()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroI64 { + fn decode(decoder: D) -> Result { + NonZeroI64::new(i64::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::I64, }) } } -impl Decodable for i128 { - fn decode(mut decoder: D) -> Result { - decoder.decode_i128() +impl Decode for i128 { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_i128(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => i128::from_le_bytes(bytes), + Endian::Big => i128::from_be_bytes(bytes), + }) + } + } } } -impl Decodable for NonZeroI128 { - fn decode(mut decoder: D) -> Result { - NonZeroI128::new(decoder.decode_i128()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroI128 { + fn decode(decoder: D) -> Result { + NonZeroI128::new(i128::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::I128, }) } } -impl Decodable for isize { - fn decode(mut decoder: D) -> Result { - decoder.decode_isize() +impl Decode for isize { + fn decode(mut decoder: D) -> Result { + match D::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_isize(decoder.reader(), D::C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + } as isize) + } + } } } -impl Decodable for NonZeroIsize { - fn decode(mut decoder: D) -> Result { - NonZeroIsize::new(decoder.decode_isize()?).ok_or(DecodeError::NonZeroTypeIsZero { +impl Decode for NonZeroIsize { + fn decode(decoder: D) -> Result { + NonZeroIsize::new(isize::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero { non_zero_type: IntegerType::Isize, }) } } -impl Decodable for f32 { - fn decode(mut decoder: D) -> Result { - decoder.decode_f32() +impl Decode for f32 { + fn decode(mut decoder: D) -> Result { + let mut bytes = [0u8; 4]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => f32::from_le_bytes(bytes), + Endian::Big => f32::from_be_bytes(bytes), + }) } } -impl Decodable for f64 { - fn decode(mut decoder: D) -> Result { - decoder.decode_f64() +impl Decode for f64 { + fn decode(mut decoder: D) -> Result { + let mut bytes = [0u8; 8]; + decoder.reader().read(&mut bytes)?; + Ok(match D::C::ENDIAN { + Endian::Little => f64::from_le_bytes(bytes), + Endian::Big => f64::from_be_bytes(bytes), + }) } } -impl Decodable for char { - fn decode(mut decoder: D) -> Result { - decoder.decode_char() +impl Decode for char { + fn decode(mut decoder: D) -> Result { + let mut array = [0u8; 4]; + + // Look at the first byte to see how many bytes must be read + decoder.reader().read(&mut array[..1])?; + + let width = utf8_char_width(array[0]); + if width == 0 { + return Err(DecodeError::InvalidCharEncoding(array)); + } + if width == 1 { + return Ok(array[0] as char); + } + + // read the remaining pain + decoder.reader().read(&mut array[1..width])?; + let res = core::str::from_utf8(&array[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or(DecodeError::InvalidCharEncoding(array))?; + Ok(res) } } -impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a [u8] { - fn borrow_decode>(mut decoder: D) -> Result { +impl<'a, 'de: 'a> BorrowDecode<'de> for &'a [u8] { + fn borrow_decode>(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; - decoder.decode_slice(len) + decoder.borrow_reader().take_bytes(len) } } -impl<'a, 'de: 'a> BorrowDecodable<'de> for &'a str { - fn borrow_decode>(decoder: D) -> Result { - let slice: &[u8] = BorrowDecodable::borrow_decode(decoder)?; +impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str { + fn borrow_decode>(decoder: D) -> Result { + let slice: &[u8] = BorrowDecode::borrow_decode(decoder)?; core::str::from_utf8(slice).map_err(DecodeError::Utf8) } } -impl Decodable for [u8; N] { - fn decode(mut decoder: D) -> Result { - decoder.decode_array() +impl Decode for [u8; N] { + fn decode(mut decoder: D) -> Result { + let mut array = [0u8; N]; + if !D::C::SKIP_FIXED_ARRAY_LENGTH { + let length = usize::decode(&mut decoder)?; + if length != N { + return Err(DecodeError::ArrayLengthMismatch { + found: length, + required: N, + }); + } + } + decoder.reader().read(&mut array)?; + Ok(array) } } -impl Decodable for core::marker::PhantomData { - fn decode(_: D) -> Result { +impl Decode for core::marker::PhantomData { + fn decode(_: D) -> Result { Ok(core::marker::PhantomData) } } -impl Decodable for Option +impl Decode for Option where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let is_some = u8::decode(&mut decoder)?; match is_some { 0 => Ok(None), @@ -254,12 +424,12 @@ where } } -impl Decodable for Result +impl Decode for Result where - T: Decodable, - U: Decodable, + T: Decode, + U: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let is_ok = u8::decode(&mut decoder)?; match is_ok { 0 => { @@ -280,61 +450,61 @@ where } } -impl Decodable for Cell +impl Decode for Cell where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Cell::new(t)) } } -impl Decodable for RefCell +impl Decode for RefCell where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(RefCell::new(t)) } } -impl Decodable for Duration { - fn decode(mut decoder: D) -> Result { - let secs = Decodable::decode(&mut decoder)?; - let nanos = Decodable::decode(&mut decoder)?; +impl Decode for Duration { + fn decode(mut decoder: D) -> Result { + let secs = Decode::decode(&mut decoder)?; + let nanos = Decode::decode(&mut decoder)?; Ok(Duration::new(secs, nanos)) } } -impl Decodable for Range +impl Decode for Range where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let min = T::decode(&mut decoder)?; let max = T::decode(&mut decoder)?; Ok(min..max) } } -impl Decodable for RangeInclusive +impl Decode for RangeInclusive where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let min = T::decode(&mut decoder)?; let max = T::decode(&mut decoder)?; Ok(RangeInclusive::new(min, max)) } } -impl Decodable for Bound +impl Decode for Bound where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { match u32::decode(&mut decoder)? { 0 => Ok(Bound::Unbounded), 1 => Ok(Bound::Included(T::decode(decoder)?)), @@ -349,80 +519,26 @@ where } } -impl<'a, 'de, T> Decode for &'a mut T -where - T: Decode, -{ - fn decode_u8(&mut self) -> Result { - T::decode_u8(self) - } +const UTF8_CHAR_WIDTH: [u8; 256] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x7F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0x9F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; - fn decode_u16(&mut self) -> Result { - T::decode_u16(self) - } - - fn decode_u32(&mut self) -> Result { - T::decode_u32(self) - } - - fn decode_u64(&mut self) -> Result { - T::decode_u64(self) - } - - fn decode_u128(&mut self) -> Result { - T::decode_u128(self) - } - - fn decode_usize(&mut self) -> Result { - T::decode_usize(self) - } - - fn decode_i8(&mut self) -> Result { - T::decode_i8(self) - } - - fn decode_i16(&mut self) -> Result { - T::decode_i16(self) - } - - fn decode_i32(&mut self) -> Result { - T::decode_i32(self) - } - - fn decode_i64(&mut self) -> Result { - T::decode_i64(self) - } - - fn decode_i128(&mut self) -> Result { - T::decode_i128(self) - } - - fn decode_isize(&mut self) -> Result { - T::decode_isize(self) - } - - fn decode_f32(&mut self) -> Result { - T::decode_f32(self) - } - - fn decode_f64(&mut self) -> Result { - T::decode_f64(self) - } - - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { - T::decode_array::(self) - } - - fn decode_char(&mut self) -> Result { - T::decode_char(self) - } -} - -impl<'a, 'de, T> BorrowDecode<'de> for &'a mut T -where - T: BorrowDecode<'de>, -{ - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - T::decode_slice(self, len) - } +// This function is a copy of core::str::utf8_char_width +const fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize } diff --git a/src/de/mod.rs b/src/de/mod.rs index 199f559..df709e4 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,81 +1,95 @@ //! Decoder-based structs and traits. -use crate::error::DecodeError; +use crate::{config::Config, error::DecodeError}; mod decoder; mod impl_tuples; mod impls; pub mod read; -pub use self::decoder::Decoder; +pub use self::decoder::DecoderImpl; +use self::read::{BorrowReader, Reader}; /// Trait that makes a type able to be decoded, akin to serde's `DeserializeOwned` trait. /// -/// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [BorrowDecodable] instead. +/// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [BorrowDecode] instead. /// -/// Whenever you implement `Decodable` for your type, the base trait `BorrowDecodable` is automatically implemented. -pub trait Decodable: for<'de> BorrowDecodable<'de> { +/// Whenever you implement `Decode` for your type, the base trait `BorrowDecode` is automatically implemented. +pub trait Decode: for<'de> BorrowDecode<'de> { /// Attempt to decode this type with the given [Decode]. - fn decode(decoder: D) -> Result; + fn decode(decoder: D) -> Result; } /// Trait that makes a type able to be decoded, akin to serde's `Deserialize` trait. /// -/// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [Decodable] instead. -pub trait BorrowDecodable<'de>: Sized { +/// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [Decode] instead. +pub trait BorrowDecode<'de>: Sized { /// Attempt to decode this type with the given [BorrowDecode]. - fn borrow_decode>(decoder: D) -> Result; + fn borrow_decode>(decoder: D) -> Result; } -impl<'de, T: Decodable> BorrowDecodable<'de> for T { - fn borrow_decode(decoder: D) -> Result { - Decodable::decode(decoder) +impl<'de, T: Decode> BorrowDecode<'de> for T { + fn borrow_decode(decoder: D) -> Result { + Decode::decode(decoder) } } /// Any source that can decode basic types. This type is most notably implemented for [Decoder]. -pub trait Decode { - /// Attempt to decode a `u8` - fn decode_u8(&mut self) -> Result; - /// Attempt to decode a `u16` - fn decode_u16(&mut self) -> Result; - /// Attempt to decode a `u32` - fn decode_u32(&mut self) -> Result; - /// Attempt to decode a `u64` - fn decode_u64(&mut self) -> Result; - /// Attempt to decode a `u128` - fn decode_u128(&mut self) -> Result; - /// Attempt to decode a `usize` - fn decode_usize(&mut self) -> Result; +pub trait Decoder: sealed::Sealed { + /// The concrete [Reader] type + type R: Reader; - /// Attempt to decode a `i8` - fn decode_i8(&mut self) -> Result; - /// Attempt to decode a `i16` - fn decode_i16(&mut self) -> Result; - /// Attempt to decode a `i32` - fn decode_i32(&mut self) -> Result; - /// Attempt to decode a `i64` - fn decode_i64(&mut self) -> Result; - /// Attempt to decode a `i128` - fn decode_i128(&mut self) -> Result; - /// Attempt to decode a `isize` - fn decode_isize(&mut self) -> Result; + /// The concrete [Config] type + type C: Config; - /// Attempt to decode a `f32` - fn decode_f32(&mut self) -> Result; - /// Attempt to decode a `f64` - fn decode_f64(&mut self) -> Result; - /// Attempt to decode an array of `N` entries. - fn decode_array(&mut self) -> Result<[u8; N], DecodeError>; + /// Returns a mutable reference to the reader + fn reader(&mut self) -> &mut Self::R; - /// Attempt to decode a `char` - fn decode_char(&mut self) -> Result; + /// Returns a mutable reference to the config + fn config(&self) -> &Self::C; } /// Any source that can decode basic types. This type is most notably implemented for [Decoder]. /// /// This is an extension of [Decode] that can also return borrowed data. -pub trait BorrowDecode<'de>: Decode { - /// Decode `len` bytes, returning the slice as borrowed data. - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError>; +pub trait BorrowDecoder<'de>: Decoder { + /// The concrete [BorrowReader] type + type BR: BorrowReader<'de>; + + /// Rerturns a mutable reference to the borrow reader + fn borrow_reader(&mut self) -> &mut Self::BR; +} + +impl<'a, 'de, T> Decoder for &'a mut T +where + T: Decoder, +{ + type R = T::R; + + type C = T::C; + + fn reader(&mut self) -> &mut Self::R { + T::reader(self) + } + + fn config(&self) -> &Self::C { + T::config(self) + } +} + +impl<'a, 'de, T> BorrowDecoder<'de> for &'a mut T +where + T: BorrowDecoder<'de>, +{ + type BR = T::BR; + + fn borrow_reader(&mut self) -> &mut Self::BR { + T::borrow_reader(self) + } +} + +pub(crate) mod sealed { + pub trait Sealed {} + + impl<'a, T> Sealed for &'a mut T where T: Sealed {} } diff --git a/src/de/read.rs b/src/de/read.rs index 6a0030a..196d6d3 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -6,21 +6,21 @@ //! //! [BorrowReader] is an extension of `Reader` that also allows returning borrowed data. A `BorrowReader` allows reading `&str` and `&[u8]`. //! -//! Specifically the `Reader` trait is used by [Decodable] and the `BorrowReader` trait is used by `[BorrowDecodable]`. +//! Specifically the `Reader` trait is used by [Decode] and the `BorrowReader` trait is used by `[BorrowDecode]`. //! -//! [Decodable]: ../trait.Decodable.html -//! [BorrowDecodable]: ../trait.BorrowDecodable.html +//! [Decode]: ../trait.Decode.html +//! [BorrowDecode]: ../trait.BorrowDecode.html use crate::error::DecodeError; /// A reader for owned data. See the module documentation for more information. -pub trait Reader<'storage> { +pub trait Reader { /// Fill the given `bytes` argument with values. Exactly the length of the given slice must be filled, or else an error must be returned. fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>; } /// A reader for borrowed data. Implementors of this must also implement the [Reader] trait. See the module documentation for more information. -pub trait BorrowReader<'storage>: Reader<'storage> { +pub trait BorrowReader<'storage>: Reader { /// Read exactly `length` bytes and return a slice to this data. If not enough bytes could be read, an error should be returned. /// /// *note*: Exactly `length` bytes must be returned. If less bytes are returned, bincode may panic. If more bytes are returned, the excess bytes may be discarded. @@ -49,7 +49,7 @@ impl<'storage> SliceReader<'storage> { } } -impl<'storage> Reader<'storage> for SliceReader<'storage> { +impl<'storage> Reader for SliceReader<'storage> { #[inline(always)] fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { if bytes.len() > self.slice.len() { diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index a942b2d..135347f 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,11 +1,7 @@ //! Contains -use super::{write::Writer, Encode}; -use crate::{ - config::{Config, Endian, IntEncoding}, - error::EncodeError, -}; -use core::marker::PhantomData; +use super::{sealed::Sealed, write::Writer, Encoder}; +use crate::config::Config; /// An Encoder that writes bytes into a given writer `W`. /// @@ -16,28 +12,25 @@ use core::marker::PhantomData; /// is used to write integers to the writer. /// /// ``` -/// # use bincode::enc::{write::SliceWriter, Encoder, Encodeable}; +/// # use bincode::enc::{write::SliceWriter, EncoderImpl, Encode}; /// # use bincode::config::{self, Config}; /// # let config = config::Default.with_fixed_int_encoding().with_big_endian(); /// let slice: &mut [u8] = &mut [0, 0, 0, 0]; -/// let mut encoder = Encoder::new(SliceWriter::new(slice), config); +/// let mut encoder = EncoderImpl::new(SliceWriter::new(slice), config); /// // this u32 can be any Encodable /// 5u32.encode(&mut encoder).unwrap(); /// assert_eq!(encoder.into_writer().bytes_written(), 4); /// assert_eq!(slice, [0, 0, 0, 5]); /// ``` -pub struct Encoder { +pub struct EncoderImpl { writer: W, - config: PhantomData, + config: C, } -impl Encoder { +impl EncoderImpl { /// Create a new Encoder - pub fn new(writer: W, _config: C) -> Encoder { - Encoder { - writer, - config: PhantomData, - } + pub fn new(writer: W, config: C) -> EncoderImpl { + EncoderImpl { writer, config } } /// Return the underlying writer @@ -46,196 +39,18 @@ impl Encoder { } } -impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { - fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError> { - self.writer.write(&[val]) +impl<'a, W: Writer, C: Config> Encoder for &'a mut EncoderImpl { + type W = W; + + type C = C; + + fn writer(&mut self) -> &mut Self::W { + &mut self.writer } - fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - self.writer.write(&[val as u8]) - } - - fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::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<(), EncodeError> { - 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<(), EncodeError> { - 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<(), EncodeError> { - self.encode_usize(val.len())?; - self.writer.write(val) - } - - fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { - if !C::SKIP_FIXED_ARRAY_LENGTH { - self.encode_usize(N)?; - } - self.writer.write(&val) - } - - fn encode_char(&mut self, val: char) -> Result<(), EncodeError> { - encode_utf8(&mut self.writer, val) + fn config(&self) -> &Self::C { + &self.config } } -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; - -fn encode_utf8(writer: &mut impl Writer, c: char) -> Result<(), EncodeError> { - let code = c as u32; - - if code < MAX_ONE_B { - writer.write(&[c as u8]) - } else if code < MAX_TWO_B { - let mut buf = [0u8; 2]; - buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - buf[1] = (code & 0x3F) as u8 | TAG_CONT; - writer.write(&buf) - } else if code < MAX_THREE_B { - let mut buf = [0u8; 3]; - buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code & 0x3F) as u8 | TAG_CONT; - writer.write(&buf) - } else { - let mut buf = [0u8; 4]; - buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - writer.write(&buf) - } -} +impl<'a, W: Writer, C: Config> Sealed for &'a mut EncoderImpl {} diff --git a/src/enc/impl_tuples.rs b/src/enc/impl_tuples.rs index b9cdb64..3ab46b1 100644 --- a/src/enc/impl_tuples.rs +++ b/src/enc/impl_tuples.rs @@ -1,35 +1,35 @@ -use super::{Encode, Encodeable}; +use super::{Encode, Encoder}; use crate::error::EncodeError; -impl Encodeable for (A,) +impl Encode for (A,) where - A: Encodeable, + A: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; Ok(()) } } -impl Encodeable for (A, B) +impl Encode for (A, B) where - A: Encodeable, - B: Encodeable, + A: Encode, + B: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; Ok(()) } } -impl Encodeable for (A, B, C) +impl Encode for (A, B, C) where - A: Encodeable, - B: Encodeable, - C: Encodeable, + A: Encode, + B: Encode, + C: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; @@ -37,14 +37,14 @@ where } } -impl Encodeable for (A, B, C, D) +impl Encode for (A, B, C, D) where - A: Encodeable, - B: Encodeable, - C: Encodeable, - D: Encodeable, + A: Encode, + B: Encode, + C: Encode, + D: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; @@ -53,15 +53,15 @@ where } } -impl Encodeable for (A, B, C, D, E) +impl Encode for (A, B, C, D, E) where - A: Encodeable, - B: Encodeable, - C: Encodeable, - D: Encodeable, - E: Encodeable, + A: Encode, + B: Encode, + C: Encode, + D: Encode, + E: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; @@ -71,16 +71,16 @@ where } } -impl Encodeable for (A, B, C, D, E, F) +impl Encode for (A, B, C, D, E, F) where - A: Encodeable, - B: Encodeable, - C: Encodeable, - D: Encodeable, - E: Encodeable, - F: Encodeable, + A: Encode, + B: Encode, + C: Encode, + D: Encode, + E: Encode, + F: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; @@ -91,17 +91,17 @@ where } } -impl Encodeable for (A, B, C, D, E, F, G) +impl Encode for (A, B, C, D, E, F, G) where - A: Encodeable, - B: Encodeable, - C: Encodeable, - D: Encodeable, - E: Encodeable, - F: Encodeable, - G: Encodeable, + A: Encode, + B: Encode, + C: Encode, + D: Encode, + E: Encode, + F: Encode, + G: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; @@ -113,18 +113,18 @@ where } } -impl Encodeable for (A, B, C, D, E, F, G, H) +impl Encode for (A, B, C, D, E, F, G, H) where - A: Encodeable, - B: Encodeable, - C: Encodeable, - D: Encodeable, - E: Encodeable, - F: Encodeable, - G: Encodeable, - H: Encodeable, + A: Encode, + B: Encode, + C: Encode, + D: Encode, + E: Encode, + F: Encode, + G: Encode, + H: Encode, { - fn encode<_E: Encode>(&self, mut encoder: _E) -> Result<(), EncodeError> { + fn encode<_E: Encoder>(&self, mut encoder: _E) -> Result<(), EncodeError> { self.0.encode(&mut encoder)?; self.1.encode(&mut encoder)?; self.2.encode(&mut encoder)?; diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 3307474..4a567a7 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,5 +1,8 @@ -use super::{Encode, Encodeable}; -use crate::error::EncodeError; +use super::{write::Writer, Encode, Encoder}; +use crate::{ + config::{Endian, IntEncoding, InternalConfig}, + error::EncodeError, +}; use core::{ cell::{Cell, RefCell}, num::{ @@ -10,192 +13,313 @@ use core::{ time::Duration, }; -impl Encodeable for bool { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u8(if *self { 1 } else { 0 }) +impl Encode for bool { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + if *self { 1u8 } else { 0u8 }.encode(encoder) } } -impl Encodeable for u8 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u8(*self) +impl Encode for u8 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.writer().write(&[*self]) } } -impl Encodeable for NonZeroU8 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroU8 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for u16 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u16(*self) +impl Encode for u16 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_u16(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroU16 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroU16 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for u32 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u32(*self) +impl Encode for u32 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_u32(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroU32 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroU32 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for u64 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u64(*self) +impl Encode for u64 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_u64(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroU64 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroU64 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for u128 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_u128(*self) +impl Encode for u128 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_u128(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroU128 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroU128 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for usize { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_usize(*self) +impl Encode for usize { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_usize(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroUsize { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroUsize { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for i8 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_i8(*self) +impl Encode for i8 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encoder.writer().write(&[*self as u8]) } } -impl Encodeable for NonZeroI8 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroI8 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for i16 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_i16(*self) +impl Encode for i16 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_i16(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroI16 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroI16 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for i32 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_i32(*self) +impl Encode for i32 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_i32(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroI32 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroI32 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for i64 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_i64(*self) +impl Encode for i64 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_i64(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroI64 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroI64 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for i128 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_i128(*self) +impl Encode for i128 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_i128(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroI128 { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroI128 { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for isize { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_isize(*self) +impl Encode for isize { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_encode_isize(encoder.writer(), E::C::ENDIAN, *self) + } + IntEncoding::Fixed => match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + }, + } } } -impl Encodeable for NonZeroIsize { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for NonZeroIsize { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.get().encode(encoder) } } -impl Encodeable for f32 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_f32(*self) +impl Encode for f32 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + } } } -impl Encodeable for f64 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_f64(*self) +impl Encode for f64 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + match E::C::ENDIAN { + Endian::Big => encoder.writer().write(&self.to_be_bytes()), + Endian::Little => encoder.writer().write(&self.to_le_bytes()), + } } } -impl Encodeable for char { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_char(*self) +impl Encode for char { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + encode_utf8(encoder.writer(), *self) } } -impl Encodeable for &'_ [u8] { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_slice(*self) +impl Encode for &'_ [u8] { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + self.len().encode(&mut encoder)?; + encoder.writer().write(self) + } +} + +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +fn encode_utf8(writer: &mut impl Writer, c: char) -> Result<(), EncodeError> { + let code = c as u32; + + if code < MAX_ONE_B { + writer.write(&[c as u8]) + } else if code < MAX_TWO_B { + let mut buf = [0u8; 2]; + buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + buf[1] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) + } else if code < MAX_THREE_B { + let mut buf = [0u8; 3]; + buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[2] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) + } else { + let mut buf = [0u8; 4]; + buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; + buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + writer.write(&buf) } } // BlockedTODO: https://github.com/rust-lang/rust/issues/37653 // -// We'll want to implement encoding for both &[u8] and &[T: Encodeable], +// We'll want to implement encoding for both &[u8] and &[T: Encode], // but those implementations overlap because u8 also implements Encodeabl // -// default impl Encodeable for &'_ [u8] { +// default impl Encode for &'_ [u8] { // fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { // encoder.encode_slice(*self) // } // } // -// impl Encodeable for &'_ [T] { +// impl Encode for &'_ [T] { // fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { // self.len().encode(&mut encoder)?; // for item in self.iter() { @@ -205,23 +329,26 @@ impl Encodeable for &'_ [u8] { // } // } -impl Encodeable for &'_ str { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_slice(self.as_bytes()) +impl Encode for &'_ str { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + self.as_bytes().encode(encoder) } } -impl Encodeable for [u8; N] { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { - encoder.encode_array(*self) +impl Encode for [u8; N] { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + if !E::C::SKIP_FIXED_ARRAY_LENGTH { + N.encode(&mut encoder)?; + } + encoder.writer().write(self) } } -impl Encodeable for Option +impl Encode for Option where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { if let Some(val) = self { 1u8.encode(&mut encoder)?; val.encode(encoder) @@ -231,12 +358,12 @@ where } } -impl Encodeable for Result +impl Encode for Result where - T: Encodeable, - U: Encodeable, + T: Encode, + U: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { match self { Ok(val) => { 0u8.encode(&mut encoder)?; @@ -250,20 +377,20 @@ where } } -impl Encodeable for Cell +impl Encode for Cell where - T: Encodeable + Copy, + T: Encode + Copy, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { T::encode(&self.get(), encoder) } } -impl Encodeable for RefCell +impl Encode for RefCell where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { let borrow_guard = self .try_borrow() .map_err(|e| EncodeError::RefCellAlreadyBorrowed { @@ -274,41 +401,41 @@ where } } -impl Encodeable for Duration { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +impl Encode for Duration { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.as_secs().encode(&mut encoder)?; self.subsec_nanos().encode(&mut encoder)?; Ok(()) } } -impl Encodeable for Range +impl Encode for Range where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.start.encode(&mut encoder)?; self.end.encode(&mut encoder)?; Ok(()) } } -impl Encodeable for RangeInclusive +impl Encode for RangeInclusive where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.start().encode(&mut encoder)?; self.end().encode(&mut encoder)?; Ok(()) } } -impl Encodeable for Bound +impl Encode for Bound where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { match self { Self::Unbounded => { 0u32.encode(encoder)?; @@ -326,71 +453,11 @@ where } } -impl<'a, T> Encodeable for &'a T -where - T: Encodeable, -{ - fn encode(&self, encoder: E) -> Result<(), EncodeError> { - T::encode(self, encoder) - } -} - -impl<'a, T> Encode for &'a mut T +impl<'a, T> Encode for &'a T where T: Encode, { - fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError> { - T::encode_u8(self, val) - } - fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError> { - T::encode_u16(self, val) - } - fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError> { - T::encode_u32(self, val) - } - fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError> { - T::encode_u64(self, val) - } - fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError> { - T::encode_u128(self, val) - } - fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError> { - T::encode_usize(self, val) - } - - fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError> { - T::encode_i8(self, val) - } - fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError> { - T::encode_i16(self, val) - } - fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError> { - T::encode_i32(self, val) - } - fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError> { - T::encode_i64(self, val) - } - fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError> { - T::encode_i128(self, val) - } - fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError> { - T::encode_isize(self, val) - } - - fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError> { - T::encode_f32(self, val) - } - fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError> { - T::encode_f64(self, val) - } - fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError> { - T::encode_slice(self, val) - } - fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { - T::encode_array(self, val) - } - - fn encode_char(&mut self, val: char) -> Result<(), EncodeError> { - T::encode_char(self, val) + fn encode(&self, encoder: E) -> Result<(), EncodeError> { + T::encode(self, encoder) } } diff --git a/src/enc/mod.rs b/src/enc/mod.rs index be3dd27..bc1de61 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -4,57 +4,55 @@ mod encoder; mod impl_tuples; mod impls; -use crate::error::EncodeError; +use crate::{config::Config, error::EncodeError}; pub mod write; -pub use self::encoder::Encoder; +pub use self::encoder::EncoderImpl; +use self::write::Writer; /// Any source that can encode types. This type is most notably implemented for [Encoder]. /// /// [Encoder]: ../struct.Encoder.html -pub trait Encodeable { +pub trait Encode { /// Encode a given type. - fn encode(&self, encoder: E) -> Result<(), EncodeError>; + fn encode(&self, encoder: E) -> Result<(), EncodeError>; } /// Helper trait to encode basic types into. -pub trait Encode { - /// Encode an `u8` - fn encode_u8(&mut self, val: u8) -> Result<(), EncodeError>; - /// Encode an `u16` - fn encode_u16(&mut self, val: u16) -> Result<(), EncodeError>; - /// Encode an `u32` - fn encode_u32(&mut self, val: u32) -> Result<(), EncodeError>; - /// Encode an `u64` - fn encode_u64(&mut self, val: u64) -> Result<(), EncodeError>; - /// Encode an `u128` - fn encode_u128(&mut self, val: u128) -> Result<(), EncodeError>; - /// Encode an `usize` - fn encode_usize(&mut self, val: usize) -> Result<(), EncodeError>; +pub trait Encoder: sealed::Sealed { + /// The concrete [Writer] type + type W: Writer; - /// Encode an `i8` - fn encode_i8(&mut self, val: i8) -> Result<(), EncodeError>; - /// Encode an `i16` - fn encode_i16(&mut self, val: i16) -> Result<(), EncodeError>; - /// Encode an `i32` - fn encode_i32(&mut self, val: i32) -> Result<(), EncodeError>; - /// Encode an `i64` - fn encode_i64(&mut self, val: i64) -> Result<(), EncodeError>; - /// Encode an `i128` - fn encode_i128(&mut self, val: i128) -> Result<(), EncodeError>; - /// Encode an `isize` - fn encode_isize(&mut self, val: isize) -> Result<(), EncodeError>; + /// The concrete [Config] type + type C: Config; - /// Encode an `f32` - fn encode_f32(&mut self, val: f32) -> Result<(), EncodeError>; - /// Encode an `f64` - fn encode_f64(&mut self, val: f64) -> Result<(), EncodeError>; - /// Encode a slice. Exactly `val.len()` bytes must be encoded, else an error should be thrown. - fn encode_slice(&mut self, val: &[u8]) -> Result<(), EncodeError>; - /// Encode an array. Exactly `N` bytes must be encoded, else an error should be thrown. - fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError>; + /// Returns a mutable reference to the writer + fn writer(&mut self) -> &mut Self::W; - /// Encode a single utf8 char - fn encode_char(&mut self, val: char) -> Result<(), EncodeError>; + /// Returns a reference to the config + fn config(&self) -> &Self::C; +} + +impl<'a, 'de, T> Encoder for &'a mut T +where + T: Encoder, +{ + type W = T::W; + + type C = T::C; + + fn writer(&mut self) -> &mut Self::W { + T::writer(self) + } + + fn config(&self) -> &Self::C { + T::config(self) + } +} + +pub(crate) mod sealed { + pub trait Sealed {} + + impl<'a, T> Sealed for &'a mut T where T: Sealed {} } diff --git a/src/enc/write.rs b/src/enc/write.rs index 589f79d..e5e16a2 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -4,9 +4,9 @@ use crate::error::EncodeError; -/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encodeable] +/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encode] /// -/// [Encodeable]: ../trait.Encodeable.html +/// [Encode]: ../trait.Encode.html pub trait Writer { /// Write `bytes` to the underlying writer. Exactly `bytes.len()` bytes must be written, or else an error should be returned. fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>; diff --git a/src/features/atomic.rs b/src/features/atomic.rs index dbbe2a0..2f2e85a 100644 --- a/src/features/atomic.rs +++ b/src/features/atomic.rs @@ -1,137 +1,137 @@ -use crate::{de::Decodable, enc::Encodeable}; +use crate::{de::Decode, enc::Encode}; use core::sync::atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering, }; -impl Encodeable for AtomicBool { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicBool { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicBool { - fn decode(decoder: D) -> Result { - Ok(AtomicBool::new(Decodable::decode(decoder)?)) +impl Decode for AtomicBool { + fn decode(decoder: D) -> Result { + Ok(AtomicBool::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicU8 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicU8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicU8 { - fn decode(decoder: D) -> Result { - Ok(AtomicU8::new(Decodable::decode(decoder)?)) +impl Decode for AtomicU8 { + fn decode(decoder: D) -> Result { + Ok(AtomicU8::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicU16 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicU16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicU16 { - fn decode(decoder: D) -> Result { - Ok(AtomicU16::new(Decodable::decode(decoder)?)) +impl Decode for AtomicU16 { + fn decode(decoder: D) -> Result { + Ok(AtomicU16::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicU32 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicU32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicU32 { - fn decode(decoder: D) -> Result { - Ok(AtomicU32::new(Decodable::decode(decoder)?)) +impl Decode for AtomicU32 { + fn decode(decoder: D) -> Result { + Ok(AtomicU32::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicU64 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicU64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicU64 { - fn decode(decoder: D) -> Result { - Ok(AtomicU64::new(Decodable::decode(decoder)?)) +impl Decode for AtomicU64 { + fn decode(decoder: D) -> Result { + Ok(AtomicU64::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicUsize { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicUsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicUsize { - fn decode(decoder: D) -> Result { - Ok(AtomicUsize::new(Decodable::decode(decoder)?)) +impl Decode for AtomicUsize { + fn decode(decoder: D) -> Result { + Ok(AtomicUsize::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicI8 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicI8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicI8 { - fn decode(decoder: D) -> Result { - Ok(AtomicI8::new(Decodable::decode(decoder)?)) +impl Decode for AtomicI8 { + fn decode(decoder: D) -> Result { + Ok(AtomicI8::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicI16 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicI16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicI16 { - fn decode(decoder: D) -> Result { - Ok(AtomicI16::new(Decodable::decode(decoder)?)) +impl Decode for AtomicI16 { + fn decode(decoder: D) -> Result { + Ok(AtomicI16::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicI32 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicI32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicI32 { - fn decode(decoder: D) -> Result { - Ok(AtomicI32::new(Decodable::decode(decoder)?)) +impl Decode for AtomicI32 { + fn decode(decoder: D) -> Result { + Ok(AtomicI32::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicI64 { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicI64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicI64 { - fn decode(decoder: D) -> Result { - Ok(AtomicI64::new(Decodable::decode(decoder)?)) +impl Decode for AtomicI64 { + fn decode(decoder: D) -> Result { + Ok(AtomicI64::new(Decode::decode(decoder)?)) } } -impl Encodeable for AtomicIsize { - fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { +impl Encode for AtomicIsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { self.load(Ordering::SeqCst).encode(encoder) } } -impl Decodable for AtomicIsize { - fn decode(decoder: D) -> Result { - Ok(AtomicIsize::new(Decodable::decode(decoder)?)) +impl Decode for AtomicIsize { + fn decode(decoder: D) -> Result { + Ok(AtomicIsize::new(Decode::decode(decoder)?)) } } diff --git a/src/features/derive.rs b/src/features/derive.rs index a7cb5d1..57b3a58 100644 --- a/src/features/derive.rs +++ b/src/features/derive.rs @@ -1,2 +1,2 @@ #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub use bincode_derive::{Decodable, Encodable}; +pub use bincode_derive::{Decode, Encode}; diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 6d00bfb..64aca51 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -1,7 +1,7 @@ use crate::{ config, - de::{Decodable, Decode}, - enc::{self, Encode, Encodeable}, + de::{Decode, Decoder}, + enc::{self, Encode, Encoder}, error::{DecodeError, EncodeError}, Config, }; @@ -21,27 +21,27 @@ impl enc::write::Writer for VecWriter { /// Encode the given value into a `Vec`. #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -pub fn encode_to_vec(val: E) -> Result, EncodeError> { +pub fn encode_to_vec(val: E) -> Result, EncodeError> { encode_to_vec_with_config(val, config::Default) } /// Encode the given value into a `Vec` with the given `Config`. See the [config] module for more information. #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -pub fn encode_to_vec_with_config( +pub fn encode_to_vec_with_config( val: E, config: C, ) -> Result, EncodeError> { let writer = VecWriter::default(); - let mut encoder = enc::Encoder::<_, C>::new(writer, config); + let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().inner) } -impl Decodable for BinaryHeap +impl Decode for BinaryHeap where - T: Decodable + Ord, + T: Decode + Ord, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; let mut map = BinaryHeap::with_capacity(len); for _ in 0..len { @@ -52,11 +52,11 @@ where } } -impl Encodeable for BinaryHeap +impl Encode for BinaryHeap where - T: Encodeable + Ord, + T: Encode + Ord, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for val in self.iter() { val.encode(&mut encoder)?; @@ -65,12 +65,12 @@ where } } -impl Decodable for BTreeMap +impl Decode for BTreeMap where - K: Decodable + Ord, - V: Decodable, + K: Decode + Ord, + V: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; let mut map = BTreeMap::new(); for _ in 0..len { @@ -82,12 +82,12 @@ where } } -impl Encodeable for BTreeMap +impl Encode for BTreeMap where - K: Encodeable + Ord, - V: Encodeable, + K: Encode + Ord, + V: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for (key, val) in self.iter() { key.encode(&mut encoder)?; @@ -97,11 +97,11 @@ where } } -impl Decodable for BTreeSet +impl Decode for BTreeSet where - T: Decodable + Ord, + T: Decode + Ord, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; let mut map = BTreeSet::new(); for _ in 0..len { @@ -112,11 +112,11 @@ where } } -impl Encodeable for BTreeSet +impl Encode for BTreeSet where - T: Encodeable + Ord, + T: Encode + Ord, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for item in self.iter() { item.encode(&mut encoder)?; @@ -125,11 +125,11 @@ where } } -impl Decodable for VecDeque +impl Decode for VecDeque where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; let mut map = VecDeque::with_capacity(len); for _ in 0..len { @@ -140,11 +140,11 @@ where } } -impl Encodeable for VecDeque +impl Encode for VecDeque where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for item in self.iter() { item.encode(&mut encoder)?; @@ -153,11 +153,11 @@ where } } -impl Decodable for Vec +impl Decode for Vec where - T: Decodable, + T: Decode, { - fn decode(mut decoder: D) -> Result { + fn decode(mut decoder: D) -> Result { let len = usize::decode(&mut decoder)?; let mut vec = Vec::with_capacity(len); for _ in 0..len { @@ -167,11 +167,11 @@ where } } -impl Encodeable for Vec +impl Encode for Vec where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for item in self.iter() { item.encode(&mut encoder)?; @@ -180,53 +180,53 @@ where } } -impl Decodable for String { - fn decode(decoder: D) -> Result { +impl Decode for String { + fn decode(decoder: D) -> Result { let bytes = Vec::::decode(decoder)?; String::from_utf8(bytes).map_err(|e| DecodeError::Utf8(e.utf8_error())) } } -impl Encodeable for String { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for String { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.as_bytes().encode(encoder) } } -impl Decodable for Box +impl Decode for Box where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Box::new(t)) } } -impl Encodeable for Box +impl Encode for Box where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { T::encode(self, encoder) } } -impl Decodable for Box<[T]> +impl Decode for Box<[T]> where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let vec = Vec::decode(decoder)?; Ok(vec.into_boxed_slice()) } } -impl Encodeable for Box<[T]> +impl Encode for Box<[T]> where - T: Encodeable, + T: Encode, { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.len().encode(&mut encoder)?; for item in self.iter() { item.encode(&mut encoder)?; @@ -235,61 +235,61 @@ where } } -impl<'cow, T> Decodable for Cow<'cow, T> +impl<'cow, T> Decode for Cow<'cow, T> where - T: Decodable + Clone, + T: Decode + Clone, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Cow::Owned(t)) } } -impl<'cow, T> Encodeable for Cow<'cow, T> +impl<'cow, T> Encode for Cow<'cow, T> where - T: Encodeable + Clone, + T: Encode + Clone, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.as_ref().encode(encoder) } } -impl Decodable for Rc +impl Decode for Rc where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Rc::new(t)) } } -impl Encodeable for Rc +impl Encode for Rc where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { T::encode(self, encoder) } } #[cfg(feature = "atomic")] -impl Decodable for Arc +impl Decode for Arc where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Arc::new(t)) } } #[cfg(feature = "atomic")] -impl Encodeable for Arc +impl Encode for Arc where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { T::encode(self, encoder) } } diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 5c6f245..5b9f5ca 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -1,7 +1,7 @@ use crate::{ config::{self, Config}, - de::{read::Reader, BorrowDecodable, BorrowDecode, Decodable, Decode, Decoder}, - enc::{write::Writer, Encode, Encodeable, Encoder}, + de::{read::Reader, BorrowDecode, BorrowDecoder, Decode, Decoder, DecoderImpl}, + enc::{write::Writer, Encode, Encoder, EncoderImpl}, error::{DecodeError, EncodeError}, }; use core::time::Duration; @@ -15,7 +15,7 @@ use std::{ /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn decode_from(src: &mut R) -> Result { +pub fn decode_from(src: &mut R) -> Result { decode_from_with_config(src, config::Default) } @@ -23,15 +23,15 @@ pub fn decode_from(src: &mut R) -> Result( +pub fn decode_from_with_config( src: &mut R, _config: C, ) -> Result { - let mut decoder = Decoder::<_, C>::new(src, _config); + let mut decoder = DecoderImpl::<_, C>::new(src, _config); D::decode(&mut decoder) } -impl<'storage, R: std::io::Read> Reader<'storage> for R { +impl<'storage, R: std::io::Read> Reader for R { #[inline(always)] fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { match self.read_exact(bytes) { @@ -43,7 +43,7 @@ impl<'storage, R: std::io::Read> Reader<'storage> for R { /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`. #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn encode_into_write( +pub fn encode_into_write( val: E, dst: &mut W, ) -> Result { @@ -52,7 +52,7 @@ pub fn encode_into_write( /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn encode_into_write_with_config( +pub fn encode_into_write_with_config( val: E, dst: &mut W, config: C, @@ -61,7 +61,7 @@ pub fn encode_into_write_with_config::new(writer, config); + let mut encoder = EncoderImpl::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written) } @@ -84,27 +84,27 @@ impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> { } } -impl<'a> Encodeable for &'a CStr { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl<'a> Encode for &'a CStr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.to_bytes_with_nul().encode(encoder) } } -impl<'de> BorrowDecodable<'de> for &'de CStr { - fn borrow_decode>(decoder: D) -> Result { +impl<'de> BorrowDecode<'de> for &'de CStr { + fn borrow_decode>(decoder: D) -> Result { let bytes = <&[u8]>::borrow_decode(decoder)?; CStr::from_bytes_with_nul(bytes).map_err(|e| DecodeError::CStrNulError { inner: e }) } } -impl Encodeable for CString { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for CString { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.as_bytes_with_nul().encode(encoder) } } -impl Decodable for CString { - fn decode(decoder: D) -> Result { +impl Decode for CString { + fn decode(decoder: D) -> Result { // BlockedTODO: https://github.com/rust-lang/rust/issues/73179 // use `from_vec_with_nul` instead, combined with: // let bytes = std::vec::Vec::::decode(decoder)?; @@ -117,11 +117,11 @@ impl Decodable for CString { } } -impl Encodeable for Mutex +impl Encode for Mutex where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { let t = self.lock().map_err(|_| EncodeError::LockFailed { type_name: core::any::type_name::>(), })?; @@ -129,21 +129,21 @@ where } } -impl Decodable for Mutex +impl Decode for Mutex where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(Mutex::new(t)) } } -impl Encodeable for RwLock +impl Encode for RwLock where - T: Encodeable, + T: Encode, { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { let t = self.read().map_err(|_| EncodeError::LockFailed { type_name: core::any::type_name::>(), })?; @@ -151,18 +151,18 @@ where } } -impl Decodable for RwLock +impl Decode for RwLock where - T: Decodable, + T: Decode, { - fn decode(decoder: D) -> Result { + fn decode(decoder: D) -> Result { let t = T::decode(decoder)?; Ok(RwLock::new(t)) } } -impl Encodeable for SystemTime { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for SystemTime { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { let duration = self.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| { EncodeError::InvalidSystemTime { inner: e, @@ -173,15 +173,15 @@ impl Encodeable for SystemTime { } } -impl Decodable for SystemTime { - fn decode(decoder: D) -> Result { +impl Decode for SystemTime { + fn decode(decoder: D) -> Result { let duration = Duration::decode(decoder)?; Ok(SystemTime::UNIX_EPOCH + duration) } } -impl Encodeable for &'_ Path { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for &'_ Path { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { match self.to_str() { Some(str) => str.encode(encoder), None => Err(EncodeError::Other("Path contains invalid UTF-8 characters")), @@ -189,28 +189,28 @@ impl Encodeable for &'_ Path { } } -impl<'de> BorrowDecodable<'de> for &'de Path { - fn borrow_decode>(decoder: D) -> Result { +impl<'de> BorrowDecode<'de> for &'de Path { + fn borrow_decode>(decoder: D) -> Result { let str = <&'de str>::borrow_decode(decoder)?; Ok(Path::new(str)) } } -impl Encodeable for PathBuf { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for PathBuf { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.as_path().encode(encoder) } } -impl Decodable for PathBuf { - fn decode(decoder: D) -> Result { +impl Decode for PathBuf { + fn decode(decoder: D) -> Result { let string = std::string::String::decode(decoder)?; Ok(string.into()) } } -impl Encodeable for IpAddr { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +impl Encode for IpAddr { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { match self { IpAddr::V4(v4) => { 0u32.encode(&mut encoder)?; @@ -224,8 +224,8 @@ impl Encodeable for IpAddr { } } -impl Decodable for IpAddr { - fn decode(mut decoder: D) -> Result { +impl Decode for IpAddr { + fn decode(mut decoder: D) -> Result { match u32::decode(&mut decoder)? { 0 => Ok(IpAddr::V4(Ipv4Addr::decode(decoder)?)), 1 => Ok(IpAddr::V6(Ipv6Addr::decode(decoder)?)), @@ -239,32 +239,32 @@ impl Decodable for IpAddr { } } -impl Encodeable for Ipv4Addr { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for Ipv4Addr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.octets().encode(encoder) } } -impl Decodable for Ipv4Addr { - fn decode(mut decoder: D) -> Result { - Ok(Self::from(decoder.decode_array::<4>()?)) +impl Decode for Ipv4Addr { + fn decode(decoder: D) -> Result { + Ok(Self::from(<[u8; 4]>::decode(decoder)?)) } } -impl Encodeable for Ipv6Addr { - fn encode(&self, encoder: E) -> Result<(), EncodeError> { +impl Encode for Ipv6Addr { + fn encode(&self, encoder: E) -> Result<(), EncodeError> { self.octets().encode(encoder) } } -impl Decodable for Ipv6Addr { - fn decode(mut decoder: D) -> Result { - Ok(Self::from(decoder.decode_array::<16>()?)) +impl Decode for Ipv6Addr { + fn decode(decoder: D) -> Result { + Ok(Self::from(<[u8; 16]>::decode(decoder)?)) } } -impl Encodeable for SocketAddr { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +impl Encode for SocketAddr { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { match self { SocketAddr::V4(v4) => { 0u32.encode(&mut encoder)?; @@ -278,8 +278,8 @@ impl Encodeable for SocketAddr { } } -impl Decodable for SocketAddr { - fn decode(mut decoder: D) -> Result { +impl Decode for SocketAddr { + fn decode(mut decoder: D) -> Result { match u32::decode(&mut decoder)? { 0 => Ok(SocketAddr::V4(SocketAddrV4::decode(decoder)?)), 1 => Ok(SocketAddr::V6(SocketAddrV6::decode(decoder)?)), @@ -293,30 +293,30 @@ impl Decodable for SocketAddr { } } -impl Encodeable for SocketAddrV4 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +impl Encode for SocketAddrV4 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.ip().encode(&mut encoder)?; self.port().encode(encoder) } } -impl Decodable for SocketAddrV4 { - fn decode(mut decoder: D) -> Result { +impl Decode for SocketAddrV4 { + fn decode(mut decoder: D) -> Result { let ip = Ipv4Addr::decode(&mut decoder)?; let port = u16::decode(decoder)?; Ok(Self::new(ip, port)) } } -impl Encodeable for SocketAddrV6 { - fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { +impl Encode for SocketAddrV6 { + fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { self.ip().encode(&mut encoder)?; self.port().encode(encoder) } } -impl Decodable for SocketAddrV6 { - fn decode(mut decoder: D) -> Result { +impl Decode for SocketAddrV6 { + fn decode(mut decoder: D) -> Result { let ip = Ipv6Addr::decode(&mut decoder)?; let port = u16::decode(decoder)?; Ok(Self::new(ip, port, 0, 0)) diff --git a/src/lib.rs b/src/lib.rs index 3e066a9..2461008 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,12 @@ //! //! # Features //! -//! |Name |Default?|Supported types for Encodeable/Decodeable|Enabled methods |Other| +//! |Name |Default?|Supported types for Encode/Decode|Enabled methods |Other| //! |------|--------|-----------------------------------------|-----------------------------------------------------------------|-----| //! |std | Yes ||`decode_from[_with_config]` and `encode_into_write[_with_config]`| //! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec[_with_config]`| //! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`|| -//! |derive| Yes |||Enables the `Encodeable` and `Decodeable` derive macro| +//! |derive| Yes |||Enables the `Encode` and `Decode` derive macro| //! |serde | No ||`serde_decode_from[_with_config]`, `serde_encode_into[_with_config]`|Also enables `_to_vec` when `alloc` is enabled| #![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] @@ -48,7 +48,7 @@ use config::Config; /// Will take the [Default] configuration. See the [config] module for more information. /// /// [Default]: config/struct.Default.html -pub fn encode_into_slice( +pub fn encode_into_slice( val: E, dst: &mut [u8], ) -> Result { @@ -58,13 +58,13 @@ pub fn encode_into_slice( /// Encode the given value into the given slice. Returns the amount of bytes that have been written. /// /// See the [config] module for more information on configurations. -pub fn encode_into_slice_with_config( +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::<_, C>::new(writer, config); + let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config); val.encode(&mut encoder)?; Ok(encoder.into_writer().bytes_written()) } @@ -74,7 +74,7 @@ pub fn encode_into_slice_with_config( /// Will take the [Default] configuration. See the [config] module for more information. /// /// [Default]: config/struct.Default.html -pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( +pub fn decode<'__de, D: de::BorrowDecode<'__de>>( src: &'__de [u8], ) -> Result { decode_with_config(src, config::Default) @@ -83,11 +83,11 @@ pub fn decode<'__de, D: de::BorrowDecodable<'__de>>( /// Attempt to decode a given type `D` from the given slice. /// /// See the [config] module for more information on configurations. -pub fn decode_with_config<'__de, D: de::BorrowDecodable<'__de>, C: Config>( +pub fn decode_with_config<'__de, D: de::BorrowDecode<'__de>, C: Config>( src: &'__de [u8], _config: C, ) -> Result { let reader = de::read::SliceReader::new(src); - let mut decoder = de::Decoder::<_, C>::new(reader, _config); + let mut decoder = de::DecoderImpl::<_, C>::new(reader, _config); D::borrow_decode(&mut decoder) } diff --git a/src/varint/decode_signed.rs b/src/varint/decode_signed.rs index d762344..b372d54 100644 --- a/src/varint/decode_signed.rs +++ b/src/varint/decode_signed.rs @@ -1,9 +1,6 @@ use crate::{config::Endian, de::read::Reader, error::DecodeError}; -pub fn varint_decode_i16<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_i16(read: &mut R, endian: Endian) -> Result { let n = super::varint_decode_u16(read, endian)?; Ok(if n % 2 == 0 { // positive number @@ -19,10 +16,7 @@ pub fn varint_decode_i16<'a, R: Reader<'a>>( }) } -pub fn varint_decode_i32<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_i32(read: &mut R, endian: Endian) -> Result { let n = super::varint_decode_u32(read, endian)?; Ok(if n % 2 == 0 { // positive number @@ -38,10 +32,7 @@ pub fn varint_decode_i32<'a, R: Reader<'a>>( }) } -pub fn varint_decode_i64<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_i64(read: &mut R, endian: Endian) -> Result { let n = super::varint_decode_u64(read, endian)?; Ok(if n % 2 == 0 { // positive number @@ -57,10 +48,7 @@ pub fn varint_decode_i64<'a, R: Reader<'a>>( }) } -pub fn varint_decode_i128<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_i128(read: &mut R, endian: Endian) -> Result { let n = super::varint_decode_u128(read, endian)?; Ok(if n % 2 == 0 { // positive number @@ -76,9 +64,6 @@ pub fn varint_decode_i128<'a, R: Reader<'a>>( }) } -pub fn varint_decode_isize<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_isize(read: &mut R, endian: Endian) -> Result { varint_decode_i64(read, endian).map(|v| v as isize) } diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index 9954832..7ecdb0e 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -5,10 +5,7 @@ use crate::{ error::{DecodeError, IntegerType}, }; -pub fn varint_decode_u16<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_u16(read: &mut R, endian: Endian) -> Result { let mut byte = [0u8; 1]; read.read(&mut byte)?; match byte[0] { @@ -36,10 +33,7 @@ pub fn varint_decode_u16<'a, R: Reader<'a>>( } } -pub fn varint_decode_u32<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_u32(read: &mut R, endian: Endian) -> Result { let mut byte = [0u8; 1]; read.read(&mut byte)?; match byte[0] { @@ -71,10 +65,7 @@ pub fn varint_decode_u32<'a, R: Reader<'a>>( } } -pub fn varint_decode_u64<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_u64(read: &mut R, endian: Endian) -> Result { let mut byte = [0u8; 1]; read.read(&mut byte)?; match byte[0] { @@ -110,10 +101,7 @@ pub fn varint_decode_u64<'a, R: Reader<'a>>( } } -pub fn varint_decode_usize<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_usize(read: &mut R, endian: Endian) -> Result { let mut byte = [0u8; 1]; read.read(&mut byte)?; match byte[0] { @@ -149,10 +137,7 @@ pub fn varint_decode_usize<'a, R: Reader<'a>>( } } -pub fn varint_decode_u128<'a, R: Reader<'a>>( - read: &mut R, - endian: Endian, -) -> Result { +pub fn varint_decode_u128(read: &mut R, endian: Endian) -> Result { let mut byte = [0u8; 1]; read.read(&mut byte)?; match byte[0] { diff --git a/tests/alloc.rs b/tests/alloc.rs index 09c7edc..e3af915 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -15,8 +15,8 @@ struct Foo { pub b: u32, } -impl bincode::enc::Encodeable for Foo { - fn encode( +impl bincode::enc::Encode for Foo { + fn encode( &self, mut encoder: E, ) -> Result<(), bincode::error::EncodeError> { @@ -26,11 +26,13 @@ impl bincode::enc::Encodeable for Foo { } } -impl bincode::de::Decodable for Foo { - fn decode(mut decoder: D) -> Result { +impl bincode::de::Decode for Foo { + fn decode( + mut decoder: D, + ) -> Result { Ok(Self { - a: bincode::de::Decodable::decode(&mut decoder)?, - b: bincode::de::Decodable::decode(&mut decoder)?, + a: bincode::de::Decode::decode(&mut decoder)?, + b: bincode::de::Decode::decode(&mut decoder)?, }) } } diff --git a/tests/derive.rs b/tests/derive.rs index 3738cf0..419b120 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,39 +1,39 @@ #![cfg(feature = "derive")] -use bincode::{de::Decodable, enc::Encodeable}; +use bincode::{de::Decode, enc::Encode}; -#[derive(bincode::Encodable, PartialEq, Debug)] -pub(crate) struct Test { +#[derive(bincode::Encode, PartialEq, Debug)] +pub(crate) struct Test { a: T, b: u32, c: u8, } -#[derive(bincode::Decodable, PartialEq, Debug, Eq)] -pub struct Test2 { +#[derive(bincode::Decode, PartialEq, Debug, Eq)] +pub struct Test2 { a: T, b: u32, c: u32, } -#[derive(bincode::Decodable, PartialEq, Debug, Eq)] +#[derive(bincode::Decode, PartialEq, Debug, Eq)] pub struct Test3<'a> { a: &'a str, b: u32, c: u32, } -#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)] pub struct TestTupleStruct(u32, u32, u32); -#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)] pub enum TestEnum { Foo, Bar { name: u32 }, Baz(u32, u32, u32), } -#[derive(bincode::Encodable, bincode::Decodable, PartialEq, Debug, Eq)] +#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)] pub enum TestEnum2<'a> { Foo, Bar { name: &'a str }, @@ -41,7 +41,7 @@ pub enum TestEnum2<'a> { } #[test] -fn test_encodable() { +fn test_encode() { let start = Test { a: 5i32, b: 10u32, @@ -55,7 +55,7 @@ fn test_encodable() { #[cfg(feature = "std")] #[test] -fn test_decodable() { +fn test_decode() { let start = Test2 { a: 5u32, b: 10u32, @@ -67,7 +67,7 @@ fn test_decodable() { } #[test] -fn test_encodable_tuple() { +fn test_encode_tuple() { let start = TestTupleStruct(5, 10, 1024); let mut slice = [0u8; 1024]; let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); @@ -76,7 +76,7 @@ fn test_encodable_tuple() { } #[test] -fn test_decodable_tuple() { +fn test_decode_tuple() { let start = TestTupleStruct(5, 10, 1024); let mut slice = [5, 10, 251, 0, 4]; let result: TestTupleStruct = bincode::decode(&mut slice).unwrap(); @@ -84,7 +84,7 @@ fn test_decodable_tuple() { } #[test] -fn test_encodable_enum_struct_variant() { +fn test_encode_enum_struct_variant() { let start = TestEnum::Bar { name: 5u32 }; let mut slice = [0u8; 1024]; let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); @@ -93,7 +93,7 @@ fn test_encodable_enum_struct_variant() { } #[test] -fn test_decodable_enum_struct_variant() { +fn test_decode_enum_struct_variant() { let start = TestEnum::Bar { name: 5u32 }; let mut slice = [1, 5]; let result: TestEnum = bincode::decode(&mut slice).unwrap(); @@ -101,7 +101,7 @@ fn test_decodable_enum_struct_variant() { } #[test] -fn test_encodable_enum_tuple_variant() { +fn test_encode_enum_tuple_variant() { let start = TestEnum::Baz(5, 10, 1024); let mut slice = [0u8; 1024]; let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); @@ -110,7 +110,7 @@ fn test_encodable_enum_tuple_variant() { } #[test] -fn test_decodable_enum_unit_variant() { +fn test_decode_enum_unit_variant() { let start = TestEnum::Foo; let mut slice = [0]; let result: TestEnum = bincode::decode(&mut slice).unwrap(); @@ -118,7 +118,7 @@ fn test_decodable_enum_unit_variant() { } #[test] -fn test_encodable_enum_unit_variant() { +fn test_encode_enum_unit_variant() { let start = TestEnum::Foo; let mut slice = [0u8; 1024]; let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); @@ -127,7 +127,7 @@ fn test_encodable_enum_unit_variant() { } #[test] -fn test_decodable_enum_tuple_variant() { +fn test_decode_enum_tuple_variant() { let start = TestEnum::Baz(5, 10, 1024); let mut slice = [2, 5, 10, 251, 0, 4]; let result: TestEnum = bincode::decode(&mut slice).unwrap(); diff --git a/tests/serde.rs b/tests/serde.rs index 7cb083b..c0dedd9 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -2,7 +2,7 @@ use serde_derive::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, bincode::Encodable, bincode::Decodable)] +#[derive(Serialize, Deserialize, bincode::Encode, bincode::Decode)] pub struct SerdeRoundtrip { pub a: u32, #[serde(skip)] diff --git a/tests/std.rs b/tests/std.rs index b804656..0781bec 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -18,8 +18,8 @@ struct Foo { pub b: u32, } -impl bincode::enc::Encodeable for Foo { - fn encode( +impl bincode::enc::Encode for Foo { + fn encode( &self, mut encoder: E, ) -> Result<(), bincode::error::EncodeError> { @@ -29,11 +29,13 @@ impl bincode::enc::Encodeable for Foo { } } -impl bincode::de::Decodable for Foo { - fn decode(mut decoder: D) -> Result { +impl bincode::de::Decode for Foo { + fn decode( + mut decoder: D, + ) -> Result { Ok(Self { - a: bincode::de::Decodable::decode(&mut decoder)?, - b: bincode::de::Decodable::decode(&mut decoder)?, + a: bincode::de::Decode::decode(&mut decoder)?, + b: bincode::de::Decode::decode(&mut decoder)?, }) } } diff --git a/tests/utils.rs b/tests/utils.rs index 3aa4e79..383377b 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; fn the_same_with_config(element: &V, config: C, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, + V: bincode::enc::Encode + bincode::de::Decode + Debug + 'static, C: Config, CMP: Fn(&V, &V) -> bool, { @@ -28,7 +28,7 @@ where pub fn the_same_with_comparer(element: V, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, + V: bincode::enc::Encode + bincode::de::Decode + Debug + 'static, CMP: Fn(&V, &V) -> bool, { // A matrix of each different config option possible @@ -101,7 +101,7 @@ where #[allow(dead_code)] // This is not used in every test pub fn the_same(element: V) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + 'static, + V: bincode::enc::Encode + bincode::de::Decode + PartialEq + Debug + 'static, { the_same_with_comparer(element, |a, b| a == b); } From 4807ea6be2f1c19f42981d04c0481ee6ffc2c3bc Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 17 Oct 2021 16:43:18 +0200 Subject: [PATCH 60/80] Added warning on unused lifetimes, fixed warnings --- .github/workflows/rust.yml | 2 +- src/de/decoder.rs | 4 ++-- src/de/mod.rs | 2 +- src/enc/mod.rs | 2 +- src/features/impl_std.rs | 2 +- src/lib.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8765a33..c8845b2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -134,7 +134,7 @@ "uses": "actions-rs/cargo@v1", "with": { "command": "clippy", - "args": "-- -D warnings" + "args": "--all-features -- -D warnings" }, "name": "Run `cargo clippy`" } diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 7205f31..0955e19 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -27,7 +27,7 @@ pub struct DecoderImpl { config: C, } -impl<'de, R: Reader, C: Config> DecoderImpl { +impl DecoderImpl { /// Construct a new Decoder pub fn new(reader: R, config: C) -> DecoderImpl { DecoderImpl { reader, config } @@ -44,7 +44,7 @@ impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecoder<'de> for &'a mut De } } -impl<'a, 'de, R: Reader, C: Config> Decoder for &'a mut DecoderImpl { +impl<'a, R: Reader, C: Config> Decoder for &'a mut DecoderImpl { type R = R; type C = C; diff --git a/src/de/mod.rs b/src/de/mod.rs index df709e4..cce0d0f 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -60,7 +60,7 @@ pub trait BorrowDecoder<'de>: Decoder { fn borrow_reader(&mut self) -> &mut Self::BR; } -impl<'a, 'de, T> Decoder for &'a mut T +impl<'a, T> Decoder for &'a mut T where T: Decoder, { diff --git a/src/enc/mod.rs b/src/enc/mod.rs index bc1de61..e859ffb 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -34,7 +34,7 @@ pub trait Encoder: sealed::Sealed { fn config(&self) -> &Self::C; } -impl<'a, 'de, T> Encoder for &'a mut T +impl<'a, T> Encoder for &'a mut T where T: Encoder, { diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 5b9f5ca..ad58835 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -31,7 +31,7 @@ pub fn decode_from_with_config( D::decode(&mut decoder) } -impl<'storage, R: std::io::Read> Reader for R { +impl Reader for R { #[inline(always)] fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { match self.read_exact(bytes) { diff --git a/src/lib.rs b/src/lib.rs index 2461008..20ccf30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![warn(missing_docs)] +#![warn(missing_docs, unused_lifetimes)] #![cfg_attr(docsrs, feature(doc_cfg))] //! Bincode is a crate for encoding and decoding using a tiny binary From 02a9b2cb7180a35fc46f168cf0ae2866e8785d70 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 17 Oct 2021 17:21:20 +0200 Subject: [PATCH 61/80] Made the test stage throw an error on warnings --- .github/workflows/rust.yml | 5 ++++- src/features/impl_alloc.rs | 4 +++- tests/alloc.rs | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c8845b2..81ce5b6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -100,7 +100,10 @@ }, { "run": "cargo test-all-features", - "name": "Run `cargo test` on all features" + "name": "Run `cargo test` on all features", + "env": { + "RUSTFLAGS": "-D warnings" + } } ] }, diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 64aca51..d146b4f 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -5,7 +5,9 @@ use crate::{ error::{DecodeError, EncodeError}, Config, }; -use alloc::{borrow::Cow, boxed::Box, collections::*, rc::Rc, string::String, sync::Arc, vec::Vec}; +#[cfg(feature = "atomic")] +use alloc::sync::Arc; +use alloc::{borrow::Cow, boxed::Box, collections::*, rc::Rc, string::String, vec::Vec}; #[derive(Default)] struct VecWriter { diff --git a/tests/alloc.rs b/tests/alloc.rs index e3af915..b8d17cf 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -7,6 +7,7 @@ mod utils; use alloc::borrow::Cow; use alloc::collections::*; use alloc::rc::Rc; +#[cfg(feature = "atomic")] use alloc::sync::Arc; use utils::{the_same, the_same_with_comparer}; From 2fd2a8d8e23d24becfbf9827428e26e35fdde260 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 17 Oct 2021 17:21:34 +0200 Subject: [PATCH 62/80] Made the varint decode_signed module report the correct errors --- src/error.rs | 34 ++++++++++++++++++++++++++++++++++ src/varint/decode_signed.rs | 29 +++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/error.rs b/src/error.rs index 2b037db..e1aec77 100644 --- a/src/error.rs +++ b/src/error.rs @@ -105,6 +105,23 @@ pub enum DecodeError { }, } +impl DecodeError { + /// If the current error is `InvalidIntegerType`, change the `expected` and + /// `found` values from `Ux` to `Ix`. This is needed to have correct error + /// reporting in src/varint/decode_signed.rs since this calls + /// src/varint/decode_unsigned.rs and needs to correct the `expected` and + /// `found` types. + pub(crate) fn change_integer_type_to_signed(self) -> DecodeError { + match self { + Self::InvalidIntegerType { expected, found } => Self::InvalidIntegerType { + expected: expected.into_signed(), + found: found.into_signed(), + }, + other => other, + } + } +} + /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. #[non_exhaustive] #[derive(Debug)] @@ -124,3 +141,20 @@ pub enum IntegerType { I128, Isize, } + +impl IntegerType { + /// Change the `Ux` value to the associated `Ix` value. + /// Returns the old value if `self` is already `Ix`. + pub(crate) fn into_signed(self) -> Self { + match self { + Self::U8 => Self::I8, + Self::U16 => Self::I16, + Self::U32 => Self::I32, + Self::U64 => Self::I64, + Self::U128 => Self::I128, + Self::Usize => Self::Isize, + + other => other, + } + } +} diff --git a/src/varint/decode_signed.rs b/src/varint/decode_signed.rs index b372d54..d670493 100644 --- a/src/varint/decode_signed.rs +++ b/src/varint/decode_signed.rs @@ -1,7 +1,12 @@ -use crate::{config::Endian, de::read::Reader, error::DecodeError}; +use crate::{ + config::Endian, + de::read::Reader, + error::{DecodeError, IntegerType}, +}; pub fn varint_decode_i16(read: &mut R, endian: Endian) -> Result { - let n = super::varint_decode_u16(read, endian)?; + let n = super::varint_decode_u16(read, endian) + .map_err(DecodeError::change_integer_type_to_signed)?; Ok(if n % 2 == 0 { // positive number (n / 2) as _ @@ -17,7 +22,8 @@ pub fn varint_decode_i16(read: &mut R, endian: Endian) -> Result(read: &mut R, endian: Endian) -> Result { - let n = super::varint_decode_u32(read, endian)?; + let n = super::varint_decode_u32(read, endian) + .map_err(DecodeError::change_integer_type_to_signed)?; Ok(if n % 2 == 0 { // positive number (n / 2) as _ @@ -33,7 +39,8 @@ pub fn varint_decode_i32(read: &mut R, endian: Endian) -> Result(read: &mut R, endian: Endian) -> Result { - let n = super::varint_decode_u64(read, endian)?; + let n = super::varint_decode_u64(read, endian) + .map_err(DecodeError::change_integer_type_to_signed)?; Ok(if n % 2 == 0 { // positive number (n / 2) as _ @@ -49,7 +56,8 @@ pub fn varint_decode_i64(read: &mut R, endian: Endian) -> Result(read: &mut R, endian: Endian) -> Result { - let n = super::varint_decode_u128(read, endian)?; + let n = super::varint_decode_u128(read, endian) + .map_err(DecodeError::change_integer_type_to_signed)?; Ok(if n % 2 == 0 { // positive number (n / 2) as _ @@ -65,5 +73,14 @@ pub fn varint_decode_i128(read: &mut R, endian: Endian) -> Result(read: &mut R, endian: Endian) -> Result { - varint_decode_i64(read, endian).map(|v| v as isize) + match varint_decode_i64(read, endian) { + Ok(val) => Ok(val as isize), + Err(DecodeError::InvalidIntegerType { found, .. }) => { + Err(DecodeError::InvalidIntegerType { + expected: IntegerType::Isize, + found: found.into_signed(), + }) + } + Err(e) => Err(e), + } } From 684f2562b1fd2fd8ca76f0d26fcfdcbb7413b474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Sun, 17 Oct 2021 21:07:31 +0200 Subject: [PATCH 63/80] Config rewrite (#412) Rewrite the config system to be slightly more friendly to adding new options --- src/config.rs | 185 ++++++++++++++++++------------------- src/de/decoder.rs | 2 +- src/de/impls.rs | 5 +- src/enc/encoder.rs | 2 +- src/enc/impls.rs | 5 +- src/features/impl_alloc.rs | 2 +- src/features/impl_std.rs | 4 +- src/lib.rs | 4 +- tests/std.rs | 2 +- tests/utils.rs | 16 ++-- 10 files changed, 116 insertions(+), 111 deletions(-) diff --git a/src/config.rs b/src/config.rs index f575ee7..4cd83c6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,11 +2,11 @@ //! //! *Important* make sure you use the same config for encoding and decoding, or else bincode will not work properly. //! -//! To use a config, first create a type of [struct@Default]. This type will implement trait [Config] for further configuration. +//! To use a config, first create a type of [Configuration]. This type will implement trait [Config] for use with bincode. //! //! ``` -//! use bincode::config::{Config, Default}; -//! let config = Default +//! use bincode::config::{Config, Configuration}; +//! let config = Configuration::standard() //! // pick one of: //! .with_big_endian() //! .with_little_endian() @@ -23,7 +23,8 @@ pub(crate) use self::internal::*; use core::marker::PhantomData; -/// The config trait that is implemented by all types returned by this function, as well as [struct@Default]. +/// The Configuration struct is used to build bincode configurations. The [Config] trait is implemented +/// by this struct when a valid configuration has been constructed. /// /// The following methods are mutually exclusive and will overwrite each other. The last call to one of these methods determines the behavior of the configuration: /// @@ -38,15 +39,48 @@ use core::marker::PhantomData; /// [with_variable_int_encoding]: #method.with_variable_int_encoding /// [skip_fixed_array_length]: #method.skip_fixed_array_length /// [write_fixed_array_length]: #method.write_fixed_array_length -pub trait Config: InternalConfig { +#[derive(Copy, Clone)] +pub struct Configuration { + _e: PhantomData, + _i: PhantomData, + _a: PhantomData, +} + +impl Configuration { + /// The default config. By default this will be: + /// - Little endian + /// - Variable int encoding + /// - Skip fixed array length + pub fn standard() -> Self { + Self::generate() + } + + /// Creates the "legacy" default config. This is the default config that was present in bincode 1.0 + /// - Little endian + /// - Fixed int length encoding + /// - Write array lengths + pub fn legacy() -> Configuration { + Self::generate() + } +} + +impl Configuration { + fn generate<_E, _I, _A>() -> Configuration<_E, _I, _A> { + Configuration { + _e: PhantomData, + _i: PhantomData, + _a: PhantomData, + } + } + /// Makes bincode encode all integer types in big endian. - fn with_big_endian(self) -> BigEndian { - BigEndian { _pd: PhantomData } + pub fn with_big_endian(self) -> Configuration { + Self::generate() } /// Makes bincode encode all integer types in little endian. - fn with_little_endian(self) -> LittleEndian { - LittleEndian { _pd: PhantomData } + pub fn with_little_endian(self) -> Configuration { + Self::generate() } /// Makes bincode encode all integer types with a variable integer encoding. @@ -91,8 +125,8 @@ pub trait Config: InternalConfig { /// /// Note that u256 and the like are unsupported by this format; if and when they are added to the /// language, they may be supported via the extension point given by the 255 byte. - fn with_variable_int_encoding(self) -> Varint { - Varint { _pd: PhantomData } + pub fn with_variable_int_encoding(self) -> Configuration { + Self::generate() } /// Fixed-size integer encoding. @@ -100,129 +134,89 @@ pub trait Config: InternalConfig { /// * Fixed size integers are encoded directly /// * Enum discriminants are encoded as u32 /// * Lengths and usize are encoded as u64 - fn with_fixed_int_encoding(self) -> Fixint { - Fixint { _pd: PhantomData } + pub fn with_fixed_int_encoding(self) -> Configuration { + Self::generate() } /// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array - fn skip_fixed_array_length(self) -> SkipFixedArrayLength { - SkipFixedArrayLength { _pd: PhantomData } + pub fn skip_fixed_array_length(self) -> Configuration { + Self::generate() } /// Write the length of fixed size arrays (`[u8; N]`) before writing the array - fn write_fixed_array_length(self) -> WriteFixedArrayLength { - WriteFixedArrayLength { _pd: PhantomData } + pub fn write_fixed_array_length(self) -> Configuration { + Self::generate() } } -impl Config for T {} +/// Indicates a type is valid for controlling the bincode configuration +pub trait Config: + InternalEndianConfig + InternalArrayLengthConfig + InternalIntEncodingConfig + Copy + Clone +{ +} -/// The default config. By default this will be: -/// - Little endian -/// - Variable int encoding -/// - Skip fixed array length -#[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; - const SKIP_FIXED_ARRAY_LENGTH: bool = true; +impl Config for T where + T: InternalEndianConfig + InternalArrayLengthConfig + InternalIntEncodingConfig + Copy + Clone +{ } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct BigEndian { - _pd: PhantomData, -} +pub struct BigEndian {} -impl InternalConfig for BigEndian { +impl InternalEndianConfig 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; - const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct LittleEndian { - _pd: PhantomData, -} +pub struct LittleEndian {} -impl InternalConfig for LittleEndian { +impl InternalEndianConfig 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; - const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct Fixint { - _pd: PhantomData, -} +pub struct Fixint {} -impl InternalConfig for Fixint { - const ENDIAN: Endian = C::ENDIAN; +impl InternalIntEncodingConfig for Fixint { const INT_ENCODING: IntEncoding = IntEncoding::Fixed; - const LIMIT: Option = C::LIMIT; - const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; - const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct Varint { - _pd: PhantomData, -} +pub struct Varint {} -impl InternalConfig for Varint { - const ENDIAN: Endian = C::ENDIAN; +impl InternalIntEncodingConfig for Varint { const INT_ENCODING: IntEncoding = IntEncoding::Variable; - const LIMIT: Option = C::LIMIT; - const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; - const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct SkipFixedArrayLength { - _pd: PhantomData, -} +pub struct SkipFixedArrayLength {} -impl InternalConfig for SkipFixedArrayLength { - const ENDIAN: Endian = C::ENDIAN; - const INT_ENCODING: IntEncoding = C::INT_ENCODING; - const LIMIT: Option = C::LIMIT; - const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +impl InternalArrayLengthConfig for SkipFixedArrayLength { const SKIP_FIXED_ARRAY_LENGTH: bool = true; } #[doc(hidden)] #[derive(Copy, Clone)] -pub struct WriteFixedArrayLength { - _pd: PhantomData, -} +pub struct WriteFixedArrayLength {} -impl InternalConfig for WriteFixedArrayLength { - const ENDIAN: Endian = C::ENDIAN; - const INT_ENCODING: IntEncoding = C::INT_ENCODING; - const LIMIT: Option = C::LIMIT; - const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; +impl InternalArrayLengthConfig for WriteFixedArrayLength { const SKIP_FIXED_ARRAY_LENGTH: bool = false; } mod internal { - pub trait InternalConfig: Copy + Clone { + use super::Configuration; + + pub trait InternalEndianConfig { const ENDIAN: Endian; - const INT_ENCODING: IntEncoding; - const LIMIT: Option; - const ALLOW_TRAILING: bool; - const SKIP_FIXED_ARRAY_LENGTH: bool; + } + + impl InternalEndianConfig for Configuration { + const ENDIAN: Endian = E::ENDIAN; } #[derive(PartialEq, Eq)] @@ -231,20 +225,25 @@ mod internal { Big, } + pub trait InternalIntEncodingConfig { + const INT_ENCODING: IntEncoding; + } + + impl InternalIntEncodingConfig for Configuration { + const INT_ENCODING: IntEncoding = I::INT_ENCODING; + } + #[derive(PartialEq, Eq)] pub enum IntEncoding { Fixed, Variable, } - 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; - const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; - const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; + pub trait InternalArrayLengthConfig { + const SKIP_FIXED_ARRAY_LENGTH: bool; + } + + impl InternalArrayLengthConfig for Configuration { + const SKIP_FIXED_ARRAY_LENGTH: bool = A::SKIP_FIXED_ARRAY_LENGTH; } } diff --git a/src/de/decoder.rs b/src/de/decoder.rs index 0955e19..fddc399 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -18,7 +18,7 @@ use crate::config::Config; /// # let some_reader = bincode::de::read::SliceReader::new(slice); /// use bincode::de::{DecoderImpl, Decode}; /// use bincode::config; -/// let mut decoder = DecoderImpl::new(some_reader, config::Default); +/// let mut decoder = DecoderImpl::new(some_reader, config::Configuration::standard()); /// // this u32 can be any Decode /// let value = u32::decode(&mut decoder).unwrap(); /// ``` diff --git a/src/de/impls.rs b/src/de/impls.rs index 39fbaa3..3dccb96 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -3,7 +3,10 @@ use super::{ BorrowDecode, BorrowDecoder, Decode, Decoder, }; use crate::{ - config::{Endian, IntEncoding, InternalConfig}, + config::{ + Endian, IntEncoding, InternalArrayLengthConfig, InternalEndianConfig, + InternalIntEncodingConfig, + }, error::{DecodeError, IntegerType}, }; use core::{ diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 135347f..8525b83 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -14,7 +14,7 @@ use crate::config::Config; /// ``` /// # use bincode::enc::{write::SliceWriter, EncoderImpl, Encode}; /// # use bincode::config::{self, Config}; -/// # let config = config::Default.with_fixed_int_encoding().with_big_endian(); +/// # let config = config::Configuration::standard().with_fixed_int_encoding().with_big_endian(); /// let slice: &mut [u8] = &mut [0, 0, 0, 0]; /// let mut encoder = EncoderImpl::new(SliceWriter::new(slice), config); /// // this u32 can be any Encodable diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 4a567a7..82645df 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -1,6 +1,9 @@ use super::{write::Writer, Encode, Encoder}; use crate::{ - config::{Endian, IntEncoding, InternalConfig}, + config::{ + Endian, IntEncoding, InternalArrayLengthConfig, InternalEndianConfig, + InternalIntEncodingConfig, + }, error::EncodeError, }; use core::{ diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index d146b4f..fd701c1 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -24,7 +24,7 @@ impl enc::write::Writer for VecWriter { /// Encode the given value into a `Vec`. #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn encode_to_vec(val: E) -> Result, EncodeError> { - encode_to_vec_with_config(val, config::Default) + encode_to_vec_with_config(val, config::Configuration::standard()) } /// Encode the given value into a `Vec` with the given `Config`. See the [config] module for more information. diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index ad58835..2b6c59b 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -16,7 +16,7 @@ use std::{ /// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn decode_from(src: &mut R) -> Result { - decode_from_with_config(src, config::Default) + decode_from_with_config(src, config::Configuration::standard()) } /// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. @@ -47,7 +47,7 @@ pub fn encode_into_write( val: E, dst: &mut W, ) -> Result { - encode_into_write_with_config(val, dst, config::Default) + encode_into_write_with_config(val, dst, config::Configuration::standard()) } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. diff --git a/src/lib.rs b/src/lib.rs index 20ccf30..4c6f837 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ pub fn encode_into_slice( val: E, dst: &mut [u8], ) -> Result { - encode_into_slice_with_config(val, dst, config::Default) + encode_into_slice_with_config(val, dst, config::Configuration::standard()) } /// Encode the given value into the given slice. Returns the amount of bytes that have been written. @@ -77,7 +77,7 @@ pub fn encode_into_slice_with_config( pub fn decode<'__de, D: de::BorrowDecode<'__de>>( src: &'__de [u8], ) -> Result { - decode_with_config(src, config::Default) + decode_with_config(src, config::Configuration::standard()) } /// Attempt to decode a given type `D` from the given slice. diff --git a/tests/std.rs b/tests/std.rs index 0781bec..09eff68 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -91,7 +91,7 @@ fn test_std_commons() { }); // Borrowed values - let config = bincode::config::Default; + let config = bincode::config::Configuration::standard(); let mut buffer = [0u8; 1024]; // &CStr diff --git a/tests/utils.rs b/tests/utils.rs index 383377b..5f4f280 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -34,7 +34,7 @@ where // A matrix of each different config option possible the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_little_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), @@ -42,7 +42,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_big_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), @@ -50,7 +50,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_little_endian() .with_variable_int_encoding() .skip_fixed_array_length(), @@ -58,7 +58,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_big_endian() .with_variable_int_encoding() .skip_fixed_array_length(), @@ -66,7 +66,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_little_endian() .with_fixed_int_encoding() .write_fixed_array_length(), @@ -74,7 +74,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_big_endian() .with_fixed_int_encoding() .write_fixed_array_length(), @@ -82,7 +82,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_little_endian() .with_variable_int_encoding() .write_fixed_array_length(), @@ -90,7 +90,7 @@ where ); the_same_with_config( &element, - config::Default + config::Configuration::standard() .with_big_endian() .with_variable_int_encoding() .write_fixed_array_length(), From 4b25114c59237a2a3a7956635440231d1766609c Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Mon, 18 Oct 2021 10:18:47 +0200 Subject: [PATCH 64/80] Processed some of the feedback --- Cargo.toml | 2 +- derive/src/error.rs | 32 +++++++---------------- derive/src/generate/generate_fn.rs | 37 +++++++++++++++++++++++---- derive/src/generate/stream_builder.rs | 17 +++++++++++- src/config.rs | 2 +- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e0b7388..595c444 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ derive = ["bincode_derive"] bincode_derive = { path = "derive", version = "2.0.0-dev", optional = true } serde = { version = "1.0.130", optional = true } -# Used for derive tests +# Used for tests [dev-dependencies] serde_derive = "1.0.130" serde_json = "1.0.68" diff --git a/derive/src/error.rs b/derive/src/error.rs index 724c372..b44dcda 100644 --- a/derive/src/error.rs +++ b/derive/src/error.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{generate::StreamBuilder, prelude::*}; use std::fmt; #[derive(Debug)] @@ -44,27 +44,13 @@ impl Error { pub fn throw_with_span(self, span: Span) -> TokenStream { // compile_error!($message) - vec![ - TokenTree::Ident(Ident::new("compile_error", span)), - TokenTree::Punct({ - let mut punct = Punct::new('!', Spacing::Alone); - punct.set_span(span); - punct - }), - TokenTree::Group({ - let mut group = Group::new(Delimiter::Brace, { - TokenTree::Literal({ - let mut string = Literal::string(&self.to_string()); - string.set_span(span); - string - }) - .into() - }); - group.set_span(span); - group - }), - ] - .into_iter() - .collect() + let mut builder = StreamBuilder::new(); + builder.ident_str("compile_error"); + builder.punct('!'); + builder.group(Delimiter::Brace, |b| { + b.lit_str(self.to_string()); + }); + builder.set_span_on_all_tokens(span); + builder.stream } } diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs index 53428ca..b42b658 100644 --- a/derive/src/generate/generate_fn.rs +++ b/derive/src/generate/generate_fn.rs @@ -1,7 +1,9 @@ use super::{ImplFor, StreamBuilder}; use crate::prelude::Delimiter; + +/// A builder for functions. pub struct FnBuilder<'a, 'b> { - generate: &'b mut ImplFor<'a>, + generate: Option<&'b mut ImplFor<'a>>, name: String, lifetime_and_generics: Vec<(String, Vec)>, @@ -13,7 +15,7 @@ pub struct FnBuilder<'a, 'b> { impl<'a, 'b> FnBuilder<'a, 'b> { pub(super) fn new(generate: &'b mut ImplFor<'a>, name: impl Into) -> Self { Self { - generate, + generate: Some(generate), name: name.into(), lifetime_and_generics: Vec::new(), self_arg: FnSelfArg::None, @@ -22,6 +24,30 @@ impl<'a, 'b> FnBuilder<'a, 'b> { } } + #[cfg(test)] + #[doc(hidden)] + #[allow(unused)] + pub fn for_test() -> Self { + Self { + generate: None, + name: String::new(), + lifetime_and_generics: Vec::new(), + self_arg: FnSelfArg::None, + args: Vec::new(), + return_type: None, + } + } + + /// Add a generic parameter. Keep in mind that this is *not* a valid lifetime. + /// + /// `dependencies` are the optional dependencies of the parameter. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// builder + /// .with_generic("D", None) // fn Foo() + /// .with_generic("E", &["Encodable"]); // fn foo(); + /// ``` pub fn with_generic(mut self, name: T, dependencies: U) -> Self where T: Into, @@ -52,7 +78,7 @@ impl<'a, 'b> FnBuilder<'a, 'b> { pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) { let FnBuilder { - generate, + mut generate, name, lifetime_and_generics, self_arg, @@ -108,9 +134,10 @@ impl<'a, 'b> FnBuilder<'a, 'b> { builder.push_parsed(&return_type); } - generate.group.append(builder); + let generator = generate.take().unwrap(); - generate.group.group(Delimiter::Brace, body_builder); + generator.group.append(builder); + generator.group.group(Delimiter::Brace, body_builder); } } diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs index a1a0854..8331286 100644 --- a/derive/src/generate/stream_builder.rs +++ b/derive/src/generate/stream_builder.rs @@ -6,7 +6,7 @@ use std::str::FromStr; #[must_use] #[derive(Default)] pub struct StreamBuilder { - pub(super) stream: TokenStream, + pub(crate) stream: TokenStream, } impl StreamBuilder { @@ -83,6 +83,11 @@ impl StreamBuilder { ]); } + pub fn lit_str(&mut self, str: impl AsRef) { + self.stream + .extend([TokenTree::Literal(Literal::string(str.as_ref()))]); + } + pub fn lit_u32(&mut self, val: u32) { self.stream .extend([TokenTree::Literal(Literal::u32_unsuffixed(val))]); @@ -92,4 +97,14 @@ impl StreamBuilder { self.stream .extend([TokenTree::Literal(Literal::usize_unsuffixed(val))]); } + + pub fn set_span_on_all_tokens(&mut self, span: Span) { + self.stream = std::mem::take(&mut self.stream) + .into_iter() + .map(|mut token| { + token.set_span(span); + token + }) + .collect(); + } } diff --git a/src/config.rs b/src/config.rs index 4cd83c6..dd2d3b9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -47,7 +47,7 @@ pub struct Configuration } impl Configuration { - /// The default config. By default this will be: + /// The default config for bincode 2.0. By default this will be: /// - Little endian /// - Variable int encoding /// - Skip fixed array length From baad206c6cbd752cd54d7c608c35a1c5bb701cec Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 19 Oct 2021 10:07:04 +0200 Subject: [PATCH 65/80] Added more documentation to derive/src/generate --- derive/src/generate/generate_fn.rs | 67 +++++++++++++++++++++------ derive/src/generate/generator.rs | 7 ++- derive/src/generate/impl_for.rs | 1 + derive/src/generate/stream_builder.rs | 41 ++++++++++++++++ 4 files changed, 100 insertions(+), 16 deletions(-) diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs index b42b658..ff44ede 100644 --- a/derive/src/generate/generate_fn.rs +++ b/derive/src/generate/generate_fn.rs @@ -24,21 +24,7 @@ impl<'a, 'b> FnBuilder<'a, 'b> { } } - #[cfg(test)] - #[doc(hidden)] - #[allow(unused)] - pub fn for_test() -> Self { - Self { - generate: None, - name: String::new(), - lifetime_and_generics: Vec::new(), - self_arg: FnSelfArg::None, - args: Vec::new(), - return_type: None, - } - } - - /// Add a generic parameter. Keep in mind that this is *not* a valid lifetime. + /// Add a generic parameter. Keep in mind that will *not* work for lifetimes. /// /// `dependencies` are the optional dependencies of the parameter. /// @@ -61,21 +47,53 @@ impl<'a, 'b> FnBuilder<'a, 'b> { self } + /// Set the value for `self`. See [FnSelfArg] for more information. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // static function by default + /// builder.with_self_arg(FnSelfArg::RefSelf); // fn foo(&self) + /// ``` pub fn with_self_arg(mut self, self_arg: FnSelfArg) -> Self { self.self_arg = self_arg; self } + /// Add an argument with a `name` and a `ty`. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo(); + /// builder + /// .with_arg("a", "u32") // fn foo(a: u32) + /// .with_arg("b", "u32"); // fn foo(a: u32, b: u32) + /// ``` pub fn with_arg(mut self, name: impl Into, ty: impl Into) -> Self { self.args.push((name.into(), ty.into())); self } + /// Set the return type for the function. By default the function will have no return type. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo() + /// builder.with_return_type("u32"); // fn foo() -> u32 + /// ``` pub fn with_return_type(mut self, ret_type: impl Into) -> Self { self.return_type = Some(ret_type.into()); self } + /// Complete the function definition. This function takes a callback that will form the body of the function. + /// + /// ```ignore + /// let mut builder: FnBuilder = ...; + /// // fn foo() + /// builder.body(|b| { + /// b.push_parsed("println!(\"hello world\");"); + /// }); + /// ``` pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) { let FnBuilder { mut generate, @@ -141,9 +159,20 @@ impl<'a, 'b> FnBuilder<'a, 'b> { } } +/// The `self` argument of a function +#[allow(dead_code)] pub enum FnSelfArg { + /// No `self` argument. The function will be a static function. None, + + /// `self`. The function will consume self. + TakeSelf, + + /// `&self`. The function will take self by reference. RefSelf, + + /// `&mut self`. The function will take self by mutable reference. + MutSelf, } impl FnSelfArg { @@ -151,10 +180,18 @@ impl FnSelfArg { let mut builder = StreamBuilder::new(); match self { Self::None => return None, + Self::TakeSelf => { + builder.ident_str("self"); + } Self::RefSelf => { builder.punct('&'); builder.ident_str("self"); } + Self::MutSelf => { + builder.punct('&'); + builder.ident_str("mut"); + builder.ident_str("self"); + } } Some(builder) } diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs index cf56fa6..b330476 100644 --- a/derive/src/generate/generator.rs +++ b/derive/src/generate/generator.rs @@ -24,18 +24,22 @@ impl Generator { } } + /// Return the name for the struct or enum that this is going to be implemented on. pub fn target_name(&self) -> &Ident { &self.name } + /// Generate an `for for ` implementation. See [ImplFor] for more information. pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { ImplFor::new(self, trait_name) } + /// Generate an `for <'__de> for ` implementation. See [ImplFor] for more information. pub fn impl_for_with_de_lifetime<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { ImplFor::new_with_de_lifetime(self, trait_name) } + /// Returns `true` if the struct or enum has lifetimes. pub fn has_lifetimes(&self) -> bool { self.generics .as_ref() @@ -43,8 +47,9 @@ impl Generator { .unwrap_or(false) } + /// Consume the contents of this generator. This *must* be called, or else the generator will panic on drop. pub fn take_stream(mut self) -> TokenStream { - std::mem::take(&mut self.stream.stream) + std::mem::take(&mut self.stream).stream } } diff --git a/derive/src/generate/impl_for.rs b/derive/src/generate/impl_for.rs index 753f206..7652848 100644 --- a/derive/src/generate/impl_for.rs +++ b/derive/src/generate/impl_for.rs @@ -58,6 +58,7 @@ impl<'a> ImplFor<'a> { Self { generator, group } } + /// Add a function to the trait implementation pub fn generate_fn<'b>(&'b mut self, name: &str) -> FnBuilder<'a, 'b> { FnBuilder::new(self, name) } diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs index 8331286..3ee6566 100644 --- a/derive/src/generate/stream_builder.rs +++ b/derive/src/generate/stream_builder.rs @@ -3,6 +3,7 @@ use crate::prelude::{ }; use std::str::FromStr; +/// A helper struct build around a [TokenStream] to make it easier to build code. #[must_use] #[derive(Default)] pub struct StreamBuilder { @@ -10,24 +11,31 @@ pub struct StreamBuilder { } impl StreamBuilder { + /// Generate a new StreamBuilder pub fn new() -> Self { Self { stream: TokenStream::new(), } } + /// Add multiple `TokenTree` items to the stream. pub fn extend(&mut self, item: impl IntoIterator) { self.stream.extend(item); } + /// Append another StreamBuilder to the current StreamBuilder. pub fn append(&mut self, builder: StreamBuilder) { self.stream.extend(builder.stream); } + /// Push a single token to the stream. pub fn push(&mut self, item: impl Into) { self.stream.extend([item.into()]); } + /// Attempt to parse the given string as valid Rust code, and append the parsed result to the internal stream. + /// + /// Currently panics if the string could not be parsed as valid Rust code. pub fn push_parsed(&mut self, item: impl AsRef) { self.stream .extend(TokenStream::from_str(item.as_ref()).unwrap_or_else(|e| { @@ -39,10 +47,12 @@ impl StreamBuilder { })); } + /// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc. pub fn ident(&mut self, ident: Ident) { self.stream.extend([TokenTree::Ident(ident)]); } + /// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc. pub fn ident_str(&mut self, ident: impl AsRef) { self.stream.extend([TokenTree::Ident(Ident::new( ident.as_ref(), @@ -50,6 +60,9 @@ impl StreamBuilder { ))]); } + /// Add a group. A group is any block surrounded by `{ .. }`, `[ .. ]` or `( .. )`. + /// + /// `delim` indicates which group it is. The `inner` callback is used to fill the contents of the group. pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder)) { let mut stream = StreamBuilder::new(); inner(&mut stream); @@ -57,11 +70,18 @@ impl StreamBuilder { .extend([TokenTree::Group(Group::new(delim, stream.stream))]); } + /// Add a single punctuation to the stream. Puncts are single-character tokens like `.`, `<`, `#`, etc + /// + /// Note that this should not be used for multi-punct constructions like `::` or `->`. For that use [puncts] instead. pub fn punct(&mut self, p: char) { self.stream .extend([TokenTree::Punct(Punct::new(p, Spacing::Alone))]); } + /// Add multiple punctuations to the stream. Multi punct tokens are e.g. `::`, `->` and `=>`. + /// + /// Note that this is the only way to add multi punct tokens. + /// If you were to use [punct] to insert `->` it would be inserted as `-` and then `>`, and not form a single token. Rust would interpret this as a "minus sign and then a greater than sign", not as a single arrow. pub fn puncts(&mut self, puncts: &str) { self.stream.extend( puncts @@ -70,12 +90,29 @@ impl StreamBuilder { ); } + /// Add a lifetime to the stream. + /// + /// Note that this is the only way to add lifetimes, if you were to do: + /// ```ignore + /// builder.punct('\''); + /// builder.ident_str("static"); + /// ``` + /// It would not add `'static`, but instead it would add `' static` as seperate tokens, and the lifetime would not work. pub fn lifetime(&mut self, lt: Ident) { self.stream.extend([ TokenTree::Punct(Punct::new('\'', Spacing::Joint)), TokenTree::Ident(lt), ]); } + + /// Add a lifetime to the stream. + /// + /// Note that this is the only way to add lifetimes, if you were to do: + /// ```ignore + /// builder.punct('\''); + /// builder.ident_str("static"); + /// ``` + /// It would not add `'static`, but instead it would add `' static` as seperate tokens, and the lifetime would not work. pub fn lifetime_str(&mut self, lt: &str) { self.stream.extend([ TokenTree::Punct(Punct::new('\'', Spacing::Joint)), @@ -83,21 +120,25 @@ impl StreamBuilder { ]); } + /// Add a literal string (`&'static str`) to the stream. pub fn lit_str(&mut self, str: impl AsRef) { self.stream .extend([TokenTree::Literal(Literal::string(str.as_ref()))]); } + /// Add an `u32` value to the stream. pub fn lit_u32(&mut self, val: u32) { self.stream .extend([TokenTree::Literal(Literal::u32_unsuffixed(val))]); } + /// Add an `usize` value to the stream. pub fn lit_usize(&mut self, val: usize) { self.stream .extend([TokenTree::Literal(Literal::usize_unsuffixed(val))]); } + /// Set the given span on all tokens in the stream. This span is used by rust for e.g. compiler errors, to indicate the position of the error. pub fn set_span_on_all_tokens(&mut self, span: Span) { self.stream = std::mem::take(&mut self.stream) .into_iter() From 435e03018263a332435eb783a61291eb553f2829 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 19 Oct 2021 10:22:19 +0200 Subject: [PATCH 66/80] Removed a panic in the derive/src/generate module, moved it to derive/src/derive_* instead --- derive/src/derive_enum.rs | 99 ++++++++++++++------------- derive/src/derive_struct.rs | 48 ++++++++----- derive/src/generate/generate_fn.rs | 27 ++++---- derive/src/generate/generator.rs | 8 ++- derive/src/generate/impl_for.rs | 20 ++++-- derive/src/generate/stream_builder.rs | 29 ++++---- 6 files changed, 132 insertions(+), 99 deletions(-) diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index fe3270f..6ab9f30 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -15,6 +15,7 @@ impl DeriveEnum { generator .impl_for("bincode::enc::Encode") + .unwrap() .generate_fn("encode") .with_generic("E", ["bincode::enc::Encoder"]) .with_self_arg(FnSelfArg::RefSelf) @@ -64,20 +65,23 @@ impl DeriveEnum { body.push_parsed(format!( "::encode(&{}, &mut encoder)?;", variant_index - )); + )) + .unwrap(); // If we have any fields, encode them all one by one for field_name in variant.fields.names() { body.push_parsed(format!( "bincode::enc::Encode::encode({}, &mut encoder)?;", field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), - )); + )) + .unwrap(); } }); match_body.punct(','); } }); - fn_body.push_parsed("Ok(())"); - }); + fn_body.push_parsed("Ok(())").unwrap(); + }) + .unwrap(); Ok(()) } @@ -89,14 +93,15 @@ impl DeriveEnum { // enum has a lifetime, implement BorrowDecode generator.impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>") + .unwrap() .generate_fn("borrow_decode") .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_builder| { fn_builder - .push_parsed("let variant_index = ::decode(&mut decoder)?;"); - fn_builder.push_parsed("match variant_index"); + .push_parsed("let variant_index = ::decode(&mut decoder)?;").unwrap(); + fn_builder.push_parsed("match variant_index").unwrap(); fn_builder.group(Delimiter::Brace, |variant_case| { for (idx, variant) in variants.iter().enumerate() { // idx => Ok(..) @@ -120,7 +125,7 @@ impl DeriveEnum { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); - variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,"); + variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,").unwrap(); } }); }); @@ -132,59 +137,59 @@ impl DeriveEnum { "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})", variants.len() - 1, enum_name.to_string() - )); + )).unwrap(); }); - }); + }).unwrap(); } else { // enum has no lifetimes, implement Decode generator.impl_for("bincode::de::Decode") + .unwrap() .generate_fn("decode") .with_generic("D", ["bincode::de::Decoder"]) .with_arg("mut decoder", "D") .with_return_type("Result") .body(|fn_builder| { + fn_builder + .push_parsed("let variant_index = ::decode(&mut decoder)?;").unwrap(); + fn_builder.push_parsed("match variant_index").unwrap(); + fn_builder.group(Delimiter::Brace, |variant_case| { + for (idx, variant) in variants.iter().enumerate() { + // idx => Ok(..) + variant_case.lit_u32(idx as u32); + variant_case.puncts("=>"); + variant_case.ident_str("Ok"); + variant_case.group(Delimiter::Parenthesis, |variant_case_body| { + // Self::Variant { } + // Self::Variant { 0: ..., 1: ... 2: ... }, + // Self::Variant { a: ..., b: ... c: ... }, + variant_case_body.ident_str("Self"); + variant_case_body.puncts("::"); + variant_case_body.ident(variant.name.clone()); - fn_builder - .push_parsed("let variant_index = ::decode(&mut decoder)?;"); - fn_builder.push_parsed("match variant_index"); - fn_builder.group(Delimiter::Brace, |variant_case| { - for (idx, variant) in variants.iter().enumerate() { - // idx => Ok(..) - variant_case.lit_u32(idx as u32); - variant_case.puncts("=>"); - variant_case.ident_str("Ok"); - variant_case.group(Delimiter::Parenthesis, |variant_case_body| { - // Self::Variant { } - // Self::Variant { 0: ..., 1: ... 2: ... }, - // Self::Variant { a: ..., b: ... c: ... }, - variant_case_body.ident_str("Self"); - variant_case_body.puncts("::"); - variant_case_body.ident(variant.name.clone()); - - variant_case_body.group(Delimiter::Brace, |variant_body| { - let is_tuple = matches!(variant.fields, Fields::Tuple(_)); - for (idx, field) in variant.fields.names().into_iter().enumerate() { - if is_tuple { - variant_body.lit_usize(idx); - } else { - variant_body.ident(field.unwrap_ident().clone()); + variant_case_body.group(Delimiter::Brace, |variant_body| { + let is_tuple = matches!(variant.fields, Fields::Tuple(_)); + for (idx, field) in variant.fields.names().into_iter().enumerate() { + if is_tuple { + variant_body.lit_usize(idx); + } else { + variant_body.ident(field.unwrap_ident().clone()); + } + variant_body.punct(':'); + variant_body.push_parsed("bincode::de::Decode::decode(&mut decoder)?,").unwrap(); } - variant_body.punct(':'); - variant_body.push_parsed("bincode::de::Decode::decode(&mut decoder)?,"); - } + }); }); - }); - variant_case.punct(','); - } + variant_case.punct(','); + } - // invalid idx - variant_case.push_parsed(format!( - "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})", - variants.len() - 1, - enum_name.to_string() - )); - }); - }); + // invalid idx + variant_case.push_parsed(format!( + "variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})", + variants.len() - 1, + enum_name.to_string() + )).unwrap(); + }); + }).unwrap(); } Ok(()) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index c71b9c8..8c08f56 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -11,8 +11,9 @@ impl DeriveStruct { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { let DeriveStruct { fields } = self; - let mut impl_for = generator.impl_for("bincode::enc::Encode"); - impl_for + generator + .impl_for("bincode::enc::Encode") + .unwrap() .generate_fn("encode") .with_generic("E", ["bincode::enc::Encoder"]) .with_self_arg(crate::generate::FnSelfArg::RefSelf) @@ -20,13 +21,16 @@ impl DeriveStruct { .with_return_type("Result<(), bincode::error::EncodeError>") .body(|fn_body| { for field in fields.names() { - fn_body.push_parsed(format!( - "bincode::enc::Encode::encode(&self.{}, &mut encoder)?;", - field.to_string() - )); + fn_body + .push_parsed(format!( + "bincode::enc::Encode::encode(&self.{}, &mut encoder)?;", + field.to_string() + )) + .unwrap(); } - fn_body.push_parsed("Ok(())"); - }); + fn_body.push_parsed("Ok(())").unwrap(); + }) + .unwrap(); Ok(()) } @@ -39,6 +43,7 @@ impl DeriveStruct { generator .impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>") + .unwrap() .generate_fn("borrow_decode") .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) .with_arg("mut decoder", "D") @@ -50,21 +55,25 @@ impl DeriveStruct { ok_group.ident_str("Self"); ok_group.group(Delimiter::Brace, |struct_body| { for field in fields.names() { - struct_body.push_parsed(format!( + struct_body + .push_parsed(format!( "{}: bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,", field.to_string() - )); + )) + .unwrap(); } }); }); - }); + }) + .unwrap(); Ok(()) } else { // struct has no lifetimes, implement Decode - let mut impl_for = generator.impl_for("bincode::de::Decode"); - impl_for + generator + .impl_for("bincode::de::Decode") + .unwrap() .generate_fn("decode") .with_generic("D", ["bincode::de::Decoder"]) .with_arg("mut decoder", "D") @@ -82,14 +91,17 @@ impl DeriveStruct { // ... // } for field in fields.names() { - struct_body.push_parsed(format!( - "{}: bincode::de::Decode::decode(&mut decoder)?,", - field.to_string() - )); + struct_body + .push_parsed(format!( + "{}: bincode::de::Decode::decode(&mut decoder)?,", + field.to_string() + )) + .unwrap(); } }); }); - }); + }) + .unwrap(); Ok(()) } diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs index ff44ede..f63a390 100644 --- a/derive/src/generate/generate_fn.rs +++ b/derive/src/generate/generate_fn.rs @@ -1,9 +1,9 @@ -use super::{ImplFor, StreamBuilder}; +use super::{stream_builder::PushParseError, ImplFor, StreamBuilder}; use crate::prelude::Delimiter; /// A builder for functions. pub struct FnBuilder<'a, 'b> { - generate: Option<&'b mut ImplFor<'a>>, + generate: &'b mut ImplFor<'a>, name: String, lifetime_and_generics: Vec<(String, Vec)>, @@ -15,7 +15,7 @@ pub struct FnBuilder<'a, 'b> { impl<'a, 'b> FnBuilder<'a, 'b> { pub(super) fn new(generate: &'b mut ImplFor<'a>, name: impl Into) -> Self { Self { - generate: Some(generate), + generate, name: name.into(), lifetime_and_generics: Vec::new(), self_arg: FnSelfArg::None, @@ -94,9 +94,9 @@ impl<'a, 'b> FnBuilder<'a, 'b> { /// b.push_parsed("println!(\"hello world\");"); /// }); /// ``` - pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) { + pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) -> Result<(), PushParseError> { let FnBuilder { - mut generate, + generate, name, lifetime_and_generics, self_arg, @@ -123,7 +123,7 @@ impl<'a, 'b> FnBuilder<'a, 'b> { if !dependencies.is_empty() { for (idx, dependency) in dependencies.into_iter().enumerate() { builder.punct(if idx == 0 { ':' } else { '+' }); - builder.push_parsed(&dependency); + builder.push_parsed(&dependency)?; } } } @@ -140,22 +140,23 @@ impl<'a, 'b> FnBuilder<'a, 'b> { if idx != 0 { arg_stream.punct(','); } - arg_stream.push_parsed(&arg_name); + arg_stream.push_parsed(&arg_name)?; arg_stream.punct(':'); - arg_stream.push_parsed(&arg_ty); + arg_stream.push_parsed(&arg_ty)?; } - }); + Ok(()) + })?; // Return type: `-> ResultType` if let Some(return_type) = return_type { builder.puncts("->"); - builder.push_parsed(&return_type); + builder.push_parsed(&return_type)?; } - let generator = generate.take().unwrap(); + generate.group.append(builder); + generate.group.group(Delimiter::Brace, body_builder); - generator.group.append(builder); - generator.group.group(Delimiter::Brace, body_builder); + Ok(()) } } diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs index b330476..7cc0bc0 100644 --- a/derive/src/generate/generator.rs +++ b/derive/src/generate/generator.rs @@ -1,3 +1,4 @@ +use super::stream_builder::PushParseError; use super::{ImplFor, StreamBuilder}; use crate::parse::{GenericConstraints, Generics}; use crate::prelude::{Ident, TokenStream}; @@ -30,12 +31,15 @@ impl Generator { } /// Generate an `for for ` implementation. See [ImplFor] for more information. - pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { + pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> Result, PushParseError> { ImplFor::new(self, trait_name) } /// Generate an `for <'__de> for ` implementation. See [ImplFor] for more information. - pub fn impl_for_with_de_lifetime<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> { + pub fn impl_for_with_de_lifetime<'a>( + &'a mut self, + trait_name: &str, + ) -> Result, PushParseError> { ImplFor::new_with_de_lifetime(self, trait_name) } diff --git a/derive/src/generate/impl_for.rs b/derive/src/generate/impl_for.rs index 7652848..db2ddf4 100644 --- a/derive/src/generate/impl_for.rs +++ b/derive/src/generate/impl_for.rs @@ -1,4 +1,4 @@ -use super::{FnBuilder, Generator, StreamBuilder}; +use super::{stream_builder::PushParseError, FnBuilder, Generator, StreamBuilder}; use crate::prelude::Delimiter; #[must_use] @@ -8,14 +8,17 @@ pub struct ImplFor<'a> { } impl<'a> ImplFor<'a> { - pub(super) fn new(generator: &'a mut Generator, trait_name: &str) -> Self { + pub(super) fn new( + generator: &'a mut Generator, + trait_name: &str, + ) -> Result { let mut builder = StreamBuilder::new(); builder.ident_str("impl"); if let Some(generics) = &generator.generics { builder.append(generics.impl_generics()); } - builder.push_parsed(trait_name); + builder.push_parsed(trait_name)?; builder.ident_str("for"); builder.ident(generator.name.clone()); @@ -28,10 +31,13 @@ impl<'a> ImplFor<'a> { generator.stream.append(builder); let group = StreamBuilder::new(); - Self { generator, group } + Ok(Self { generator, group }) } - pub(super) fn new_with_de_lifetime(generator: &'a mut Generator, trait_name: &str) -> Self { + pub(super) fn new_with_de_lifetime( + generator: &'a mut Generator, + trait_name: &str, + ) -> Result { let mut builder = StreamBuilder::new(); builder.ident_str("impl"); @@ -43,7 +49,7 @@ impl<'a> ImplFor<'a> { builder.punct('>'); } - builder.push_parsed(trait_name); + builder.push_parsed(trait_name)?; builder.ident_str("for"); builder.ident(generator.name.clone()); if let Some(generics) = &generator.generics { @@ -55,7 +61,7 @@ impl<'a> ImplFor<'a> { generator.stream.append(builder); let group = StreamBuilder::new(); - Self { generator, group } + Ok(Self { generator, group }) } /// Add a function to the trait implementation diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs index 3ee6566..3c44647 100644 --- a/derive/src/generate/stream_builder.rs +++ b/derive/src/generate/stream_builder.rs @@ -1,5 +1,5 @@ use crate::prelude::{ - Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, }; use std::str::FromStr; @@ -36,15 +36,13 @@ impl StreamBuilder { /// Attempt to parse the given string as valid Rust code, and append the parsed result to the internal stream. /// /// Currently panics if the string could not be parsed as valid Rust code. - pub fn push_parsed(&mut self, item: impl AsRef) { - self.stream - .extend(TokenStream::from_str(item.as_ref()).unwrap_or_else(|e| { - panic!( - "Could not parse string as rust: {:?}\n{:?}", - item.as_ref(), - e - ) - })); + pub fn push_parsed(&mut self, item: impl AsRef) -> Result<(), PushParseError> { + let tokens = TokenStream::from_str(item.as_ref()).map_err(|e| PushParseError { + error: e, + code: item.as_ref().to_string(), + })?; + self.stream.extend(tokens); + Ok(()) } /// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc. @@ -63,11 +61,12 @@ impl StreamBuilder { /// Add a group. A group is any block surrounded by `{ .. }`, `[ .. ]` or `( .. )`. /// /// `delim` indicates which group it is. The `inner` callback is used to fill the contents of the group. - pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder)) { + pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder) -> T) -> T { let mut stream = StreamBuilder::new(); - inner(&mut stream); + let result = inner(&mut stream); self.stream .extend([TokenTree::Group(Group::new(delim, stream.stream))]); + result } /// Add a single punctuation to the stream. Puncts are single-character tokens like `.`, `<`, `#`, etc @@ -149,3 +148,9 @@ impl StreamBuilder { .collect(); } } + +#[derive(Debug)] +pub struct PushParseError { + pub error: LexError, + pub code: String, +} From 151edf46d3b7dca62c6ecc7a6c5ddcd7f7cab394 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 19 Oct 2021 11:04:56 +0200 Subject: [PATCH 67/80] Included spec.md into cargo's documentation, fixed the issues, changed the [u8; N] implementations to [T; N] --- docs/spec.md | 66 ++++++++++++++++++++++++++++++------------------ src/de/impls.rs | 40 ++++++++++++++++++++++++++--- src/enc/impls.rs | 10 ++++++-- src/lib.rs | 4 +++ tests/utils.rs | 2 +- 5 files changed, 91 insertions(+), 31 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 58ab56c..6cd8471 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -2,7 +2,7 @@ *NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization with `serde-derive` is supported as well. `serde-derive` has the same guarantees as `bincode_derive` for now. -Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123 +Related issue: ## Endian @@ -17,12 +17,14 @@ All basic numeric types will be encoded based on the configured [IntEncoding](#I All floating point types will take up exactly 4 (for `f32`) or 8 (for `f64`) bytes. All tuples have no additional bytes, and are encoded in their specified order, e.g. -```rs +```rust +use bincode::config::Configuration; + let tuple = (u32::min_value(), i32::max_value()); // 8 bytes -let encoded = bincode::encode_to_vec_with_options(&tuple, Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(tuple, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 0, 0, 0, 0, // 4 bytes for first type: u32 - 255, 255, 255, 255 // 4 bytes for second type: i32 + 255, 255, 255, 127 // 4 bytes for second type: i32 ]); ``` @@ -56,7 +58,9 @@ Enums are encoded with their variant first, followed by optionally the variant f Both named and unnamed fields are serialized with their values only, and therefor encode to the same value. -```rs +```rust +use bincode::config::Configuration; + #[derive(bincode::Encode)] pub enum SomeEnum { A, @@ -65,23 +69,23 @@ pub enum SomeEnum { } // SomeEnum::A -let encoded = bincode::encode_to_vec_with_options(&SomeEnum::A, Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(SomeEnum::A, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 0, 0, 0, 0, // first variant, A // no extra bytes because A has no fields ]); // SomeEnum::B(0) -let encoded = bincode::encode_to_vec_with_options(&SomeEnum::B(0), Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(SomeEnum::B(0), Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ - 0, 0, 0, 1, // first variant, B + 1, 0, 0, 0, // first variant, B 0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes ]); // SomeEnum::C { value: 0u32 } -let encoded = bincode::encode_to_vec_with_options(&SomeEnum::C { value: 0u32 }, Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(SomeEnum::C { value: 0u32 }, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ - 0, 0, 0, 2, // first variant, C + 2, 0, 0, 0, // first variant, C 0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes ]); ``` @@ -92,16 +96,17 @@ Collections are encoded with their length value first, following by each entry o **note**: fixed array length do not have their `len` encoded. See [Arrays](#arrays) -```rs +```rust +use bincode::config::Configuration; let list = vec![ 0u8, 1u8, 2u8 ]; -let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(list, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ - 0, 0, 0, 0, 0, 0, 0, 3, // length of 3u64 + 3, 0, 0, 0, 0, 0, 0, 0, // length of 3u64 0, // entry 0 1, // entry 1 2, // entry 2 @@ -114,30 +119,39 @@ This also applies to e.g. `HashMap`, where each entry is a [tuple](#basic-types) Both `String` and `&str` are treated as a `Vec`. See [Collections](#collections) for more information. -```rs +```rust +use bincode::config::Configuration; + let str = "Hello"; // Could also be `String::new(...)` -let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap(); +let encoded = bincode::encode_to_vec_with_config(str, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ - 0, 0, 0, 0, 0, 0, 0, 5, // length of the string, 5 bytes + 5, 0, 0, 0, 0, 0, 0, 0, // length of the string, 5 bytes b'H', b'e', b'l', b'l', b'o' ]); ``` # Arrays -Arrays are encoded *without* a length. +Arrays are encoded *with* a length by default. + +```rust +use bincode::config::Configuration; -```rs let arr: [u8; 5] = [10, 20, 30, 40, 50]; -let encoded = bincode::encode_to_vec(&list).unwrap(); -assert_eq!(encoded.as_slice(), &[10, 20, 30, 40 50]); +let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 5, 0, 0, 0, 0, 0, 0, 0, // The length, as a u64 + 10, 20, 30, 40, 50, // the bytes +]); ``` This applies to any type `T` that implements `Encodabl`/`Decodabl` -```rs -#[derive(bincode::Encodabl)] +```rust +use bincode::config::Configuration; + +#[derive(bincode::Encode)] struct Foo { first: u8, second: u8 @@ -154,7 +168,11 @@ let arr: [Foo; 2] = [ }, ]; -let encoded = bincode::encode_to_vec(&list).unwrap(); -assert_eq!(encoded.as_slice(), &[10, 20, 30, 40]); +let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap(); +assert_eq!(encoded.as_slice(), &[ + 2, 0, 0, 0, 0, 0, 0, 0, // Length of the array + 10, 20, // First Foo + 30, 40, // Second Foo +]); ``` diff --git a/src/de/impls.rs b/src/de/impls.rs index 3dccb96..1ef50c5 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -382,9 +382,11 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str { } } -impl Decode for [u8; N] { +impl Decode for [T; N] +where + T: Decode + Sized, +{ fn decode(mut decoder: D) -> Result { - let mut array = [0u8; N]; if !D::C::SKIP_FIXED_ARRAY_LENGTH { let length = usize::decode(&mut decoder)?; if length != N { @@ -394,8 +396,38 @@ impl Decode for [u8; N] { }); } } - decoder.reader().read(&mut array)?; - Ok(array) + + // Safety: this is taken from the example of https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html + // and is therefor assumed to be safe + + use core::mem::MaybeUninit; + + // Create an uninitialized array of `MaybeUninit`. The `assume_init` is + // safe because the type we are claiming to have initialized here is a + // bunch of `MaybeUninit`s, which do not require initialization. + let mut data: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + // Dropping a `MaybeUninit` does nothing. Thus using raw pointer + // assignment instead of `ptr::write` does not cause the old + // uninitialized value to be dropped. Also if there is a panic during + // this loop, we have a memory leak, but there is no memory safety + // issue. + for elem in &mut data[..] { + elem.write(T::decode(&mut decoder)?); + } + + // Everything is initialized. Transmute the array to the + // initialized type. + + // BlockedTODO: https://github.com/rust-lang/rust/issues/61956 + // let result = unsafe { transmute::<_, [T; N]>(data) }; + + // Const generics don't work well with transmute at the moment + // The above issue recommends doing the following + let ptr = &mut data as *mut _ as *mut [T; N]; + let res = unsafe { ptr.read() }; + core::mem::forget(data); + Ok(res) } } diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 82645df..6685839 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -338,12 +338,18 @@ impl Encode for &'_ str { } } -impl Encode for [u8; N] { +impl Encode for [T; N] +where + T: Encode, +{ fn encode(&self, mut encoder: E) -> Result<(), EncodeError> { if !E::C::SKIP_FIXED_ARRAY_LENGTH { N.encode(&mut encoder)?; } - encoder.writer().write(self) + for item in self.iter() { + item.encode(&mut encoder)?; + } + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index 4c6f837..c158754 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,3 +91,7 @@ pub fn decode_with_config<'__de, D: de::BorrowDecode<'__de>, C: Config>( let mut decoder = de::DecoderImpl::<_, C>::new(reader, _config); D::borrow_decode(&mut decoder) } + +pub mod spec { + #![doc = include_str!("../docs/spec.md")] +} diff --git a/tests/utils.rs b/tests/utils.rs index 5f4f280..f0c4316 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -7,7 +7,7 @@ where C: Config, CMP: Fn(&V, &V) -> bool, { - let mut buffer = [0u8; 1024]; + let mut buffer = [0u8; 2048]; let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", From 07b3c8cd76b2dd997d42848d2f99bd8b5931407c Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 19 Oct 2021 11:26:29 +0200 Subject: [PATCH 68/80] Made the Decode of [T; N] properly drop all instances of T when an error has occured --- src/de/impls.rs | 42 +++++++++++++++++++++++++++++++++--------- src/lib.rs | 3 +++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index 1ef50c5..99d1c10 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -400,31 +400,55 @@ where // Safety: this is taken from the example of https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html // and is therefor assumed to be safe - use core::mem::MaybeUninit; + use core::mem::{ManuallyDrop, MaybeUninit}; // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut data: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; - // Dropping a `MaybeUninit` does nothing. Thus using raw pointer - // assignment instead of `ptr::write` does not cause the old - // uninitialized value to be dropped. Also if there is a panic during - // this loop, we have a memory leak, but there is no memory safety - // issue. - for elem in &mut data[..] { - elem.write(T::decode(&mut decoder)?); + for (idx, elem) in data.iter_mut().enumerate() { + match T::decode(&mut decoder) { + Ok(t) => { + elem.write(t); + } + Err(e) => { + // We encountered an error, clean up all previous entries + + unsafe { + // Safety: we know we've written up to `idx` items + for item in &mut data[..idx] { + // Safety: We know the `item` is written with a valid value of `T`. + // And we know that `&mut item` won't be used any more after this. + ManuallyDrop::drop(&mut *(item as *mut _ as *mut ManuallyDrop)); + } + // make sure `data` isn't dropped twice + core::mem::forget(data); + } + + return Err(e); + } + } } // Everything is initialized. Transmute the array to the // initialized type. // BlockedTODO: https://github.com/rust-lang/rust/issues/61956 + // This does not work at the moment: // let result = unsafe { transmute::<_, [T; N]>(data) }; + // Alternatively we can use this: + // BlockedTODO: https://github.com/rust-lang/rust/issues/80908 + // Const generics don't work well with transmute at the moment - // The above issue recommends doing the following + // The first issue above recommends doing the following: let ptr = &mut data as *mut _ as *mut [T; N]; + + // Safety: we know this is an array with every value written, + // and that the array is valid. + // As well as the original `data` that will be forgotten so we won't get + // multiple (mutable) references to the same memory let res = unsafe { ptr.read() }; core::mem::forget(data); Ok(res) diff --git a/src/lib.rs b/src/lib.rs index c158754..8502006 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,6 +92,9 @@ pub fn decode_with_config<'__de, D: de::BorrowDecode<'__de>, C: Config>( D::borrow_decode(&mut decoder) } +// TODO: Currently our doctests fail when trying to include the specs because the specs depend on `derive` and `alloc`. +// But we want to have the specs in the docs always +#[cfg(all(feature = "alloc", feature = "derive"))] pub mod spec { #![doc = include_str!("../docs/spec.md")] } From 6ff33cd8c255f360723f3ca427f4f899b9a91846 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 12:54:37 +0200 Subject: [PATCH 69/80] Replaced the decode implementation of [T; N] with the implementation from core --- src/de/impl_core.rs | 186 ++++++++++++++++++++++++++++++++++++++++++++ src/de/impls.rs | 59 ++------------ src/de/mod.rs | 1 + 3 files changed, 192 insertions(+), 54 deletions(-) create mode 100644 src/de/impl_core.rs diff --git a/src/de/impl_core.rs b/src/de/impl_core.rs new file mode 100644 index 0000000..a5dc4c4 --- /dev/null +++ b/src/de/impl_core.rs @@ -0,0 +1,186 @@ +#![allow(unused_unsafe)] + +//! Contains implementations for rust core that have not been stabilized +//! +//! Functions in this are expected to be properly peer reviewed by the community +//! +//! Any modifications done are purely to make the code compatible with bincode + +use core::mem::{self, MaybeUninit}; + +/// Pulls `N` items from `iter` and returns them as an array. If the iterator +/// yields fewer than `N` items, `None` is returned and all already yielded +/// items are dropped. +/// +/// Since the iterator is passed as a mutable reference and this function calls +/// `next` at most `N` times, the iterator can still be used afterwards to +/// retrieve the remaining items. +/// +/// If `iter.next()` panicks, all items already yielded by the iterator are +/// dropped. +#[allow(clippy::while_let_on_iterator)] +pub fn collect_into_array(iter: &mut I) -> Option> +where + I: Iterator>, +{ + if N == 0 { + // SAFETY: An empty array is always inhabited and has no validity invariants. + return unsafe { Some(Ok(mem::zeroed())) }; + } + + struct Guard<'a, T, const N: usize> { + array_mut: &'a mut [MaybeUninit; N], + initialized: usize, + } + + impl Drop for Guard<'_, T, N> { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + + // SAFETY: this slice will contain only initialized objects. + unsafe { + core::ptr::drop_in_place(slice_assume_init_mut( + &mut self.array_mut.get_unchecked_mut(..self.initialized), + )); + } + } + } + + let mut array = uninit_array::(); + let mut guard = Guard { + array_mut: &mut array, + initialized: 0, + }; + + while let Some(item_rslt) = iter.next() { + let item = match item_rslt { + Err(err) => { + return Some(Err(err)); + } + Ok(elem) => elem, + }; + + // SAFETY: `guard.initialized` starts at 0, is increased by one in the + // loop and the loop is aborted once it reaches N (which is + // `array.len()`). + unsafe { + guard + .array_mut + .get_unchecked_mut(guard.initialized) + .write(item); + } + guard.initialized += 1; + + // Check if the whole array was initialized. + if guard.initialized == N { + mem::forget(guard); + + // SAFETY: the condition above asserts that all elements are + // initialized. + let out = unsafe { array_assume_init(array) }; + return Some(Ok(out)); + } + } + + // This is only reached if the iterator is exhausted before + // `guard.initialized` reaches `N`. Also note that `guard` is dropped here, + // dropping all already initialized elements. + None +} + +/// Assuming all the elements are initialized, get a mutable slice to them. +/// +/// # Safety +/// +/// It is up to the caller to guarantee that the `MaybeUninit` elements +/// really are in an initialized state. +/// Calling this when the content is not yet fully initialized causes undefined behavior. +/// +/// See [`assume_init_mut`] for more details and examples. +/// +/// [`assume_init_mut`]: MaybeUninit::assume_init_mut +// #[unstable(feature = "maybe_uninit_slice", issue = "63569")] +// #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] +#[inline(always)] +pub unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit]) -> &mut [T] { + // SAFETY: similar to safety notes for `slice_get_ref`, but we have a + // mutable reference which is also guaranteed to be valid for writes. + unsafe { &mut *(slice as *mut [MaybeUninit] as *mut [T]) } +} + +/// Create a new array of `MaybeUninit` items, in an uninitialized state. +/// +/// Note: in a future Rust version this method may become unnecessary +/// when Rust allows +/// [inline const expressions](https://github.com/rust-lang/rust/issues/76001). +/// The example below could then use `let mut buf = [const { MaybeUninit::::uninit() }; 32];`. +/// +/// # Examples +/// +/// ```ignore +/// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)] +/// +/// use std::mem::MaybeUninit; +/// +/// extern "C" { +/// fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize; +/// } +/// +/// /// Returns a (possibly smaller) slice of data that was actually read +/// fn read(buf: &mut [MaybeUninit]) -> &[u8] { +/// unsafe { +/// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); +/// MaybeUninit::slice_assume_init_ref(&buf[..len]) +/// } +/// } +/// +/// let mut buf: [MaybeUninit; 32] = MaybeUninit::uninit_array(); +/// let data = read(&mut buf); +/// ``` +// #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] +// #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] +#[inline(always)] +fn uninit_array() -> [MaybeUninit; LEN] { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. + unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } +} + +/// Extracts the values from an array of `MaybeUninit` containers. +/// +/// # Safety +/// +/// It is up to the caller to guarantee that all elements of the array are +/// in an initialized state. +/// +/// # Examples +/// +/// ```ignore +/// #![feature(maybe_uninit_uninit_array)] +/// #![feature(maybe_uninit_array_assume_init)] +/// use std::mem::MaybeUninit; +/// +/// let mut array: [MaybeUninit; 3] = MaybeUninit::uninit_array(); +/// array[0].write(0); +/// array[1].write(1); +/// array[2].write(2); +/// +/// // SAFETY: Now safe as we initialised all elements +/// let array = unsafe { +/// MaybeUninit::array_assume_init(array) +/// }; +/// +/// assert_eq!(array, [0, 1, 2]); +/// ``` +// #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")] +#[inline(always)] +pub unsafe fn array_assume_init(array: [MaybeUninit; N]) -> [T; N] { + // SAFETY: + // * The caller guarantees that all elements of the array are initialized + // * `MaybeUninit` and T are guaranteed to have the same layout + // * `MaybeUninit` does not drop, so there are no double-frees + // And thus the conversion is safe + unsafe { + // intrinsics::assert_inhabited::<[T; N]>(); + (&array as *const _ as *const [T; N]).read() + } +} diff --git a/src/de/impls.rs b/src/de/impls.rs index 99d1c10..9a738ed 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -397,61 +397,12 @@ where } } - // Safety: this is taken from the example of https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html - // and is therefor assumed to be safe + let result = + super::impl_core::collect_into_array(&mut (0..N).map(|_| T::decode(&mut decoder))); - use core::mem::{ManuallyDrop, MaybeUninit}; - - // Create an uninitialized array of `MaybeUninit`. The `assume_init` is - // safe because the type we are claiming to have initialized here is a - // bunch of `MaybeUninit`s, which do not require initialization. - let mut data: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; - - for (idx, elem) in data.iter_mut().enumerate() { - match T::decode(&mut decoder) { - Ok(t) => { - elem.write(t); - } - Err(e) => { - // We encountered an error, clean up all previous entries - - unsafe { - // Safety: we know we've written up to `idx` items - for item in &mut data[..idx] { - // Safety: We know the `item` is written with a valid value of `T`. - // And we know that `&mut item` won't be used any more after this. - ManuallyDrop::drop(&mut *(item as *mut _ as *mut ManuallyDrop)); - } - // make sure `data` isn't dropped twice - core::mem::forget(data); - } - - return Err(e); - } - } - } - - // Everything is initialized. Transmute the array to the - // initialized type. - - // BlockedTODO: https://github.com/rust-lang/rust/issues/61956 - // This does not work at the moment: - // let result = unsafe { transmute::<_, [T; N]>(data) }; - - // Alternatively we can use this: - // BlockedTODO: https://github.com/rust-lang/rust/issues/80908 - - // Const generics don't work well with transmute at the moment - // The first issue above recommends doing the following: - let ptr = &mut data as *mut _ as *mut [T; N]; - - // Safety: we know this is an array with every value written, - // and that the array is valid. - // As well as the original `data` that will be forgotten so we won't get - // multiple (mutable) references to the same memory - let res = unsafe { ptr.read() }; - core::mem::forget(data); - Ok(res) + // result is only None if N does not match the values of `(0..N)`, which it always should + // So this unsafe should never occur + result.unwrap() } } diff --git a/src/de/mod.rs b/src/de/mod.rs index cce0d0f..14a4e32 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -3,6 +3,7 @@ use crate::{config::Config, error::DecodeError}; mod decoder; +mod impl_core; mod impl_tuples; mod impls; From f70e94a42731b8ba34c288730649fdf3866becd0 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 13:26:31 +0200 Subject: [PATCH 70/80] Added dedicated error for `std::path::Path` encoding. Fixed broken link in documentation. --- src/error.rs | 4 ++++ src/features/impl_std.rs | 2 +- src/lib.rs | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index e1aec77..a1e85fb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,6 +18,10 @@ pub enum EncodeError { /// An uncommon error occured, see the inner text for more information Other(&'static str), + /// A `std::path::Path` was being encoded but did not contain a valid `&str` representation + #[cfg(feature = "std")] + InvalidPathCharacters, + /// The targetted writer encountered an `std::io::Error` #[cfg(feature = "std")] Io { diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 2b6c59b..e59d465 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -184,7 +184,7 @@ impl Encode for &'_ Path { fn encode(&self, encoder: E) -> Result<(), EncodeError> { match self.to_str() { Some(str) => str.encode(encoder), - None => Err(EncodeError::Other("Path contains invalid UTF-8 characters")), + None => Err(EncodeError::InvalidPathCharacters), } } } diff --git a/src/lib.rs b/src/lib.rs index 8502006..5df6810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,9 +45,9 @@ use config::Config; /// Encode the given value into the given slice. Returns the amount of bytes that have been written. /// -/// Will take the [Default] configuration. See the [config] module for more information. +/// Will take the [standard] configuration. See the [config] module for more information. /// -/// [Default]: config/struct.Default.html +/// [standard]: config/struct.Configuration.html#method.standard pub fn encode_into_slice( val: E, dst: &mut [u8], From adc47b68953d9ea85177c1be8ba67e87a9fa9f4f Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 13:31:13 +0200 Subject: [PATCH 71/80] Fixed a copy-paste error where RwLock would report to be a Mutex if it fails to lock --- src/features/impl_std.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index e59d465..37888cc 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -145,7 +145,7 @@ where { fn encode(&self, encoder: E) -> Result<(), EncodeError> { let t = self.read().map_err(|_| EncodeError::LockFailed { - type_name: core::any::type_name::>(), + type_name: core::any::type_name::>(), })?; t.encode(encoder) } From dd7e8e8e43b447ae6b9cc2909b24de5e5b1ddbe2 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 13:39:45 +0200 Subject: [PATCH 72/80] Changed bincode version to 2.0.0-alpha.0 --- Cargo.toml | 4 ++-- derive/Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 595c444..5024204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ [package] name = "bincode" -version = "2.0.0-dev" # remember to update html_root_url and bincode_derive +version = "2.0.0-alpha.0" # remember to update html_root_url and bincode_derive authors = ["Ty Overby ", "Francesco Mazzoli ", "Zoey Riordan ", "Victor Koenders "] exclude = ["logo.svg", "examples/*", ".gitignore", ".github/"] @@ -30,7 +30,7 @@ atomic = [] derive = ["bincode_derive"] [dependencies] -bincode_derive = { path = "derive", version = "2.0.0-dev", optional = true } +bincode_derive = { path = "derive", version = "2.0.0-alpha.0", optional = true } serde = { version = "1.0.130", optional = true } # Used for tests diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 609a1df..e00e553 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bincode_derive" -version = "2.0.0-dev" # remember to update bincode +version = "2.0.0-alpha.0" # remember to update bincode authors = ["Zoey Riordan ", "Victor Koenders "] edition = "2018" diff --git a/src/lib.rs b/src/lib.rs index 5df6810..17ca796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ //! |derive| Yes |||Enables the `Encode` and `Decode` derive macro| //! |serde | No ||`serde_decode_from[_with_config]`, `serde_encode_into[_with_config]`|Also enables `_to_vec` when `alloc` is enabled| -#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-dev")] +#![doc(html_root_url = "https://docs.rs/bincode/2.0.0-alpha.0")] #![crate_name = "bincode"] #![crate_type = "rlib"] #![crate_type = "dylib"] From 707d0d238ffd1030b0ba71e5e7d9edec257f234b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 14:19:40 +0200 Subject: [PATCH 73/80] Made all encode and decode functions always require a Config, removed _with_config functions --- benches/varint.rs | 32 +++++++++++++++---------------- docs/spec.md | 16 ++++++++-------- src/features/impl_alloc.rs | 14 +++----------- src/features/impl_std.rs | 28 +++++++++------------------ src/lib.rs | 39 ++++++++++---------------------------- tests/alloc.rs | 5 +++-- tests/basic_types.rs | 18 +++++++++++------- tests/derive.rs | 31 ++++++++++++++++++++---------- tests/serde.rs | 7 +++++-- tests/std.rs | 17 ++++++++++------- tests/utils.rs | 4 ++-- 11 files changed, 98 insertions(+), 113 deletions(-) diff --git a/benches/varint.rs b/benches/varint.rs index fcaf998..6f18bfc 100644 --- a/benches/varint.rs +++ b/benches/varint.rs @@ -10,11 +10,11 @@ fn slice_varint_u8(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("slice_varint_u8", |b| { b.iter(|| { - let _: Vec = bincode::decode_with_config(&bytes, config).unwrap(); + let _: Vec = bincode::decode_from_slice(&bytes, config).unwrap(); }) }); } @@ -26,11 +26,11 @@ fn slice_varint_u16(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("slice_varint_u16", |b| { b.iter(|| { - let _: Vec = bincode::decode_with_config(&bytes, config).unwrap(); + let _: Vec = bincode::decode_from_slice(&bytes, config).unwrap(); }) }); } @@ -42,11 +42,11 @@ fn slice_varint_u32(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("slice_varint_u32", |b| { b.iter(|| { - let _: Vec = bincode::decode_with_config(&bytes, config).unwrap(); + let _: Vec = bincode::decode_from_slice(&bytes, config).unwrap(); }) }); } @@ -58,11 +58,11 @@ fn slice_varint_u64(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("slice_varint_u64", |b| { b.iter(|| { - let _: Vec = bincode::decode_with_config(&bytes, config).unwrap(); + let _: Vec = bincode::decode_from_slice(&bytes, config).unwrap(); }) }); } @@ -74,12 +74,12 @@ fn bufreader_varint_u8(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("bufreader_varint_u8", |b| { b.iter(|| { let _: Vec = - bincode::decode_from_with_config(&mut std::io::BufReader::new(&bytes[..]), config) + bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config) .unwrap(); }) }); @@ -92,12 +92,12 @@ fn bufreader_varint_u16(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("bufreader_varint_u16", |b| { b.iter(|| { let _: Vec = - bincode::decode_from_with_config(&mut std::io::BufReader::new(&bytes[..]), config) + bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config) .unwrap(); }) }); @@ -110,12 +110,12 @@ fn bufreader_varint_u32(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("bufreader_varint_u32", |b| { b.iter(|| { let _: Vec = - bincode::decode_from_with_config(&mut std::io::BufReader::new(&bytes[..]), config) + bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config) .unwrap(); }) }); @@ -128,12 +128,12 @@ fn bufreader_varint_u64(c: &mut Criterion) { .take(10_000) .collect(); let config = Configuration::standard(); - let bytes = bincode::encode_to_vec_with_config(&input, config).unwrap(); + let bytes = bincode::encode_to_vec(&input, config).unwrap(); c.bench_function("bufreader_varint_u64", |b| { b.iter(|| { let _: Vec = - bincode::decode_from_with_config(&mut std::io::BufReader::new(&bytes[..]), config) + bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config) .unwrap(); }) }); diff --git a/docs/spec.md b/docs/spec.md index 6cd8471..316477b 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -21,7 +21,7 @@ All tuples have no additional bytes, and are encoded in their specified order, e use bincode::config::Configuration; let tuple = (u32::min_value(), i32::max_value()); // 8 bytes -let encoded = bincode::encode_to_vec_with_config(tuple, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(tuple, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 0, 0, 0, 0, // 4 bytes for first type: u32 255, 255, 255, 127 // 4 bytes for second type: i32 @@ -69,21 +69,21 @@ pub enum SomeEnum { } // SomeEnum::A -let encoded = bincode::encode_to_vec_with_config(SomeEnum::A, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(SomeEnum::A, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 0, 0, 0, 0, // first variant, A // no extra bytes because A has no fields ]); // SomeEnum::B(0) -let encoded = bincode::encode_to_vec_with_config(SomeEnum::B(0), Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(SomeEnum::B(0), Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 1, 0, 0, 0, // first variant, B 0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes ]); // SomeEnum::C { value: 0u32 } -let encoded = bincode::encode_to_vec_with_config(SomeEnum::C { value: 0u32 }, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(SomeEnum::C { value: 0u32 }, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 2, 0, 0, 0, // first variant, C 0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes @@ -104,7 +104,7 @@ let list = vec![ 2u8 ]; -let encoded = bincode::encode_to_vec_with_config(list, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(list, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 3, 0, 0, 0, 0, 0, 0, 0, // length of 3u64 0, // entry 0 @@ -124,7 +124,7 @@ use bincode::config::Configuration; let str = "Hello"; // Could also be `String::new(...)` -let encoded = bincode::encode_to_vec_with_config(str, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(str, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 5, 0, 0, 0, 0, 0, 0, 0, // length of the string, 5 bytes b'H', b'e', b'l', b'l', b'o' @@ -139,7 +139,7 @@ Arrays are encoded *with* a length by default. use bincode::config::Configuration; let arr: [u8; 5] = [10, 20, 30, 40, 50]; -let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(arr, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 5, 0, 0, 0, 0, 0, 0, 0, // The length, as a u64 10, 20, 30, 40, 50, // the bytes @@ -168,7 +168,7 @@ let arr: [Foo; 2] = [ }, ]; -let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap(); +let encoded = bincode::encode_to_vec(arr, Configuration::legacy()).unwrap(); assert_eq!(encoded.as_slice(), &[ 2, 0, 0, 0, 0, 0, 0, 0, // Length of the array 10, 20, // First Foo diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index fd701c1..f33a786 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -1,5 +1,4 @@ use crate::{ - config, de::{Decode, Decoder}, enc::{self, Encode, Encoder}, error::{DecodeError, EncodeError}, @@ -21,18 +20,11 @@ impl enc::write::Writer for VecWriter { } } -/// Encode the given value into a `Vec`. -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -pub fn encode_to_vec(val: E) -> Result, EncodeError> { - encode_to_vec_with_config(val, config::Configuration::standard()) -} - /// Encode the given value into a `Vec` with the given `Config`. See the [config] module for more information. +/// +/// [config]: config/index.html #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -pub fn encode_to_vec_with_config( - val: E, - config: C, -) -> Result, EncodeError> { +pub fn encode_to_vec(val: E, config: C) -> Result, EncodeError> { let writer = VecWriter::default(); let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config); val.encode(&mut encoder)?; diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 37888cc..24c8028 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -1,5 +1,5 @@ use crate::{ - config::{self, Config}, + config::Config, de::{read::Reader, BorrowDecode, BorrowDecoder, Decode, Decoder, DecoderImpl}, enc::{write::Writer, Encode, Encoder, EncoderImpl}, error::{DecodeError, EncodeError}, @@ -13,17 +13,13 @@ use std::{ time::SystemTime, }; -/// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn decode_from(src: &mut R) -> Result { - decode_from_with_config(src, config::Configuration::standard()) -} - /// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`. /// /// See the [config] module for more information about config options. +/// +/// [config]: config/index.html #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn decode_from_with_config( +pub fn decode_from_reader( src: &mut R, _config: C, ) -> Result { @@ -41,18 +37,12 @@ impl Reader for R { } } -/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`. +/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. +/// See the [config] module for more information. +/// +/// [config]: config/index.html #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn encode_into_write( - val: E, - dst: &mut W, -) -> Result { - encode_into_write_with_config(val, dst, config::Configuration::standard()) -} - -/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information. -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn encode_into_write_with_config( +pub fn encode_into_writer( val: E, dst: &mut W, config: C, diff --git a/src/lib.rs b/src/lib.rs index 17ca796..eca7d75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,11 +15,11 @@ //! //! |Name |Default?|Supported types for Encode/Decode|Enabled methods |Other| //! |------|--------|-----------------------------------------|-----------------------------------------------------------------|-----| -//! |std | Yes ||`decode_from[_with_config]` and `encode_into_write[_with_config]`| -//! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec[_with_config]`| +//! |std | Yes ||`decode_from_reader` and `encode_into_writer`| +//! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec`| //! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`|| //! |derive| Yes |||Enables the `Encode` and `Decode` derive macro| -//! |serde | No ||`serde_decode_from[_with_config]`, `serde_encode_into[_with_config]`|Also enables `_to_vec` when `alloc` is enabled| +//! |serde | No |TODO|TODO|TODO| #![doc(html_root_url = "https://docs.rs/bincode/2.0.0-alpha.0")] #![crate_name = "bincode"] @@ -43,22 +43,12 @@ pub mod error; use config::Config; -/// Encode the given value into the given slice. Returns the amount of bytes that have been written. -/// -/// Will take the [standard] configuration. See the [config] module for more information. -/// -/// [standard]: config/struct.Configuration.html#method.standard -pub fn encode_into_slice( - val: E, - dst: &mut [u8], -) -> Result { - encode_into_slice_with_config(val, dst, config::Configuration::standard()) -} - /// Encode the given value into the given slice. Returns the amount of bytes that have been written. /// /// See the [config] module for more information on configurations. -pub fn encode_into_slice_with_config( +/// +/// [config]: config/index.html +pub fn encode_into_slice( val: E, dst: &mut [u8], config: C, @@ -69,22 +59,13 @@ pub fn encode_into_slice_with_config( Ok(encoder.into_writer().bytes_written()) } -/// Attempt to decode a given type `D` from the given slice. -/// -/// Will take the [Default] configuration. See the [config] module for more information. -/// -/// [Default]: config/struct.Default.html -pub fn decode<'__de, D: de::BorrowDecode<'__de>>( - src: &'__de [u8], -) -> Result { - decode_with_config(src, config::Configuration::standard()) -} - /// Attempt to decode a given type `D` from the given slice. /// /// See the [config] module for more information on configurations. -pub fn decode_with_config<'__de, D: de::BorrowDecode<'__de>, C: Config>( - src: &'__de [u8], +/// +/// [config]: config/index.html +pub fn decode_from_slice<'a, D: de::BorrowDecode<'a>, C: Config>( + src: &'a [u8], _config: C, ) -> Result { let reader = de::read::SliceReader::new(src); diff --git a/tests/alloc.rs b/tests/alloc.rs index b8d17cf..baad469 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -9,6 +9,7 @@ use alloc::collections::*; use alloc::rc::Rc; #[cfg(feature = "atomic")] use alloc::sync::Arc; +use bincode::config::Configuration; use utils::{the_same, the_same_with_comparer}; struct Foo { @@ -40,10 +41,10 @@ impl bincode::de::Decode for Foo { #[test] fn test_vec() { - let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }).unwrap(); + let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }, Configuration::standard()).unwrap(); assert_eq!(vec, &[5, 10]); - let foo: Foo = bincode::decode(&vec).unwrap(); + let foo: Foo = bincode::decode_from_slice(&vec, Configuration::standard()).unwrap(); assert_eq!(foo.a, 5); assert_eq!(foo.b, 10); } diff --git a/tests/basic_types.rs b/tests/basic_types.rs index 7bb100b..8b8d4e8 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,5 +1,6 @@ mod utils; +use bincode::config::Configuration; use core::cell::{Cell, RefCell}; use core::ops::Bound; use core::time::Duration; @@ -119,7 +120,7 @@ fn test_refcell_already_borrowed() { let _mutable_guard = cell.borrow_mut(); // now try to encode it let mut slice = [0u8; 10]; - let result = bincode::encode_into_slice(&cell, &mut slice) + let result = bincode::encode_into_slice(&cell, &mut slice, Configuration::standard()) .expect_err("Encoding a borrowed refcell should fail"); match result { @@ -132,10 +133,11 @@ fn test_refcell_already_borrowed() { fn test_slice() { let mut buffer = [0u8; 32]; let input: &[u8] = &[1, 2, 3, 4, 5, 6, 7]; - bincode::encode_into_slice(input, &mut buffer).unwrap(); + bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap(); assert_eq!(&buffer[..8], &[7, 1, 2, 3, 4, 5, 6, 7]); - let output: &[u8] = bincode::decode(&mut buffer[..8]).unwrap(); + let output: &[u8] = + bincode::decode_from_slice(&mut buffer[..8], Configuration::standard()).unwrap(); assert_eq!(input, output); } @@ -143,13 +145,14 @@ fn test_slice() { fn test_str() { let mut buffer = [0u8; 32]; let input: &str = "Hello world"; - bincode::encode_into_slice(input, &mut buffer).unwrap(); + bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap(); assert_eq!( &buffer[..12], &[11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100] ); - let output: &str = bincode::decode(&mut buffer[..12]).unwrap(); + let output: &str = + bincode::decode_from_slice(&mut buffer[..12], Configuration::standard()).unwrap(); assert_eq!(input, output); } @@ -157,9 +160,10 @@ fn test_str() { fn test_array() { let mut buffer = [0u8; 32]; let input: [u8; 10] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; - bincode::encode_into_slice(input, &mut buffer).unwrap(); + bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap(); assert_eq!(&buffer[..10], &[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]); - let output: [u8; 10] = bincode::decode(&mut buffer[..10]).unwrap(); + let output: [u8; 10] = + bincode::decode_from_slice(&mut buffer[..10], Configuration::standard()).unwrap(); assert_eq!(input, output); } diff --git a/tests/derive.rs b/tests/derive.rs index 419b120..6c8ff6c 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,5 +1,6 @@ #![cfg(feature = "derive")] +use bincode::config::Configuration; use bincode::{de::Decode, enc::Encode}; #[derive(bincode::Encode, PartialEq, Debug)] @@ -48,7 +49,8 @@ fn test_encode() { c: 20u8, }; let mut slice = [0u8; 1024]; - let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + let bytes_written = + bincode::encode_into_slice(start, &mut slice, Configuration::standard()).unwrap(); assert_eq!(bytes_written, 3); assert_eq!(&slice[..bytes_written], &[10, 10, 20]); } @@ -62,7 +64,8 @@ fn test_decode() { c: 1024u32, }; let slice = [5, 10, 251, 0, 4]; - let result: Test2 = bincode::decode_from(&mut slice.as_ref()).unwrap(); + let result: Test2 = + bincode::decode_from_reader(&mut slice.as_ref(), Configuration::standard()).unwrap(); assert_eq!(result, start); } @@ -70,7 +73,8 @@ fn test_decode() { fn test_encode_tuple() { let start = TestTupleStruct(5, 10, 1024); let mut slice = [0u8; 1024]; - let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + let bytes_written = + bincode::encode_into_slice(start, &mut slice, Configuration::standard()).unwrap(); assert_eq!(bytes_written, 5); assert_eq!(&slice[..bytes_written], &[5, 10, 251, 0, 4]); } @@ -79,7 +83,8 @@ fn test_encode_tuple() { fn test_decode_tuple() { let start = TestTupleStruct(5, 10, 1024); let mut slice = [5, 10, 251, 0, 4]; - let result: TestTupleStruct = bincode::decode(&mut slice).unwrap(); + let result: TestTupleStruct = + bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap(); assert_eq!(result, start); } @@ -87,7 +92,8 @@ fn test_decode_tuple() { fn test_encode_enum_struct_variant() { let start = TestEnum::Bar { name: 5u32 }; let mut slice = [0u8; 1024]; - let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + let bytes_written = + bincode::encode_into_slice(start, &mut slice, Configuration::standard()).unwrap(); assert_eq!(bytes_written, 2); assert_eq!(&slice[..bytes_written], &[1, 5]); } @@ -96,7 +102,8 @@ fn test_encode_enum_struct_variant() { fn test_decode_enum_struct_variant() { let start = TestEnum::Bar { name: 5u32 }; let mut slice = [1, 5]; - let result: TestEnum = bincode::decode(&mut slice).unwrap(); + let result: TestEnum = + bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap(); assert_eq!(result, start); } @@ -104,7 +111,8 @@ fn test_decode_enum_struct_variant() { fn test_encode_enum_tuple_variant() { let start = TestEnum::Baz(5, 10, 1024); let mut slice = [0u8; 1024]; - let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + let bytes_written = + bincode::encode_into_slice(start, &mut slice, Configuration::standard()).unwrap(); assert_eq!(bytes_written, 6); assert_eq!(&slice[..bytes_written], &[2, 5, 10, 251, 0, 4]); } @@ -113,7 +121,8 @@ fn test_encode_enum_tuple_variant() { fn test_decode_enum_unit_variant() { let start = TestEnum::Foo; let mut slice = [0]; - let result: TestEnum = bincode::decode(&mut slice).unwrap(); + let result: TestEnum = + bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap(); assert_eq!(result, start); } @@ -121,7 +130,8 @@ fn test_decode_enum_unit_variant() { fn test_encode_enum_unit_variant() { let start = TestEnum::Foo; let mut slice = [0u8; 1024]; - let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap(); + let bytes_written = + bincode::encode_into_slice(start, &mut slice, Configuration::standard()).unwrap(); assert_eq!(bytes_written, 1); assert_eq!(&slice[..bytes_written], &[0]); } @@ -130,6 +140,7 @@ fn test_encode_enum_unit_variant() { fn test_decode_enum_tuple_variant() { let start = TestEnum::Baz(5, 10, 1024); let mut slice = [2, 5, 10, 251, 0, 4]; - let result: TestEnum = bincode::decode(&mut slice).unwrap(); + let result: TestEnum = + bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap(); assert_eq!(result, start); } diff --git a/tests/serde.rs b/tests/serde.rs index c0dedd9..17705b1 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -1,5 +1,6 @@ #![cfg(all(feature = "serde", feature = "alloc", feature = "derive"))] +use bincode::config::Configuration; use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, bincode::Encode, bincode::Decode)] @@ -20,9 +21,11 @@ fn test_serde_round_trip() { assert_eq!(result.b, 0); // validate bincode working - let bytes = bincode::encode_to_vec(SerdeRoundtrip { a: 15, b: 15 }).unwrap(); + let bytes = + bincode::encode_to_vec(SerdeRoundtrip { a: 15, b: 15 }, Configuration::standard()).unwrap(); assert_eq!(bytes, &[15, 15]); - let result: SerdeRoundtrip = bincode::decode(&bytes).unwrap(); + let result: SerdeRoundtrip = + bincode::decode_from_slice(&bytes, Configuration::standard()).unwrap(); assert_eq!(result.a, 15); assert_eq!(result.b, 15); } diff --git a/tests/std.rs b/tests/std.rs index 09eff68..7223d9c 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -2,6 +2,7 @@ mod utils; +use bincode::config::Configuration; use std::{ ffi::{CStr, CString}, io::{Cursor, Seek, SeekFrom}, @@ -43,7 +44,7 @@ impl bincode::de::Decode for Foo { #[test] fn test_std_cursor() { let mut cursor = Cursor::<&[u8]>::new(&[5, 10]); - let foo: Foo = bincode::decode_from(&mut cursor).unwrap(); + let foo: Foo = bincode::decode_from_reader(&mut cursor, Configuration::standard()).unwrap(); assert_eq!(foo.a, 5); assert_eq!(foo.b, 10); @@ -53,11 +54,13 @@ fn test_std_cursor() { fn test_std_file() { let mut file = tempfile::tempfile().expect("Could not create temp file"); - let bytes_written = bincode::encode_into_write(Foo { a: 30, b: 50 }, &mut file).unwrap(); + let bytes_written = + bincode::encode_into_writer(Foo { a: 30, b: 50 }, &mut file, Configuration::standard()) + .unwrap(); assert_eq!(bytes_written, 2); file.seek(SeekFrom::Start(0)).unwrap(); - let foo: Foo = bincode::decode_from(&mut file).unwrap(); + let foo: Foo = bincode::decode_from_reader(&mut file, Configuration::standard()).unwrap(); assert_eq!(foo.a, 30); assert_eq!(foo.b, 50); @@ -96,13 +99,13 @@ fn test_std_commons() { // &CStr let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); - let len = bincode::encode_into_slice_with_config(cstr, &mut buffer, config).unwrap(); - let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + let len = bincode::encode_into_slice(cstr, &mut buffer, config).unwrap(); + let decoded: &CStr = bincode::decode_from_slice(&mut buffer[..len], config).unwrap(); assert_eq!(cstr, decoded); // Path let path = Path::new("C:/Program Files/Foo"); - let len = bincode::encode_into_slice_with_config(path, &mut buffer, config).unwrap(); - let decoded: &Path = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); + let len = bincode::encode_into_slice(path, &mut buffer, config).unwrap(); + let decoded: &Path = bincode::decode_from_slice(&mut buffer[..len], config).unwrap(); assert_eq!(path, decoded); } diff --git a/tests/utils.rs b/tests/utils.rs index f0c4316..015ab1b 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -8,14 +8,14 @@ where CMP: Fn(&V, &V) -> bool, { let mut buffer = [0u8; 2048]; - let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap(); + let len = bincode::encode_into_slice(&element, &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", element, &buffer[..len], core::any::type_name::() ); - let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); + let decoded: V = bincode::decode_from_slice(&mut buffer, config).unwrap(); assert!( cmp(&element, &decoded), From dae645f675a3d6c2b60b7fb6d85ebb2b3e64369b Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 14:27:03 +0200 Subject: [PATCH 74/80] Joined the 2 Sealed traits into a single one --- src/de/decoder.rs | 3 +-- src/de/mod.rs | 17 ++++++----------- src/enc/encoder.rs | 4 ++-- src/enc/mod.rs | 12 +++--------- src/lib.rs | 1 + src/utils.rs | 3 +++ 6 files changed, 16 insertions(+), 24 deletions(-) create mode 100644 src/utils.rs diff --git a/src/de/decoder.rs b/src/de/decoder.rs index fddc399..df9756a 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,9 +1,8 @@ use super::{ read::{BorrowReader, Reader}, - sealed::Sealed, BorrowDecoder, Decoder, }; -use crate::config::Config; +use crate::{config::Config, utils::Sealed}; /// A Decoder that reads bytes from a given reader `R`. /// diff --git a/src/de/mod.rs b/src/de/mod.rs index 14a4e32..95b28ba 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,15 +1,16 @@ //! Decoder-based structs and traits. -use crate::{config::Config, error::DecodeError}; - mod decoder; mod impl_core; mod impl_tuples; mod impls; -pub mod read; -pub use self::decoder::DecoderImpl; use self::read::{BorrowReader, Reader}; +use crate::{config::Config, error::DecodeError, utils::Sealed}; + +pub mod read; + +pub use self::decoder::DecoderImpl; /// Trait that makes a type able to be decoded, akin to serde's `DeserializeOwned` trait. /// @@ -36,7 +37,7 @@ impl<'de, T: Decode> BorrowDecode<'de> for T { } /// Any source that can decode basic types. This type is most notably implemented for [Decoder]. -pub trait Decoder: sealed::Sealed { +pub trait Decoder: Sealed { /// The concrete [Reader] type type R: Reader; @@ -88,9 +89,3 @@ where T::borrow_reader(self) } } - -pub(crate) mod sealed { - pub trait Sealed {} - - impl<'a, T> Sealed for &'a mut T where T: Sealed {} -} diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 8525b83..58a8605 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,7 +1,7 @@ //! Contains -use super::{sealed::Sealed, write::Writer, Encoder}; -use crate::config::Config; +use super::{write::Writer, Encoder}; +use crate::{config::Config, utils::Sealed}; /// An Encoder that writes bytes into a given writer `W`. /// diff --git a/src/enc/mod.rs b/src/enc/mod.rs index e859ffb..bf989b1 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -4,12 +4,12 @@ mod encoder; mod impl_tuples; mod impls; -use crate::{config::Config, error::EncodeError}; +use self::write::Writer; +use crate::{config::Config, error::EncodeError, utils::Sealed}; pub mod write; pub use self::encoder::EncoderImpl; -use self::write::Writer; /// Any source that can encode types. This type is most notably implemented for [Encoder]. /// @@ -20,7 +20,7 @@ pub trait Encode { } /// Helper trait to encode basic types into. -pub trait Encoder: sealed::Sealed { +pub trait Encoder: Sealed { /// The concrete [Writer] type type W: Writer; @@ -50,9 +50,3 @@ where T::config(self) } } - -pub(crate) mod sealed { - pub trait Sealed {} - - impl<'a, T> Sealed for &'a mut T where T: Sealed {} -} diff --git a/src/lib.rs b/src/lib.rs index eca7d75..6b40163 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ extern crate alloc; extern crate std; mod features; +pub(crate) mod utils; pub(crate) mod varint; pub use features::*; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..1433256 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,3 @@ +pub trait Sealed {} + +impl<'a, T> Sealed for &'a mut T where T: Sealed {} From bd994e354d4feb909877172d3f3e3cfa662131e7 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 14:45:16 +0200 Subject: [PATCH 75/80] Updated documentation of Encode, added an example to lib.rs --- src/de/mod.rs | 4 ++++ src/enc/encoder.rs | 2 -- src/enc/mod.rs | 4 ++-- src/lib.rs | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index 95b28ba..05d4747 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -17,6 +17,8 @@ pub use self::decoder::DecoderImpl; /// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [BorrowDecode] instead. /// /// Whenever you implement `Decode` for your type, the base trait `BorrowDecode` is automatically implemented. +/// +/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to your type. Note that if the type contains any lifetimes, `BorrowDecode` will be implemented instead. pub trait Decode: for<'de> BorrowDecode<'de> { /// Attempt to decode this type with the given [Decode]. fn decode(decoder: D) -> Result; @@ -25,6 +27,8 @@ pub trait Decode: for<'de> BorrowDecode<'de> { /// Trait that makes a type able to be decoded, akin to serde's `Deserialize` trait. /// /// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [Decode] instead. +/// +/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to a type with a lifetime. pub trait BorrowDecode<'de>: Sized { /// Attempt to decode this type with the given [BorrowDecode]. fn borrow_decode>(decoder: D) -> Result; diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 58a8605..f2c83f9 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -1,5 +1,3 @@ -//! Contains - use super::{write::Writer, Encoder}; use crate::{config::Config, utils::Sealed}; diff --git a/src/enc/mod.rs b/src/enc/mod.rs index bf989b1..6f58012 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -11,9 +11,9 @@ pub mod write; pub use self::encoder::EncoderImpl; -/// Any source that can encode types. This type is most notably implemented for [Encoder]. +/// Any source that can be encoded. This trait should be implemented for all types that you want to be able to use with any of the `encode_with` methods. /// -/// [Encoder]: ../struct.Encoder.html +/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Encode)]` to your trait. pub trait Encode { /// Encode a given type. fn encode(&self, encoder: E) -> Result<(), EncodeError>; diff --git a/src/lib.rs b/src/lib.rs index 6b40163..adae6b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,39 @@ //! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`|| //! |derive| Yes |||Enables the `Encode` and `Decode` derive macro| //! |serde | No |TODO|TODO|TODO| +//! +//! # Example +//! +//! ```rust +//! use bincode::config::Configuration; +//! +//! let mut slice = [0u8; 100]; +//! +//! // You can encode any type that implements `enc::Encode`. +//! // You can automatically implement this trait on custom types with the `derive` feature. +//! let input = ( +//! 0u8, +//! 10u32, +//! 10000i128, +//! 'a', +//! [0u8, 1u8, 2u8, 3u8] +//! ); +//! +//! let length = bincode::encode_into_slice( +//! input, +//! &mut slice, +//! Configuration::standard() +//! ).unwrap(); +//! +//! let slice = &slice[..length]; +//! println!("Bytes written: {:?}", slice); +//! +//! // Decoding works the same as encoding. +//! // The trait used is `de::Decode`, and can also be automatically implemented with the `derive` feature. +//! let decoded: (u8, u32, i128, char, [u8; 4]) = bincode::decode_from_slice(slice, Configuration::standard()).unwrap(); +//! +//! assert_eq!(decoded, input); +//! ``` #![doc(html_root_url = "https://docs.rs/bincode/2.0.0-alpha.0")] #![crate_name = "bincode"] From 0be7e2f4f237e951d18d14a4599434ff5e04bc77 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Thu, 21 Oct 2021 17:34:56 +0200 Subject: [PATCH 76/80] Updated to edition 2021 --- Cargo.toml | 2 +- derive/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5024204..26e6fe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ keywords = ["binary", "encode", "decode", "serialize", "deserialize"] license = "MIT" description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!" -edition = "2018" +edition = "2021" [features] default = ["std", "derive", "atomic"] diff --git a/derive/Cargo.toml b/derive/Cargo.toml index e00e553..c3a6ec3 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -2,7 +2,7 @@ name = "bincode_derive" version = "2.0.0-alpha.0" # remember to update bincode authors = ["Zoey Riordan ", "Victor Koenders "] -edition = "2018" +edition = "2021" repository = "https://github.com/bincode-org/bincode" documentation = "https://docs.rs/bincode_derive" From 539906f441b53503c4f66fc89f182ba719f1e447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Fri, 22 Oct 2021 14:47:05 +0200 Subject: [PATCH 77/80] Optimize performance of slice writing --- src/enc/write.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/enc/write.rs b/src/enc/write.rs index e5e16a2..dc57096 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -26,33 +26,35 @@ pub trait Writer { /// ``` pub struct SliceWriter<'storage> { slice: &'storage mut [u8], - idx: usize, + original_length: usize, } impl<'storage> SliceWriter<'storage> { /// Create a new instance of `SliceWriter` with the given byte array. pub fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> { + let original = bytes.len(); SliceWriter { slice: bytes, - idx: 0, + original_length: original, } } /// Return the amount of bytes written so far. pub fn bytes_written(&self) -> usize { - self.idx + self.original_length - self.slice.len() } } impl<'storage> Writer for SliceWriter<'storage> { + #[inline(always)] fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { - let remaining = &mut self.slice[self.idx..]; - if bytes.len() > remaining.len() { + if bytes.len() > self.slice.len() { return Err(EncodeError::UnexpectedEnd); } - self.idx += bytes.len(); - let write_slice = &mut remaining[..bytes.len()]; - write_slice.copy_from_slice(bytes); + let (a, b) = core::mem::replace(&mut self.slice, &mut []).split_at_mut(bytes.len()); + a.copy_from_slice(&bytes[..]); + self.slice = b; + Ok(()) } } From 62b8f39f8fed119223879049a3843b9bfe07df79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Fri, 22 Oct 2021 14:47:44 +0200 Subject: [PATCH 78/80] Optimize performance of decoding u8 arrays --- src/de/impls.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index 9a738ed..2729878 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -10,6 +10,7 @@ use crate::{ error::{DecodeError, IntegerType}, }; use core::{ + any::TypeId, cell::{Cell, RefCell}, num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, @@ -384,7 +385,7 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str { impl Decode for [T; N] where - T: Decode + Sized, + T: Decode + Sized + 'static, { fn decode(mut decoder: D) -> Result { if !D::C::SKIP_FIXED_ARRAY_LENGTH { @@ -397,12 +398,24 @@ where } } - let result = - super::impl_core::collect_into_array(&mut (0..N).map(|_| T::decode(&mut decoder))); + if TypeId::of::() == TypeId::of::() { + let mut buf = [0u8; N]; + decoder.reader().read(&mut buf)?; + let ptr = &mut buf as *mut _ as *mut [T; N]; - // result is only None if N does not match the values of `(0..N)`, which it always should - // So this unsafe should never occur - result.unwrap() + // Safety: we know that T is a u8, so it is perfectly safe to + // translate an array of u8 into an array of T + let res = unsafe { ptr.read() }; + core::mem::forget(buf); + Ok(res) + } else { + let result = + super::impl_core::collect_into_array(&mut (0..N).map(|_| T::decode(&mut decoder))); + + // result is only None if N does not match the values of `(0..N)`, which it always should + // So this unsafe should never occur + result.unwrap() + } } } From 99de47a6c87b0c307108f3c316c671518fe0f3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Sun, 24 Oct 2021 16:44:36 +0200 Subject: [PATCH 79/80] Reintroduce varint optimizations --- src/de/impls.rs | 13 +- src/de/read.rs | 42 +++++ src/error.rs | 2 + src/features/impl_std.rs | 40 ++++- src/lib.rs | 30 ++++ src/varint/decode_unsigned.rs | 322 ++++++++++++++++++++++++++++------ tests/derive.rs | 2 +- tests/std.rs | 6 +- 8 files changed, 388 insertions(+), 69 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index 2729878..acddebe 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -31,10 +31,17 @@ impl Decode for bool { } impl Decode for u8 { + #[inline] fn decode(mut decoder: D) -> Result { - let mut bytes = [0u8; 1]; - decoder.reader().read(&mut bytes)?; - Ok(bytes[0]) + if let Some(buf) = decoder.reader().peek_read(1) { + let byte = buf[0]; + decoder.reader().consume(1); + Ok(byte) + } else { + let mut bytes = [0u8; 1]; + decoder.reader().read(&mut bytes)?; + Ok(bytes[0]) + } } } diff --git a/src/de/read.rs b/src/de/read.rs index 196d6d3..228518a 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -17,6 +17,38 @@ use crate::error::DecodeError; pub trait Reader { /// Fill the given `bytes` argument with values. Exactly the length of the given slice must be filled, or else an error must be returned. fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>; + + /// If this reader wraps a buffer of any kind, this function lets callers access contents of + /// the buffer without passing data through a buffer first. + #[inline] + fn peek_read(&self, _: usize) -> Option<&[u8]> { + None + } + + /// If an implementation of `peek_read` is provided, an implementation of this function + /// must be provided so that subsequent reads or peek-reads do not return the same bytes + #[inline] + fn consume(&mut self, _: usize) {} +} + +impl<'a, T> Reader for &'a mut T +where + T: Reader, +{ + #[inline] + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { + (**self).read(bytes) + } + + #[inline] + fn peek_read(&self, n: usize) -> Option<&[u8]> { + (**self).peek_read(n) + } + + #[inline] + fn consume(&mut self, n: usize) { + (*self).consume(n) + } } /// A reader for borrowed data. Implementors of this must also implement the [Reader] trait. See the module documentation for more information. @@ -61,6 +93,16 @@ impl<'storage> Reader for SliceReader<'storage> { Ok(()) } + + #[inline] + fn peek_read(&self, n: usize) -> Option<&'storage [u8]> { + self.slice.get(..n) + } + + #[inline] + fn consume(&mut self, n: usize) { + self.slice = self.slice.get(n..).unwrap_or_default(); + } } impl<'storage> BorrowReader<'storage> for SliceReader<'storage> { diff --git a/src/error.rs b/src/error.rs index a1e85fb..856dc8a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -144,6 +144,8 @@ pub enum IntegerType { I64, I128, Isize, + + Reserved, } impl IntegerType { diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 24c8028..649c27c 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -7,6 +7,7 @@ use crate::{ use core::time::Duration; use std::{ ffi::{CStr, CString}, + io::Read, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, path::{Path, PathBuf}, sync::{Mutex, RwLock}, @@ -19,22 +20,52 @@ use std::{ /// /// [config]: config/index.html #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn decode_from_reader( +pub fn decode_from_std_read( src: &mut R, _config: C, ) -> Result { - let mut decoder = DecoderImpl::<_, C>::new(src, _config); + let reader = IoReader { reader: src }; + let mut decoder = DecoderImpl::<_, C>::new(reader, _config); D::decode(&mut decoder) } -impl Reader for R { +struct IoReader { + reader: R, +} + +impl Reader for IoReader +where + R: std::io::Read, +{ #[inline(always)] + fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { + match self.reader.read_exact(bytes) { + Ok(_) => Ok(()), + Err(_) => Err(DecodeError::UnexpectedEnd), + } + } +} + +impl Reader for std::io::BufReader +where + R: std::io::Read, +{ fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { match self.read_exact(bytes) { Ok(_) => Ok(()), Err(_) => Err(DecodeError::UnexpectedEnd), } } + + #[inline] + fn peek_read(&self, n: usize) -> Option<&[u8]> { + self.buffer().get(..n) + } + + #[inline] + fn consume(&mut self, n: usize) { + ::consume(self, n); + } } /// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. @@ -42,7 +73,7 @@ impl Reader for R { /// /// [config]: config/index.html #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -pub fn encode_into_writer( +pub fn encode_into_std_write( val: E, dst: &mut W, config: C, @@ -62,6 +93,7 @@ struct IoWriter<'a, W: std::io::Write> { } impl<'storage, W: std::io::Write> Writer for IoWriter<'storage, W> { + #[inline(always)] fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> { self.writer .write_all(bytes) diff --git a/src/lib.rs b/src/lib.rs index adae6b7..5403aec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,8 @@ mod features; pub(crate) mod utils; pub(crate) mod varint; +use de::read::Reader; +use enc::write::Writer; pub use features::*; pub mod config; @@ -93,6 +95,21 @@ pub fn encode_into_slice( Ok(encoder.into_writer().bytes_written()) } +/// Encode the given value into a custom [Writer]. +/// +/// See the [config] module for more information on configurations. +/// +/// [config]: config/index.html +pub fn encode_into_writer( + val: E, + writer: W, + config: C, +) -> Result<(), error::EncodeError> { + let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config); + val.encode(&mut encoder)?; + Ok(()) +} + /// Attempt to decode a given type `D` from the given slice. /// /// See the [config] module for more information on configurations. @@ -107,6 +124,19 @@ pub fn decode_from_slice<'a, D: de::BorrowDecode<'a>, C: Config>( D::borrow_decode(&mut decoder) } +/// Attempt to decode a given type `D` from the given [Reader]. +/// +/// See the [config] module for more information on configurations. +/// +/// [config]: config/index.html +pub fn decode_from_reader( + reader: R, + _config: C, +) -> Result { + let mut decoder = de::DecoderImpl::<_, C>::new(reader, _config); + D::decode(&mut decoder) +} + // TODO: Currently our doctests fail when trying to include the specs because the specs depend on `derive` and `alloc`. // But we want to have the specs in the docs always #[cfg(all(feature = "alloc", feature = "derive"))] diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index 7ecdb0e..d5574e0 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -1,14 +1,22 @@ -use super::{U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE}; +use core::{convert::TryInto, u32}; + +use super::{SINGLE_BYTE_MAX, U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE}; use crate::{ config::Endian, de::read::Reader, error::{DecodeError, IntegerType}, }; -pub fn varint_decode_u16(read: &mut R, endian: Endian) -> Result { - let mut byte = [0u8; 1]; - read.read(&mut byte)?; - match byte[0] { +#[inline(never)] +#[cold] +fn deserialize_varint_cold_u16(read: &mut R, endian: Endian) -> Result +where + R: Reader, +{ + let mut bytes = [0u8; 1]; + read.read(&mut bytes)?; + match bytes[0] { + byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u16), U16_BYTE => { let mut bytes = [0u8; 2]; read.read(&mut bytes)?; @@ -17,26 +25,23 @@ pub fn varint_decode_u16(read: &mut R, endian: Endian) -> Result u16::from_le_bytes(bytes), }) } - U32_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U16, - found: IntegerType::U32, - }), - U64_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U16, - found: IntegerType::U64, - }), - U128_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U16, - found: IntegerType::U128, - }), - x => Ok(x as u16), + U32_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U32), + U64_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U64), + U128_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U128), + _ => invalid_varint_discriminant(IntegerType::U16, IntegerType::Reserved), } } -pub fn varint_decode_u32(read: &mut R, endian: Endian) -> Result { - let mut byte = [0u8; 1]; - read.read(&mut byte)?; - match byte[0] { +#[inline(never)] +#[cold] +fn deserialize_varint_cold_u32(read: &mut R, endian: Endian) -> Result +where + R: Reader, +{ + let mut bytes = [0u8; 1]; + read.read(&mut bytes)?; + match bytes[0] { + byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u32), U16_BYTE => { let mut bytes = [0u8; 2]; read.read(&mut bytes)?; @@ -49,26 +54,26 @@ pub fn varint_decode_u32(read: &mut R, endian: Endian) -> Result u32::from_be_bytes(bytes), - Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes) as u32, + Endian::Little => u32::from_le_bytes(bytes) as u32, }) } - U64_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U32, - found: IntegerType::U64, - }), - U128_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U32, - found: IntegerType::U128, - }), - x => Ok(x as u32), + U64_BYTE => invalid_varint_discriminant(IntegerType::U32, IntegerType::U64), + U128_BYTE => invalid_varint_discriminant(IntegerType::U32, IntegerType::U128), + _ => invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved), } } -pub fn varint_decode_u64(read: &mut R, endian: Endian) -> Result { - let mut byte = [0u8; 1]; - read.read(&mut byte)?; - match byte[0] { +#[inline(never)] +#[cold] +fn deserialize_varint_cold_u64(read: &mut R, endian: Endian) -> Result +where + R: Reader, +{ + let mut bytes = [0u8; 1]; + read.read(&mut bytes)?; + match bytes[0] { + byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u64), U16_BYTE => { let mut bytes = [0u8; 2]; read.read(&mut bytes)?; @@ -89,22 +94,25 @@ pub fn varint_decode_u64(read: &mut R, endian: Endian) -> Result u64::from_be_bytes(bytes), - Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes) as u64, + Endian::Little => u64::from_le_bytes(bytes) as u64, }) } - U128_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::U64, - found: IntegerType::U128, - }), - x => Ok(x as u64), + U128_BYTE => invalid_varint_discriminant(IntegerType::U64, IntegerType::U128), + _ => invalid_varint_discriminant(IntegerType::U64, IntegerType::Reserved), } } -pub fn varint_decode_usize(read: &mut R, endian: Endian) -> Result { - let mut byte = [0u8; 1]; - read.read(&mut byte)?; - match byte[0] { +#[inline(never)] +#[cold] +fn deserialize_varint_cold_usize(read: &mut R, endian: Endian) -> Result +where + R: Reader, +{ + let mut bytes = [0u8; 1]; + read.read(&mut bytes)?; + match bytes[0] { + byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as usize), U16_BYTE => { let mut bytes = [0u8; 2]; read.read(&mut bytes)?; @@ -129,18 +137,21 @@ pub fn varint_decode_usize(read: &mut R, endian: Endian) -> Result u64::from_le_bytes(bytes) as usize, }) } - U128_BYTE => Err(DecodeError::InvalidIntegerType { - expected: IntegerType::Usize, - found: IntegerType::U128, - }), - x => Ok(x as usize), + U128_BYTE => invalid_varint_discriminant(IntegerType::Usize, IntegerType::U128), + _ => invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved), } } -pub fn varint_decode_u128(read: &mut R, endian: Endian) -> Result { - let mut byte = [0u8; 1]; - read.read(&mut byte)?; - match byte[0] { +#[inline(never)] +#[cold] +fn deserialize_varint_cold_u128(read: &mut R, endian: Endian) -> Result +where + R: Reader, +{ + let mut bytes = [0u8; 1]; + read.read(&mut bytes)?; + match bytes[0] { + byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u128), U16_BYTE => { let mut bytes = [0u8; 2]; read.read(&mut bytes)?; @@ -173,7 +184,202 @@ pub fn varint_decode_u128(read: &mut R, endian: Endian) -> Result u128::from_le_bytes(bytes), }) } - x => Ok(x as u128), + _ => invalid_varint_discriminant(IntegerType::U128, IntegerType::Reserved), + } +} + +#[inline(never)] +#[cold] +fn invalid_varint_discriminant( + expected: IntegerType, + found: IntegerType, +) -> Result { + Err(DecodeError::InvalidIntegerType { expected, found }) +} + +pub fn varint_decode_u16(read: &mut R, endian: Endian) -> Result { + if let Some(bytes) = read.peek_read(3) { + let (discriminant, bytes) = bytes.split_at(1); + let (out, used) = match discriminant[0] { + byte @ 0..=SINGLE_BYTE_MAX => (byte as u16, 1), + U16_BYTE => { + let val = match endian { + Endian::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()), + Endian::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()), + }; + + (val, 3) + } + U32_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U32), + U64_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U64), + U128_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U128), + _ => return invalid_varint_discriminant(IntegerType::U16, IntegerType::Reserved), + }; + + read.consume(used); + Ok(out) + } else { + deserialize_varint_cold_u16(read, endian) + } +} + +pub fn varint_decode_u32(read: &mut R, endian: Endian) -> Result { + if let Some(bytes) = read.peek_read(5) { + let (discriminant, bytes) = bytes.split_at(1); + let (out, used) = match discriminant[0] { + byte @ 0..=SINGLE_BYTE_MAX => (byte as u32, 1), + U16_BYTE => { + let val = match endian { + Endian::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()), + Endian::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()), + }; + + (val as u32, 3) + } + U32_BYTE => { + let val = match endian { + Endian::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()), + Endian::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()), + }; + + (val as u32, 5) + } + U64_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U64), + U128_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U128), + _ => return invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved), + }; + + read.consume(used); + Ok(out) + } else { + deserialize_varint_cold_u32(read, endian) + } +} + +pub fn varint_decode_u64(read: &mut R, endian: Endian) -> Result { + if let Some(bytes) = read.peek_read(9) { + let (discriminant, bytes) = bytes.split_at(1); + let (out, used) = match discriminant[0] { + byte @ 0..=SINGLE_BYTE_MAX => (byte as u64, 1), + U16_BYTE => { + let val = match endian { + Endian::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()), + Endian::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()), + }; + + (val as u64, 3) + } + U32_BYTE => { + let val = match endian { + Endian::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()), + Endian::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()), + }; + + (val as u64, 5) + } + U64_BYTE => { + let val = match endian { + Endian::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()), + Endian::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()), + }; + + (val as u64, 9) + } + U128_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U128), + _ => return invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved), + }; + + read.consume(used); + Ok(out) + } else { + deserialize_varint_cold_u64(read, endian) + } +} + +pub fn varint_decode_usize(read: &mut R, endian: Endian) -> Result { + if let Some(bytes) = read.peek_read(9) { + let (discriminant, bytes) = bytes.split_at(1); + let (out, used) = match discriminant[0] { + byte @ 0..=SINGLE_BYTE_MAX => (byte as usize, 1), + U16_BYTE => { + let val = match endian { + Endian::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()), + Endian::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()), + }; + + (val as usize, 3) + } + U32_BYTE => { + let val = match endian { + Endian::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()), + Endian::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()), + }; + + (val as usize, 5) + } + U64_BYTE => { + let val = match endian { + Endian::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()), + Endian::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()), + }; + + (val as usize, 9) + } + U128_BYTE => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::U128), + _ => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved), + }; + + read.consume(used); + Ok(out) + } else { + deserialize_varint_cold_usize(read, endian) + } +} + +pub fn varint_decode_u128(read: &mut R, endian: Endian) -> Result { + if let Some(bytes) = read.peek_read(17) { + let (discriminant, bytes) = bytes.split_at(1); + let (out, used) = match discriminant[0] { + byte @ 0..=SINGLE_BYTE_MAX => (byte as u128, 1), + U16_BYTE => { + let val = match endian { + Endian::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()), + Endian::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()), + }; + + (val as u128, 3) + } + U32_BYTE => { + let val = match endian { + Endian::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()), + Endian::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()), + }; + + (val as u128, 5) + } + U64_BYTE => { + let val = match endian { + Endian::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()), + Endian::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()), + }; + + (val as u128, 9) + } + U128_BYTE => { + let val = match endian { + Endian::Big => u128::from_be_bytes(bytes[..16].try_into().unwrap()), + Endian::Little => u128::from_le_bytes(bytes[..16].try_into().unwrap()), + }; + + (val as u128, 17) + } + _ => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved), + }; + + read.consume(used); + Ok(out) + } else { + deserialize_varint_cold_u128(read, endian) } } diff --git a/tests/derive.rs b/tests/derive.rs index 6c8ff6c..0ec0e49 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -65,7 +65,7 @@ fn test_decode() { }; let slice = [5, 10, 251, 0, 4]; let result: Test2 = - bincode::decode_from_reader(&mut slice.as_ref(), Configuration::standard()).unwrap(); + bincode::decode_from_std_read(&mut slice.as_ref(), Configuration::standard()).unwrap(); assert_eq!(result, start); } diff --git a/tests/std.rs b/tests/std.rs index 7223d9c..66b4e7b 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -44,7 +44,7 @@ impl bincode::de::Decode for Foo { #[test] fn test_std_cursor() { let mut cursor = Cursor::<&[u8]>::new(&[5, 10]); - let foo: Foo = bincode::decode_from_reader(&mut cursor, Configuration::standard()).unwrap(); + let foo: Foo = bincode::decode_from_std_read(&mut cursor, Configuration::standard()).unwrap(); assert_eq!(foo.a, 5); assert_eq!(foo.b, 10); @@ -55,12 +55,12 @@ fn test_std_file() { let mut file = tempfile::tempfile().expect("Could not create temp file"); let bytes_written = - bincode::encode_into_writer(Foo { a: 30, b: 50 }, &mut file, Configuration::standard()) + bincode::encode_into_std_write(Foo { a: 30, b: 50 }, &mut file, Configuration::standard()) .unwrap(); assert_eq!(bytes_written, 2); file.seek(SeekFrom::Start(0)).unwrap(); - let foo: Foo = bincode::decode_from_reader(&mut file, Configuration::standard()).unwrap(); + let foo: Foo = bincode::decode_from_std_read(&mut file, Configuration::standard()).unwrap(); assert_eq!(foo.a, 30); assert_eq!(foo.b, 50); From 382b2c7a8f1609b653fc9c7ab8f190163031b1fc Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 24 Oct 2021 18:06:16 +0200 Subject: [PATCH 80/80] Fixed clippy lint, removed function that was only used in 1 place --- src/de/impls.rs | 1 - src/de/read.rs | 17 ++++++----------- src/enc/write.rs | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index acddebe..4efff04 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -413,7 +413,6 @@ where // Safety: we know that T is a u8, so it is perfectly safe to // translate an array of u8 into an array of T let res = unsafe { ptr.read() }; - core::mem::forget(buf); Ok(res) } else { let result = diff --git a/src/de/read.rs b/src/de/read.rs index 228518a..b0f6cc3 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -69,16 +69,6 @@ impl<'storage> SliceReader<'storage> { pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { SliceReader { slice: bytes } } - - #[inline(always)] - fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8], DecodeError> { - if length > self.slice.len() { - return Err(DecodeError::UnexpectedEnd); - } - let (read_slice, remaining) = self.slice.split_at(length); - self.slice = remaining; - Ok(read_slice) - } } impl<'storage> Reader for SliceReader<'storage> { @@ -108,6 +98,11 @@ impl<'storage> Reader for SliceReader<'storage> { impl<'storage> BorrowReader<'storage> for SliceReader<'storage> { #[inline(always)] fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError> { - self.get_byte_slice(length) + if length > self.slice.len() { + return Err(DecodeError::UnexpectedEnd); + } + let (read_slice, remaining) = self.slice.split_at(length); + self.slice = remaining; + Ok(read_slice) } } diff --git a/src/enc/write.rs b/src/enc/write.rs index dc57096..7618830 100644 --- a/src/enc/write.rs +++ b/src/enc/write.rs @@ -52,7 +52,7 @@ impl<'storage> Writer for SliceWriter<'storage> { return Err(EncodeError::UnexpectedEnd); } let (a, b) = core::mem::replace(&mut self.slice, &mut []).split_at_mut(bytes.len()); - a.copy_from_slice(&bytes[..]); + a.copy_from_slice(bytes); self.slice = b; Ok(())