From 081949070f337418444c038230b317cdd99a458c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2026 07:48:22 +0000 Subject: [PATCH 1/6] feat(error): improve DecodeError Display implementation Implement Display for DecodeError variants using match to yield user-friendly error messages rather than falling back to the Debug representation. Add Display impls for AllowedEnumVariants and IntegerType to assist in formatting. Co-authored-by: panayang <223123845+panayang@users.noreply.github.com> --- src/error.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 09e2a3d..ca4cf58 100644 --- a/src/error.rs +++ b/src/error.rs @@ -303,8 +303,35 @@ impl core::fmt::Display for DecodeError { &self, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { - // TODO: Improve this? - write!(f, "{self:?}") + match self { + Self::UnexpectedEnd { additional } => write!(f, "Unexpected end of input. Needed {} more bytes", additional), + Self::LimitExceeded => write!(f, "The given configuration limit was exceeded"), + Self::InvalidIntegerType { expected, found } => write!(f, "Invalid type was found. Expected {}, but found {}", expected, found), + Self::NonZeroTypeIsZero { non_zero_type } => write!(f, "The decoder tried to decode a NonZero{} but the value was zero", non_zero_type), + Self::UnexpectedVariant { type_name, allowed, found } => write!(f, "Invalid enum variant was found for {}. Expected {}, but found {}", type_name, allowed, found), + Self::Utf8 { inner } => write!(f, "{}", inner), + Self::InvalidCharEncoding(inner) => write!(f, "Failed to decode a char. Bytes: {:?}", inner), + Self::InvalidBooleanValue(inner) => write!(f, "Failed to decode a bool. Value: {}", inner), + Self::InvalidCborInfo(inner) => write!(f, "Invalid CBOR additional info value: {}", inner), + Self::ArrayLengthMismatch { required, found } => write!(f, "Array length mismatch. Expected length {}, but found {}", required, found), + Self::OutsideUsizeRange(inner) => write!(f, "The encoded value {} is outside the range of the target usize type", inner), + Self::OutsideIsizeRange(inner) => write!(f, "The encoded value {} is outside the range of the target isize type", inner), + Self::EmptyEnum { type_name } => write!(f, "Tried to decode an enum with no variants: {}", type_name), + Self::InvalidDuration { secs, nanos } => write!(f, "Failed to decode a Duration. Seconds: {}, Nanoseconds: {}", secs, nanos), + Self::InvalidSystemTime { duration } => write!(f, "Failed to decode a SystemTime. Duration {:?} could not be added to UNIX_EPOCH", duration), + #[cfg(feature = "std")] + Self::CStringNulError { position } => write!(f, "Incoming data contained a 0 byte at position {}", position), + #[cfg(feature = "std")] + Self::Io { inner, additional } => write!(f, "IO error: {}. Needed {} more bytes", inner, additional), + Self::Other(inner) => write!(f, "{}", inner), + #[cfg(feature = "alloc")] + Self::OtherString(inner) => write!(f, "{}", inner), + #[cfg(feature = "serde")] + Self::Serde(inner) => write!(f, "{}", inner), + Self::SchemaMismatch { expected, actual } => write!(f, "Schema mismatch. Expected hash {}, but found {}", expected, actual), + Self::DuplicateMapKey => write!(f, "The decoder tried to decode a map, but a duplicate key was found"), + Self::InvalidMapOrder => write!(f, "The decoder tried to decode a map, but the keys were not in the correct order"), + } } } @@ -340,6 +367,17 @@ pub enum AllowedEnumVariants { Allowed(&'static [u32]), } +impl core::fmt::Display for AllowedEnumVariants { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Range { min, max } => write!(f, "min: {}, max: {}", min, max), + Self::Allowed(allowed) => { + write!(f, "allowed: {:?}", allowed) + } + } + } +} + /// Integer types. Used by [`DecodeError`\]. These types have no purpose other than being shown in errors. #[non_exhaustive] #[derive(Debug, PartialEq, Eq)] @@ -362,6 +400,26 @@ pub enum IntegerType { Reserved, } +impl core::fmt::Display for IntegerType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::U8 => write!(f, "u8"), + Self::U16 => write!(f, "u16"), + Self::U32 => write!(f, "u32"), + Self::U64 => write!(f, "u64"), + Self::U128 => write!(f, "u128"), + Self::Usize => write!(f, "usize"), + Self::I8 => write!(f, "i8"), + Self::I16 => write!(f, "i16"), + Self::I32 => write!(f, "i32"), + Self::I64 => write!(f, "i64"), + Self::I128 => write!(f, "i128"), + Self::Isize => write!(f, "isize"), + Self::Reserved => write!(f, "reserved"), + } + } +} + impl IntegerType { /// Change the `Ux` value to the associated `Ix` value. /// Returns the old value if `self` is already `Ix`. From 842d7795858d217cdf609666659b37074a9833a5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2026 10:15:27 +0000 Subject: [PATCH 2/6] feat(error): improve DecodeError Display implementation Implement Display for DecodeError variants using match to yield user-friendly error messages rather than falling back to the Debug representation. Add Display impls for AllowedEnumVariants and IntegerType to assist in formatting. Also do the same for serde DecodeError and EncodeError. --- src/features/serde/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/features/serde/mod.rs b/src/features/serde/mod.rs index caed7a6..d863278 100644 --- a/src/features/serde/mod.rs +++ b/src/features/serde/mod.rs @@ -172,6 +172,21 @@ bincode_error_serde! { } } +impl core::fmt::Display for DecodeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::AnyNotSupported => write!(f, "Bincode does not support serde's `any` decoding feature."), + Self::IdentifierNotSupported => write!(f, "Bincode does not support serde identifiers"), + Self::IgnoredAnyNotSupported => write!(f, "Bincode does not support serde's `ignored_any`."), + Self::CannotBorrowOwnedData => write!(f, "Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead"), + #[cfg(not(feature = "alloc"))] + Self::CannotAllocate => write!(f, "Could not allocate data like `String` and `Vec`"), + #[cfg(not(feature = "alloc"))] + Self::CustomError => write!(f, "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information."), + } + } +} + #[cfg(feature = "alloc")] impl serde::de::Error for crate::error::DecodeError { fn custom(msg: T) -> Self @@ -209,6 +224,18 @@ pub enum EncodeError { CustomError, } +impl core::fmt::Display for EncodeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::SequenceMustHaveLength => write!(f, "Serde provided bincode with a sequence without a length, which is not supported in bincode"), + #[cfg(not(feature = "alloc"))] + Self::CannotCollectStr => write!(f, "Serializer::collect_str got called but bincode was unable to allocate memory."), + #[cfg(not(feature = "alloc"))] + Self::CustomError => write!(f, "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information."), + } + } +} + #[allow(clippy::from_over_into)] impl Into for EncodeError { fn into(self) -> crate::error::EncodeError { From 2b0045770f38f2a7eb64f98c275ddc2e1f177532 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2026 13:00:47 +0000 Subject: [PATCH 3/6] feat(error): improve DecodeError Display implementation Implement Display for DecodeError variants using match to yield user-friendly error messages rather than falling back to the Debug representation. Add Display impls for AllowedEnumVariants and IntegerType to assist in formatting. Also do the same for serde DecodeError and EncodeError. From b57165db29fa6cdc2013d8a175604f8557ff9cd1 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2026 16:52:06 +0000 Subject: [PATCH 4/6] feat(error): improve DecodeError Display implementation Implement Display for DecodeError variants using match to yield user-friendly error messages rather than falling back to the Debug representation. Add Display impls for AllowedEnumVariants and IntegerType to assist in formatting. Also do the same for serde DecodeError and EncodeError. From 53c1ddea3125b8c6c5cf7336deeddf9112818aea Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 02:32:10 +0000 Subject: [PATCH 5/6] feat(error): improve DecodeError Display implementation Implement Display for DecodeError variants using match to yield user-friendly error messages rather than falling back to the Debug representation. Add Display impls for AllowedEnumVariants and IntegerType to assist in formatting. Also do the same for serde DecodeError and EncodeError. From 6799f0756cb210d4477d1649ed5d81d481b8c41c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 08:50:38 +0000 Subject: [PATCH 6/6] style(error): Format code with nightly cargo fmt Resolve clippy lints from uninlined_format_args and too_many_lines in DecodeError fmt implementation. --- src/error.rs | 170 ++++++++++++++++++++++++++++---------- src/features/serde/mod.rs | 64 +++++++++++--- 2 files changed, 181 insertions(+), 53 deletions(-) diff --git a/src/error.rs b/src/error.rs index ca4cf58..0d038cf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -299,38 +299,118 @@ pub const fn decode_err_from(e: crate::features::serde::DecodeError) -> DecodeEr } impl core::fmt::Display for DecodeError { + #[allow(clippy::too_many_lines)] fn fmt( &self, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match self { - Self::UnexpectedEnd { additional } => write!(f, "Unexpected end of input. Needed {} more bytes", additional), - Self::LimitExceeded => write!(f, "The given configuration limit was exceeded"), - Self::InvalidIntegerType { expected, found } => write!(f, "Invalid type was found. Expected {}, but found {}", expected, found), - Self::NonZeroTypeIsZero { non_zero_type } => write!(f, "The decoder tried to decode a NonZero{} but the value was zero", non_zero_type), - Self::UnexpectedVariant { type_name, allowed, found } => write!(f, "Invalid enum variant was found for {}. Expected {}, but found {}", type_name, allowed, found), - Self::Utf8 { inner } => write!(f, "{}", inner), - Self::InvalidCharEncoding(inner) => write!(f, "Failed to decode a char. Bytes: {:?}", inner), - Self::InvalidBooleanValue(inner) => write!(f, "Failed to decode a bool. Value: {}", inner), - Self::InvalidCborInfo(inner) => write!(f, "Invalid CBOR additional info value: {}", inner), - Self::ArrayLengthMismatch { required, found } => write!(f, "Array length mismatch. Expected length {}, but found {}", required, found), - Self::OutsideUsizeRange(inner) => write!(f, "The encoded value {} is outside the range of the target usize type", inner), - Self::OutsideIsizeRange(inner) => write!(f, "The encoded value {} is outside the range of the target isize type", inner), - Self::EmptyEnum { type_name } => write!(f, "Tried to decode an enum with no variants: {}", type_name), - Self::InvalidDuration { secs, nanos } => write!(f, "Failed to decode a Duration. Seconds: {}, Nanoseconds: {}", secs, nanos), - Self::InvalidSystemTime { duration } => write!(f, "Failed to decode a SystemTime. Duration {:?} could not be added to UNIX_EPOCH", duration), + | Self::UnexpectedEnd { additional } => { + write!( + f, + "Unexpected end of input. Needed {additional} more bytes" + ) + }, + | Self::LimitExceeded => write!(f, "The given configuration limit was exceeded"), + | Self::InvalidIntegerType { expected, found } => { + write!( + f, + "Invalid type was found. Expected {expected}, but found {found}" + ) + }, + | Self::NonZeroTypeIsZero { non_zero_type } => { + write!( + f, + "The decoder tried to decode a NonZero{non_zero_type} but the value was zero" + ) + }, + | Self::UnexpectedVariant { + type_name, + allowed, + found, + } => { + write!( + f, + "Invalid enum variant was found for {type_name}. Expected {allowed}, but found {found}" + ) + }, + | Self::Utf8 { inner } => write!(f, "{inner}"), + | Self::InvalidCharEncoding(inner) => { + write!(f, "Failed to decode a char. Bytes: {inner:?}") + }, + | Self::InvalidBooleanValue(inner) => { + write!(f, "Failed to decode a bool. Value: {inner}") + }, + | Self::InvalidCborInfo(inner) => { + write!(f, "Invalid CBOR additional info value: {inner}") + }, + | Self::ArrayLengthMismatch { required, found } => { + write!( + f, + "Array length mismatch. Expected length {required}, but found {found}" + ) + }, + | Self::OutsideUsizeRange(inner) => { + write!( + f, + "The encoded value {inner} is outside the range of the target usize type" + ) + }, + | Self::OutsideIsizeRange(inner) => { + write!( + f, + "The encoded value {inner} is outside the range of the target isize type" + ) + }, + | Self::EmptyEnum { type_name } => { + write!(f, "Tried to decode an enum with no variants: {type_name}") + }, + | Self::InvalidDuration { secs, nanos } => { + write!( + f, + "Failed to decode a Duration. Seconds: {secs}, Nanoseconds: {nanos}" + ) + }, + | Self::InvalidSystemTime { duration } => { + write!( + f, + "Failed to decode a SystemTime. Duration {duration:?} could not be added to UNIX_EPOCH" + ) + }, #[cfg(feature = "std")] - Self::CStringNulError { position } => write!(f, "Incoming data contained a 0 byte at position {}", position), + | Self::CStringNulError { position } => { + write!( + f, + "Incoming data contained a 0 byte at position {position}" + ) + }, #[cfg(feature = "std")] - Self::Io { inner, additional } => write!(f, "IO error: {}. Needed {} more bytes", inner, additional), - Self::Other(inner) => write!(f, "{}", inner), + | Self::Io { inner, additional } => { + write!(f, "IO error: {inner}. Needed {additional} more bytes") + }, + | Self::Other(inner) => write!(f, "{inner}"), #[cfg(feature = "alloc")] - Self::OtherString(inner) => write!(f, "{}", inner), + | Self::OtherString(inner) => write!(f, "{inner}"), #[cfg(feature = "serde")] - Self::Serde(inner) => write!(f, "{}", inner), - Self::SchemaMismatch { expected, actual } => write!(f, "Schema mismatch. Expected hash {}, but found {}", expected, actual), - Self::DuplicateMapKey => write!(f, "The decoder tried to decode a map, but a duplicate key was found"), - Self::InvalidMapOrder => write!(f, "The decoder tried to decode a map, but the keys were not in the correct order"), + | Self::Serde(inner) => write!(f, "{inner}"), + | Self::SchemaMismatch { expected, actual } => { + write!( + f, + "Schema mismatch. Expected hash {expected}, but found {actual}" + ) + }, + | Self::DuplicateMapKey => { + write!( + f, + "The decoder tried to decode a map, but a duplicate key was found" + ) + }, + | Self::InvalidMapOrder => { + write!( + f, + "The decoder tried to decode a map, but the keys were not in the correct order" + ) + }, } } } @@ -368,12 +448,15 @@ pub enum AllowedEnumVariants { } impl core::fmt::Display for AllowedEnumVariants { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { match self { - Self::Range { min, max } => write!(f, "min: {}, max: {}", min, max), - Self::Allowed(allowed) => { - write!(f, "allowed: {:?}", allowed) - } + | Self::Range { min, max } => write!(f, "min: {min}, max: {max}"), + | Self::Allowed(allowed) => { + write!(f, "allowed: {allowed:?}") + }, } } } @@ -401,21 +484,24 @@ pub enum IntegerType { } impl core::fmt::Display for IntegerType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { match self { - Self::U8 => write!(f, "u8"), - Self::U16 => write!(f, "u16"), - Self::U32 => write!(f, "u32"), - Self::U64 => write!(f, "u64"), - Self::U128 => write!(f, "u128"), - Self::Usize => write!(f, "usize"), - Self::I8 => write!(f, "i8"), - Self::I16 => write!(f, "i16"), - Self::I32 => write!(f, "i32"), - Self::I64 => write!(f, "i64"), - Self::I128 => write!(f, "i128"), - Self::Isize => write!(f, "isize"), - Self::Reserved => write!(f, "reserved"), + | Self::U8 => write!(f, "u8"), + | Self::U16 => write!(f, "u16"), + | Self::U32 => write!(f, "u32"), + | Self::U64 => write!(f, "u64"), + | Self::U128 => write!(f, "u128"), + | Self::Usize => write!(f, "usize"), + | Self::I8 => write!(f, "i8"), + | Self::I16 => write!(f, "i16"), + | Self::I32 => write!(f, "i32"), + | Self::I64 => write!(f, "i64"), + | Self::I128 => write!(f, "i128"), + | Self::Isize => write!(f, "isize"), + | Self::Reserved => write!(f, "reserved"), } } } diff --git a/src/features/serde/mod.rs b/src/features/serde/mod.rs index d863278..234b1a2 100644 --- a/src/features/serde/mod.rs +++ b/src/features/serde/mod.rs @@ -173,16 +173,40 @@ bincode_error_serde! { } impl core::fmt::Display for DecodeError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { match self { - Self::AnyNotSupported => write!(f, "Bincode does not support serde's `any` decoding feature."), - Self::IdentifierNotSupported => write!(f, "Bincode does not support serde identifiers"), - Self::IgnoredAnyNotSupported => write!(f, "Bincode does not support serde's `ignored_any`."), - Self::CannotBorrowOwnedData => write!(f, "Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead"), + | Self::AnyNotSupported => { + write!( + f, + "Bincode does not support serde's `any` decoding feature." + ) + }, + | Self::IdentifierNotSupported => { + write!(f, "Bincode does not support serde identifiers") + }, + | Self::IgnoredAnyNotSupported => { + write!(f, "Bincode does not support serde's `ignored_any`.") + }, + | Self::CannotBorrowOwnedData => { + write!( + f, + "Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead" + ) + }, #[cfg(not(feature = "alloc"))] - Self::CannotAllocate => write!(f, "Could not allocate data like `String` and `Vec`"), + | Self::CannotAllocate => { + write!(f, "Could not allocate data like `String` and `Vec`") + }, #[cfg(not(feature = "alloc"))] - Self::CustomError => write!(f, "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information."), + | Self::CustomError => { + write!( + f, + "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information." + ) + }, } } } @@ -225,13 +249,31 @@ pub enum EncodeError { } impl core::fmt::Display for EncodeError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { match self { - Self::SequenceMustHaveLength => write!(f, "Serde provided bincode with a sequence without a length, which is not supported in bincode"), + | Self::SequenceMustHaveLength => { + write!( + f, + "Serde provided bincode with a sequence without a length, which is not supported in bincode" + ) + }, #[cfg(not(feature = "alloc"))] - Self::CannotCollectStr => write!(f, "Serializer::collect_str got called but bincode was unable to allocate memory."), + | Self::CannotCollectStr => { + write!( + f, + "Serializer::collect_str got called but bincode was unable to allocate memory." + ) + }, #[cfg(not(feature = "alloc"))] - Self::CustomError => write!(f, "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information."), + | Self::CustomError => { + write!( + f, + "Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information." + ) + }, } } }