diff --git a/compatibility/src/membership.rs b/compatibility/src/membership.rs index 57801b0..121f04e 100644 --- a/compatibility/src/membership.rs +++ b/compatibility/src/membership.rs @@ -8,7 +8,7 @@ use std::collections::BTreeSet; type NodeId = u64; #[derive( - bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, + bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, )] #[bincode(crate = "bincode_2")] pub struct Membership { diff --git a/compatibility/src/rand.rs b/compatibility/src/rand.rs index cb0f4f0..4561afb 100644 --- a/compatibility/src/rand.rs +++ b/compatibility/src/rand.rs @@ -5,7 +5,7 @@ use rand::Rng; #[derive( - Debug, bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, PartialEq, + Debug, bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, PartialEq, Eq, )] #[bincode(crate = "bincode_2")] pub struct Lcg64Xsh32 { diff --git a/compatibility/src/sway.rs b/compatibility/src/sway.rs index c01d0f2..84167d4 100644 --- a/compatibility/src/sway.rs +++ b/compatibility/src/sway.rs @@ -25,7 +25,7 @@ fn random(rng: &mut impl Rng) -> FTXresponse { } } -#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)] #[bincode(crate = "bincode_2")] pub enum FTXresponse { Result(FTXresponseSuccess), @@ -33,7 +33,7 @@ pub enum FTXresponse { } #[derive( - bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, + bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, )] #[bincode(crate = "bincode_2")] pub struct FTXresponseSuccess { @@ -41,14 +41,14 @@ pub struct FTXresponseSuccess { pub result: T, } -#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)] #[bincode(crate = "bincode_2")] pub struct FTXresponseFailure { pub success: bool, pub error: String, } -#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)] #[bincode(crate = "bincode_2")] pub enum TradeSide { Buy, diff --git a/src/error.rs b/src/error.rs index a544f0c..6b671f5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -65,7 +65,7 @@ impl core::fmt::Display for EncodeError { /// Errors that can be encountered by decoding a type #[non_exhaustive] -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum DecodeError { /// The reader reached its end but more bytes were expected. UnexpectedEnd { @@ -164,6 +164,20 @@ pub enum DecodeError { position: usize, }, + /// The reader encountered an IO error but more bytes were expected. + #[cfg(feature = "std")] + Io { + /// The IO error expected + inner: std::io::Error, + + /// Gives an estimate of how many extra bytes are needed. + /// + /// **Note**: this is only an estimate and not indicative of the actual bytes needed. + /// + /// **Note**: Bincode has no look-ahead mechanism. This means that this will only return the amount of bytes to be read for the current action, and not take into account the entire data structure being read. + additional: usize, + }, + /// An uncommon error occurred, see the inner text for more information #[cfg(feature = "alloc")] OtherString(alloc::string::String), @@ -199,7 +213,7 @@ impl DecodeError { /// Indicates which enum variants are allowed #[non_exhaustive] -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum AllowedEnumVariants { /// All values between `min` and `max` (inclusive) are allowed #[allow(missing_docs)] diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index 72330ed..f926228 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -48,12 +48,12 @@ where { #[inline(always)] fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> { - match self.reader.read_exact(bytes) { - Ok(_) => Ok(()), - Err(_) => Err(DecodeError::UnexpectedEnd { + self.reader + .read_exact(bytes) + .map_err(|inner| DecodeError::Io { + inner, additional: bytes.len(), - }), - } + }) } } @@ -62,12 +62,10 @@ 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 { - additional: bytes.len(), - }), - } + self.read_exact(bytes).map_err(|inner| DecodeError::Io { + inner, + additional: bytes.len(), + }) } #[inline] diff --git a/src/features/serde/mod.rs b/src/features/serde/mod.rs index fc3952f..0f2ba09 100644 --- a/src/features/serde/mod.rs +++ b/src/features/serde/mod.rs @@ -65,7 +65,7 @@ pub use self::de_owned::*; pub use self::ser::*; /// A serde-specific error that occurred while decoding. -#[derive(Debug, PartialEq)] +#[derive(Debug)] #[non_exhaustive] pub enum DecodeError { /// Bincode does not support serde's `any` decoding feature @@ -124,7 +124,7 @@ impl Into for DecodeError { } /// A serde-specific error that occurred while encoding. -#[derive(Debug, PartialEq)] +#[derive(Debug)] #[non_exhaustive] pub enum EncodeError { /// Serde provided bincode with a sequence without a length, which is not supported in bincode diff --git a/tests/basic_types.rs b/tests/basic_types.rs index a69c3de..f58d6da 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -1,5 +1,6 @@ mod utils; +use bincode::error::DecodeError; use core::cell::{Cell, RefCell}; use core::ops::Bound; use core::time::Duration; @@ -253,13 +254,14 @@ fn test_duration_out_of_range() { let result: Result<(std::time::Duration, usize), _> = bincode::decode_from_slice(&input, bincode::config::standard()); - assert_eq!( - result.unwrap_err(), - bincode::error::DecodeError::InvalidDuration { + match result { + Err(DecodeError::InvalidDuration { secs: u64::MAX, - nanos: u32::MAX - } - ); + nanos: u32::MAX, + }) => {} + Err(e) => panic!("Expected InvalidDuration, got {:?}", e), + Ok(_) => panic!("Expected the decode to fail"), + } } #[test] diff --git a/tests/derive.rs b/tests/derive.rs index bdbbb26..e6f2693 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,5 +1,7 @@ #![cfg(feature = "derive")] +use bincode::error::DecodeError; + #[derive(bincode::Encode, PartialEq, Debug)] pub(crate) struct Test { a: T, @@ -276,28 +278,38 @@ fn test_c_style_enum() { assert_eq!(ser(CStyleEnum::D), 5); assert_eq!(ser(CStyleEnum::E), 6); - fn de(num: u8) -> Result { - let (result, len) = bincode::decode_from_slice(&[num], bincode::config::standard())?; - assert_eq!(len, 1); - Ok(result) + fn assert_de_successfully(num: u8, expected: CStyleEnum) { + match bincode::decode_from_slice::(&[num], bincode::config::standard()) { + Ok((result, len)) => { + assert_eq!(len, 1); + assert_eq!(result, expected) + } + Err(e) => panic!("Could not deserialize CStyleEnum idx {num}: {e:?}"), + } } - fn expected_err(idx: u32) -> Result { - Err(bincode::error::DecodeError::UnexpectedVariant { - type_name: "CStyleEnum", - allowed: &bincode::error::AllowedEnumVariants::Allowed(&[1, 2, 3, 5, 6]), - found: idx, - }) + fn assert_de_fails(num: u8) { + match bincode::decode_from_slice::(&[num], bincode::config::standard()) { + Ok(_) => { + panic!("Expected to not be able to decode CStyleEnum index {num}, but it succeeded") + } + Err(DecodeError::UnexpectedVariant { + type_name: "CStyleEnum", + allowed: &bincode::error::AllowedEnumVariants::Allowed(&[1, 2, 3, 5, 6]), + found, + }) if found == num as u32 => {} + Err(e) => panic!("Expected DecodeError::UnexpectedVariant, got {e:?}"), + } } - assert_eq!(de(0), expected_err(0)); - assert_eq!(de(1).unwrap(), CStyleEnum::A); - assert_eq!(de(2).unwrap(), CStyleEnum::B); - assert_eq!(de(3).unwrap(), CStyleEnum::C); - assert_eq!(de(4), expected_err(4)); - assert_eq!(de(5).unwrap(), CStyleEnum::D); - assert_eq!(de(6).unwrap(), CStyleEnum::E); - assert_eq!(de(7), expected_err(7)); + assert_de_fails(0); + assert_de_successfully(1, CStyleEnum::A); + assert_de_successfully(2, CStyleEnum::B); + assert_de_successfully(3, CStyleEnum::C); + assert_de_fails(4); + assert_de_successfully(5, CStyleEnum::D); + assert_de_successfully(6, CStyleEnum::E); + assert_de_fails(7); } macro_rules! macro_newtype { @@ -344,14 +356,13 @@ pub enum BorrowedEmptyEnum {} #[test] fn test_empty_enum_decode() { - let err = - bincode::decode_from_slice::(&[], bincode::config::standard()).unwrap_err(); - assert_eq!( - err, - bincode::error::DecodeError::EmptyEnum { - type_name: "derive::EmptyEnum" - } - ); + match bincode::decode_from_slice::(&[], bincode::config::standard()) { + Ok(_) => panic!("We successfully decoded an empty slice, this should never happen"), + Err(DecodeError::EmptyEnum { + type_name: "derive::EmptyEnum", + }) => {} + Err(e) => panic!("Expected DecodeError::EmptyEnum, got {e:?}"), + } } #[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)] diff --git a/tests/issues/issue_427.rs b/tests/issues/issue_427.rs index 5d63899..09ea981 100644 --- a/tests/issues/issue_427.rs +++ b/tests/issues/issue_427.rs @@ -5,7 +5,7 @@ /// # Remarks /// Used to store HID-IO data chunks. Will be chunked into individual packets on transmission. #[repr(C)] -#[derive(PartialEq, Clone, Debug, bincode::Encode)] +#[derive(PartialEq, Eq, Clone, Debug, bincode::Encode)] pub struct HidIoPacketBuffer { /// Type of packet (Continued is automatically set if needed) pub ptype: u32, @@ -20,7 +20,7 @@ pub struct HidIoPacketBuffer { } #[repr(u32)] -#[derive(PartialEq, Clone, Copy, Debug, bincode::Encode)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, bincode::Encode)] #[allow(dead_code)] /// Requests for to perform a specific action pub enum HidIoCommandId { diff --git a/tests/issues/issue_474.rs b/tests/issues/issue_474.rs index 941e8c5..8a80973 100644 --- a/tests/issues/issue_474.rs +++ b/tests/issues/issue_474.rs @@ -8,12 +8,12 @@ use std::collections::HashMap; use std::prelude::rust_2021::*; use uuid::Uuid; -#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Debug)] +#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Eq, Debug)] pub struct MyStruct { name: String, } -#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Debug)] +#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Eq, Debug)] pub struct CustomerTest { pub id: Option, pub email_address: Option, diff --git a/tests/issues/issue_500.rs b/tests/issues/issue_500.rs index 79c0028..6c013ba 100644 --- a/tests/issues/issue_500.rs +++ b/tests/issues/issue_500.rs @@ -13,6 +13,7 @@ use std::collections::BTreeSet; serde_derive::Deserialize, Debug, PartialEq, + Eq, )] pub struct Membership { /// learners set diff --git a/tests/serde.rs b/tests/serde.rs index d742db7..2adfcc4 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -50,7 +50,7 @@ fn test_serde_round_trip() { assert_eq!(len, 13); } -#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] pub struct SerdeWithBorrowedData<'a> { pub a: u32, #[serde(skip)] @@ -95,7 +95,7 @@ fn test_serialize_deserialize_borrowed_data() { ); } -#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] pub struct SerdeWithOwnedData { pub a: u32, #[serde(skip)] @@ -146,18 +146,18 @@ mod derive { use bincode::{Decode, Encode}; use serde_derive::{Deserialize, Serialize}; - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] pub struct SerdeType { pub a: u32, } - #[derive(Decode, Encode, PartialEq, Debug)] + #[derive(Decode, Encode, PartialEq, Eq, Debug)] pub struct StructWithSerde { #[bincode(with_serde)] pub serde: SerdeType, } - #[derive(Decode, Encode, PartialEq, Debug)] + #[derive(Decode, Encode, PartialEq, Eq, Debug)] pub enum EnumWithSerde { Unit(#[bincode(with_serde)] SerdeType), Struct { diff --git a/tests/std.rs b/tests/std.rs index 79fad9f..34d0162 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -3,6 +3,7 @@ mod utils; +use bincode::error::DecodeError; use std::{ ffi::{CStr, CString}, io::{Cursor, Seek, SeekFrom}, @@ -149,12 +150,16 @@ fn test_system_time_out_of_range() { let result: Result<(std::time::SystemTime, usize), _> = bincode::decode_from_slice(&input, bincode::config::standard()); - assert_eq!( - result.unwrap_err(), - bincode::error::DecodeError::InvalidSystemTime { - duration: std::time::Duration::new(10447520527445462160, 144), + match result { + Ok(_) => panic!("Expected the decode to fail, but it succeeded"), + Err(DecodeError::InvalidSystemTime { duration }) => { + assert_eq!( + duration, + std::time::Duration::new(10447520527445462160, 144) + ) } - ); + Err(e) => panic!("Expected DecodeError::InvalidSystemTime, got {e:?}"), + } } /// Simple example of user-defined hasher to test encoding/decoding HashMap and HashSet with custom hash algorithms. diff --git a/tests/utils.rs b/tests/utils.rs index a1bac55..3672ebc 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -42,7 +42,7 @@ where let mut buffer = [0u8; 2048]; let len = bincode::serde::encode_into_slice(&element, &mut buffer, config); - let decoded = bincode::serde::decode_from_slice(&mut buffer, config); + let decoded = bincode::serde::decode_from_slice(&buffer, config); if !C::SKIP_FIXED_ARRAY_LENGTH { let len = len.unwrap();