From 86e03aeda704493d7a8973d86051f2a1d38bf092 Mon Sep 17 00:00:00 2001 From: Trangar Date: Sat, 4 Jun 2022 15:23:55 +0200 Subject: [PATCH] Rewrite: seperated Decode and BorrowDecode (#526) * Rewrite: seperated Decode and BorrowDecode * Fixed cargo.toml issues * Fixed clippy warning * Removed the `impl_tuples` macro call with manually exported code * Replaced the generated code in `impl_tuples` with the macro instead * Implemented BorrowDecode for Box<[T]> * Added a test to see if zoxide can be ported to bincode 2 * Added a test for Arc * Made several `Encode` implementations require `T: ?Sized` * Implemented Decode for Arc * Added BlockedTODO links to commented out code * Fixed clippy and lint issues * Updated virtue dependency in fuzz lockfile --- derive/Cargo.toml | 2 +- derive/src/attribute.rs | 46 ++++++++ derive/src/derive_enum.rs | 45 +++++-- derive/src/derive_struct.rs | 59 ++++++---- fuzz/Cargo.lock | 5 +- fuzz/fuzz_targets/compat.rs | 18 ++- src/atomic.rs | 24 +++- src/de/impl_tuples.rs | 185 ++++++++--------------------- src/de/impls.rs | 216 ++++++++++++++++++++++++++++++---- src/de/mod.rs | 47 +++++++- src/enc/impls.rs | 47 ++++---- src/features/impl_alloc.rs | 194 ++++++++++++++++++++++++++---- src/features/impl_std.rs | 70 +++++++++++ src/features/serde/mod.rs | 11 ++ src/lib.rs | 19 ++- src/varint/decode_unsigned.rs | 4 +- src/varint/encode_unsigned.rs | 4 +- tests/alloc.rs | 68 +++++++++-- tests/atomic.rs | 29 ++++- tests/basic_types.rs | 20 ++-- tests/derive.rs | 102 +++++++++++++--- tests/issues/issue_431.rs | 6 +- tests/issues/issue_474.rs | 2 +- tests/serde.rs | 2 +- tests/std.rs | 13 +- tests/utils.rs | 7 +- 26 files changed, 934 insertions(+), 311 deletions(-) diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 55b8bb1..d7f989a 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -16,4 +16,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode" proc-macro = true [dependencies] -virtue = "0.0.7" +virtue = "0.0.8" diff --git a/derive/src/attribute.rs b/derive/src/attribute.rs index 5f0b8ca..30f817b 100644 --- a/derive/src/attribute.rs +++ b/derive/src/attribute.rs @@ -3,12 +3,20 @@ use virtue::utils::{parse_tagged_attribute, ParsedAttribute}; pub struct ContainerAttributes { pub crate_name: String, + pub bounds: Option<(String, Literal)>, + pub decode_bounds: Option<(String, Literal)>, + pub borrow_decode_bounds: Option<(String, Literal)>, + pub encode_bounds: Option<(String, Literal)>, } impl Default for ContainerAttributes { fn default() -> Self { Self { crate_name: "::bincode".to_string(), + bounds: None, + decode_bounds: None, + encode_bounds: None, + borrow_decode_bounds: None, } } } @@ -30,6 +38,44 @@ impl FromAttribute for ContainerAttributes { return Err(Error::custom_at("Should be a literal str", val.span())); } } + ParsedAttribute::Property(key, val) if key.to_string() == "bounds" => { + let val_string = val.to_string(); + if val_string.starts_with('"') && val_string.ends_with('"') { + result.bounds = + Some((val_string[1..val_string.len() - 1].to_string(), val)); + } else { + return Err(Error::custom_at("Should be a literal str", val.span())); + } + } + ParsedAttribute::Property(key, val) if key.to_string() == "decode_bounds" => { + let val_string = val.to_string(); + if val_string.starts_with('"') && val_string.ends_with('"') { + result.decode_bounds = + Some((val_string[1..val_string.len() - 1].to_string(), val)); + } else { + return Err(Error::custom_at("Should be a literal str", val.span())); + } + } + ParsedAttribute::Property(key, val) if key.to_string() == "encode_bounds" => { + let val_string = val.to_string(); + if val_string.starts_with('"') && val_string.ends_with('"') { + result.encode_bounds = + Some((val_string[1..val_string.len() - 1].to_string(), val)); + } else { + return Err(Error::custom_at("Should be a literal str", val.span())); + } + } + ParsedAttribute::Property(key, val) + if key.to_string() == "borrow_decode_bounds" => + { + let val_string = val.to_string(); + if val_string.starts_with('"') && val_string.ends_with('"') { + result.borrow_decode_bounds = + Some((val_string[1..val_string.len() - 1].to_string(), val)); + } else { + return Err(Error::custom_at("Should be a literal str", val.span())); + } + } ParsedAttribute::Tag(i) => { return Err(Error::custom_at("Unknown field attribute", i.span())) } diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index ef82fad..0f21e8c 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -22,12 +22,22 @@ impl DeriveEnum { generator .impl_for(format!("{}::Encode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { + if let Some((bounds, lit)) = + (self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) + { + where_constraints.clear(); where_constraints - .push_constraint(g, format!("{}::Encode", crate_name)) - .unwrap(); + .push_parsed_constraint(bounds) + .map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints + .push_constraint(g, format!("{}::Encode", crate_name)) + .unwrap(); + } } - }) + Ok(()) + })? .generate_fn("encode") .with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)]) .with_self_arg(FnSelfArg::RefSelf) @@ -206,7 +216,7 @@ impl DeriveEnum { Ok(()) } - pub fn generate_decode(&self, generator: &mut Generator) -> Result<()> { + pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { let crate_name = self.attributes.crate_name.as_str(); // Remember to keep this mostly in sync with generate_borrow_decode @@ -216,10 +226,16 @@ impl DeriveEnum { generator .impl_for(format!("{}::Decode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { - where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap(); + if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { + where_constraints.clear(); + where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap(); + } } - }) + Ok(()) + })? .generate_fn("decode") .with_generic_deps("D", [format!("{}::de::Decoder", crate_name)]) .with_arg("decoder", "&mut D") @@ -293,6 +309,7 @@ impl DeriveEnum { } Ok(()) })?; + self.generate_borrow_decode(generator)?; Ok(()) } @@ -304,10 +321,16 @@ impl DeriveEnum { generator.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"]) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { - where_constraints.push_constraint(g, format!("{}::enc::BorrowDecode", crate_name)).unwrap(); + if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { + where_constraints.clear(); + where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap(); + } } - }) + Ok(()) + })? .generate_fn("borrow_decode") .with_generic_deps("D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)]) .with_arg("decoder", "&mut D") diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index fb0c125..14e4c9c 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -10,18 +10,26 @@ pub(crate) struct DeriveStruct { impl DeriveStruct { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { - let DeriveStruct { fields, attributes } = self; - let crate_name = attributes.crate_name; - + let crate_name = &self.attributes.crate_name; generator .impl_for(&format!("{}::Encode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { + if let Some((bounds, lit)) = + (self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) + { + where_constraints.clear(); where_constraints - .push_constraint(g, format!("{}::Encode", crate_name)) - .unwrap(); + .push_parsed_constraint(bounds) + .map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints + .push_constraint(g, format!("{}::Encode", crate_name)) + .unwrap(); + } } - }) + Ok(()) + })? .generate_fn("encode") .with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)]) .with_self_arg(virtue::generate::FnSelfArg::RefSelf) @@ -31,7 +39,7 @@ impl DeriveStruct { crate_name )) .body(|fn_body| { - for field in fields.names() { + for field in self.fields.names() { let attributes = field .attributes() .get_attribute::()? @@ -56,16 +64,21 @@ impl DeriveStruct { pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_borrow_decode - let DeriveStruct { fields, attributes } = self; - let crate_name = attributes.crate_name; + let crate_name = &self.attributes.crate_name; generator .impl_for(format!("{}::Decode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { - where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap(); + if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { + where_constraints.clear(); + where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap(); + } } - }) + Ok(()) + })? .generate_fn("decode") .with_generic_deps("D", [format!("{}::de::Decoder", crate_name)]) .with_arg("decoder", "&mut D") @@ -82,7 +95,7 @@ impl DeriveStruct { // b: bincode::Decode::decode(decoder)?, // ... // } - for field in fields.names() { + for field in &self.fields.names() { let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { struct_body @@ -106,21 +119,27 @@ impl DeriveStruct { })?; Ok(()) })?; + self.generate_borrow_decode(generator)?; Ok(()) } pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_decode - let DeriveStruct { fields, attributes } = self; - let crate_name = attributes.crate_name; + let crate_name = self.attributes.crate_name; generator .impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"]) .modify_generic_constraints(|generics, where_constraints| { - for g in generics.iter_generics() { - where_constraints.push_constraint(g, format!("{}::BorrowDecode", crate_name)).unwrap(); + if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { + where_constraints.clear(); + where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; + } else { + for g in generics.iter_generics() { + where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap(); + } } - }) + Ok(()) + })? .generate_fn("borrow_decode") .with_generic_deps("D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)]) .with_arg("decoder", "&mut D") @@ -131,7 +150,7 @@ impl DeriveStruct { fn_body.group(Delimiter::Parenthesis, |ok_group| { ok_group.ident_str("Self"); ok_group.group(Delimiter::Brace, |struct_body| { - for field in fields.names() { + for field in self.fields.names() { let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { struct_body diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 3a369de..a360e66 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -22,6 +22,7 @@ name = "bincode" version = "2.0.0-rc.1" dependencies = [ "bincode_derive", + "serde", ] [[package]] @@ -121,6 +122,6 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "virtue" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757cfbfe0d17ee6f22fe97e536d463047d451b47cf9d11e2b7d1398b0ef274dd" +checksum = "7b60dcd6a64dd45abf9bd426970c9843726da7fc08f44cd6fcebf68c21220a63" diff --git a/fuzz/fuzz_targets/compat.rs b/fuzz/fuzz_targets/compat.rs index 9014529..6fac88d 100644 --- a/fuzz/fuzz_targets/compat.rs +++ b/fuzz/fuzz_targets/compat.rs @@ -8,7 +8,17 @@ use std::num::{NonZeroI128, NonZeroI32, NonZeroU128, NonZeroU32}; use std::path::PathBuf; use std::time::{Duration, SystemTime}; -#[derive(bincode::Decode, bincode::Encode, PartialEq, Debug, serde::Serialize, serde::Deserialize, Eq, PartialOrd, Ord)] +#[derive( + bincode::Decode, + bincode::Encode, + PartialEq, + Debug, + serde::Serialize, + serde::Deserialize, + Eq, + PartialOrd, + Ord, +)] enum AllTypes { BTreeMap(BTreeMap), BTreeSet(BTreeSet), @@ -47,14 +57,14 @@ fuzz_target!(|data: &[u8]| { let bincode_v2: Result<(AllTypes, _), _> = bincode::decode_from_slice(data, config); match (&bincode_v1, &bincode_v2) { - (Err(e), _) if e.to_string() == "the size limit has been reached" => {}, - (_, Err(bincode::error::DecodeError::LimitExceeded)) => {}, + (Err(e), _) if e.to_string() == "the size limit has been reached" => {} + (_, Err(bincode::error::DecodeError::LimitExceeded)) => {} (Ok(bincode_v1), Ok((bincode_v2, _))) if bincode_v1 != bincode_v2 => { println!("Bytes: {:?}", data); println!("Bincode V1: {:?}", bincode_v1); println!("Bincode V2: {:?}", bincode_v2); panic!("failed equality check"); - }, + } (Ok(_), Err(_)) | (Err(_), Ok(_)) => { println!("Bytes: {:?}", data); println!("Bincode V1: {:?}", bincode_v1); diff --git a/src/atomic.rs b/src/atomic.rs index 5267dc9..1b70252 100644 --- a/src/atomic.rs +++ b/src/atomic.rs @@ -1,4 +1,4 @@ -use crate::{de::Decode, enc::Encode}; +use crate::{de::Decode, enc::Encode, impl_borrow_decode}; use core::sync::atomic::Ordering; #[cfg(target_has_atomic = "ptr")] @@ -32,6 +32,8 @@ impl Decode for AtomicBool { Ok(AtomicBool::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "8")] +impl_borrow_decode!(AtomicBool); #[cfg(target_has_atomic = "8")] impl Encode for AtomicU8 { @@ -49,6 +51,8 @@ impl Decode for AtomicU8 { Ok(AtomicU8::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "8")] +impl_borrow_decode!(AtomicU8); #[cfg(target_has_atomic = "16")] impl Encode for AtomicU16 { @@ -66,6 +70,8 @@ impl Decode for AtomicU16 { Ok(AtomicU16::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "16")] +impl_borrow_decode!(AtomicU16); #[cfg(target_has_atomic = "32")] impl Encode for AtomicU32 { @@ -83,6 +89,8 @@ impl Decode for AtomicU32 { Ok(AtomicU32::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "32")] +impl_borrow_decode!(AtomicU32); #[cfg(target_has_atomic = "64")] impl Encode for AtomicU64 { @@ -100,6 +108,8 @@ impl Decode for AtomicU64 { Ok(AtomicU64::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "64")] +impl_borrow_decode!(AtomicU64); #[cfg(target_has_atomic = "ptr")] impl Encode for AtomicUsize { @@ -117,6 +127,8 @@ impl Decode for AtomicUsize { Ok(AtomicUsize::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "ptr")] +impl_borrow_decode!(AtomicUsize); #[cfg(target_has_atomic = "8")] impl Encode for AtomicI8 { @@ -134,6 +146,8 @@ impl Decode for AtomicI8 { Ok(AtomicI8::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "8")] +impl_borrow_decode!(AtomicI8); #[cfg(target_has_atomic = "16")] impl Encode for AtomicI16 { @@ -151,6 +165,8 @@ impl Decode for AtomicI16 { Ok(AtomicI16::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "16")] +impl_borrow_decode!(AtomicI16); #[cfg(target_has_atomic = "32")] impl Encode for AtomicI32 { @@ -168,6 +184,8 @@ impl Decode for AtomicI32 { Ok(AtomicI32::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "32")] +impl_borrow_decode!(AtomicI32); #[cfg(target_has_atomic = "64")] impl Encode for AtomicI64 { @@ -185,6 +203,8 @@ impl Decode for AtomicI64 { Ok(AtomicI64::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "64")] +impl_borrow_decode!(AtomicI64); #[cfg(target_has_atomic = "ptr")] impl Encode for AtomicIsize { @@ -202,3 +222,5 @@ impl Decode for AtomicIsize { Ok(AtomicIsize::new(Decode::decode(decoder)?)) } } +#[cfg(target_has_atomic = "ptr")] +impl_borrow_decode!(AtomicIsize); diff --git a/src/de/impl_tuples.rs b/src/de/impl_tuples.rs index 70d82cd..951444e 100644 --- a/src/de/impl_tuples.rs +++ b/src/de/impl_tuples.rs @@ -1,141 +1,54 @@ -use super::{Decode, Decoder}; +use super::{BorrowDecode, BorrowDecoder, Decode, Decoder}; use crate::error::DecodeError; -impl Decode for (A,) -where - A: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _D) -> Result { - Ok((A::decode(&mut decoder)?,)) +macro_rules! impl_tuple { + () => {}; + ($first:ident $(, $extra:ident)*) => { + impl<'de, $first $(, $extra)*> BorrowDecode<'de> for ($first, $($extra, )*) + where + $first: BorrowDecode<'de>, + $( + $extra : BorrowDecode<'de>, + )* + { + fn borrow_decode>(decoder: &mut BD) -> Result { + Ok(( + $first::borrow_decode(decoder)?, + $($extra :: borrow_decode(decoder)?, )* + )) + } + } + + impl<$first $(, $extra)*> Decode for ($first, $($extra, )*) + where + $first: Decode, + $( + $extra : Decode, + )* + { + fn decode(decoder: &mut DE) -> Result { + Ok(( + $first::decode(decoder)?, + $($extra :: decode(decoder)?, )* + )) + } + } } } -impl Decode for (A, B) -where - A: Decode, - B: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _D) -> Result { - Ok((A::decode(&mut decoder)?, B::decode(&mut decoder)?)) - } -} - -impl Decode for (A, B, C) -where - A: Decode, - B: Decode, - C: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _D) -> Result { - Ok(( - A::decode(&mut decoder)?, - B::decode(&mut decoder)?, - C::decode(&mut decoder)?, - )) - } -} - -impl Decode for (A, B, C, D) -where - A: Decode, - B: Decode, - C: Decode, - D: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _D) -> Result { - Ok(( - A::decode(&mut decoder)?, - B::decode(&mut decoder)?, - C::decode(&mut decoder)?, - D::decode(&mut decoder)?, - )) - } -} - -impl Decode for (A, B, C, D, E) -where - A: Decode, - B: Decode, - C: Decode, - D: Decode, - E: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _D) -> Result { - Ok(( - A::decode(&mut decoder)?, - B::decode(&mut decoder)?, - C::decode(&mut decoder)?, - D::decode(&mut decoder)?, - E::decode(&mut decoder)?, - )) - } -} - -impl Decode for (A, B, C, D, E, F) -where - A: Decode, - B: Decode, - C: Decode, - D: Decode, - E: Decode, - F: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _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 Decode for (A, B, C, D, E, F, G) -where - A: Decode, - B: Decode, - C: Decode, - D: Decode, - E: Decode, - F: Decode, - G: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _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 Decode for (A, B, C, D, E, F, G, H) -where - A: Decode, - B: Decode, - C: Decode, - D: Decode, - E: Decode, - F: Decode, - G: Decode, - H: Decode, -{ - fn decode<_D: Decoder>(mut decoder: &mut _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)?, - )) - } -} +impl_tuple!(A); +impl_tuple!(A, B); +impl_tuple!(A, B, C); +impl_tuple!(A, B, C, D); +impl_tuple!(A, B, C, D, E); +impl_tuple!(A, B, C, D, E, F); +impl_tuple!(A, B, C, D, E, F, G); +impl_tuple!(A, B, C, D, E, F, G, H); +impl_tuple!(A, B, C, D, E, F, G, H, I); +impl_tuple!(A, B, C, D, E, F, G, H, I, J); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); +impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); diff --git a/src/de/impls.rs b/src/de/impls.rs index d0c80b1..7902ce5 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -8,6 +8,7 @@ use crate::{ InternalIntEncodingConfig, }, error::{DecodeError, IntegerType}, + impl_borrow_decode, }; use core::{ any::TypeId, @@ -29,6 +30,7 @@ impl Decode for bool { } } } +impl_borrow_decode!(bool); impl Decode for u8 { #[inline] @@ -45,6 +47,7 @@ impl Decode for u8 { } } } +impl_borrow_decode!(u8); impl Decode for NonZeroU8 { fn decode(decoder: &mut D) -> Result { @@ -53,6 +56,7 @@ impl Decode for NonZeroU8 { }) } } +impl_borrow_decode!(NonZeroU8); impl Decode for u16 { fn decode(decoder: &mut D) -> Result { @@ -72,6 +76,7 @@ impl Decode for u16 { } } } +impl_borrow_decode!(u16); impl Decode for NonZeroU16 { fn decode(decoder: &mut D) -> Result { @@ -80,6 +85,7 @@ impl Decode for NonZeroU16 { }) } } +impl_borrow_decode!(NonZeroU16); impl Decode for u32 { fn decode(decoder: &mut D) -> Result { @@ -99,6 +105,7 @@ impl Decode for u32 { } } } +impl_borrow_decode!(u32); impl Decode for NonZeroU32 { fn decode(decoder: &mut D) -> Result { @@ -107,6 +114,7 @@ impl Decode for NonZeroU32 { }) } } +impl_borrow_decode!(NonZeroU32); impl Decode for u64 { fn decode(decoder: &mut D) -> Result { @@ -126,6 +134,7 @@ impl Decode for u64 { } } } +impl_borrow_decode!(u64); impl Decode for NonZeroU64 { fn decode(decoder: &mut D) -> Result { @@ -134,6 +143,7 @@ impl Decode for NonZeroU64 { }) } } +impl_borrow_decode!(NonZeroU64); impl Decode for u128 { fn decode(decoder: &mut D) -> Result { @@ -153,6 +163,7 @@ impl Decode for u128 { } } } +impl_borrow_decode!(u128); impl Decode for NonZeroU128 { fn decode(decoder: &mut D) -> Result { @@ -161,6 +172,7 @@ impl Decode for NonZeroU128 { }) } } +impl_borrow_decode!(NonZeroU128); impl Decode for usize { fn decode(decoder: &mut D) -> Result { @@ -185,6 +197,7 @@ impl Decode for usize { } } } +impl_borrow_decode!(usize); impl Decode for NonZeroUsize { fn decode(decoder: &mut D) -> Result { @@ -193,6 +206,7 @@ impl Decode for NonZeroUsize { }) } } +impl_borrow_decode!(NonZeroUsize); impl Decode for i8 { fn decode(decoder: &mut D) -> Result { @@ -202,6 +216,7 @@ impl Decode for i8 { Ok(bytes[0] as i8) } } +impl_borrow_decode!(i8); impl Decode for NonZeroI8 { fn decode(decoder: &mut D) -> Result { @@ -210,6 +225,7 @@ impl Decode for NonZeroI8 { }) } } +impl_borrow_decode!(NonZeroI8); impl Decode for i16 { fn decode(decoder: &mut D) -> Result { @@ -229,6 +245,7 @@ impl Decode for i16 { } } } +impl_borrow_decode!(i16); impl Decode for NonZeroI16 { fn decode(decoder: &mut D) -> Result { @@ -237,6 +254,7 @@ impl Decode for NonZeroI16 { }) } } +impl_borrow_decode!(NonZeroI16); impl Decode for i32 { fn decode(decoder: &mut D) -> Result { @@ -256,6 +274,7 @@ impl Decode for i32 { } } } +impl_borrow_decode!(i32); impl Decode for NonZeroI32 { fn decode(decoder: &mut D) -> Result { @@ -264,6 +283,7 @@ impl Decode for NonZeroI32 { }) } } +impl_borrow_decode!(NonZeroI32); impl Decode for i64 { fn decode(decoder: &mut D) -> Result { @@ -283,6 +303,7 @@ impl Decode for i64 { } } } +impl_borrow_decode!(i64); impl Decode for NonZeroI64 { fn decode(decoder: &mut D) -> Result { @@ -291,6 +312,7 @@ impl Decode for NonZeroI64 { }) } } +impl_borrow_decode!(NonZeroI64); impl Decode for i128 { fn decode(decoder: &mut D) -> Result { @@ -310,6 +332,7 @@ impl Decode for i128 { } } } +impl_borrow_decode!(i128); impl Decode for NonZeroI128 { fn decode(decoder: &mut D) -> Result { @@ -318,6 +341,7 @@ impl Decode for NonZeroI128 { }) } } +impl_borrow_decode!(NonZeroI128); impl Decode for isize { fn decode(decoder: &mut D) -> Result { @@ -337,6 +361,7 @@ impl Decode for isize { } } } +impl_borrow_decode!(isize); impl Decode for NonZeroIsize { fn decode(decoder: &mut D) -> Result { @@ -345,6 +370,7 @@ impl Decode for NonZeroIsize { }) } } +impl_borrow_decode!(NonZeroIsize); impl Decode for f32 { fn decode(decoder: &mut D) -> Result { @@ -357,6 +383,7 @@ impl Decode for f32 { }) } } +impl_borrow_decode!(f32); impl Decode for f64 { fn decode(decoder: &mut D) -> Result { @@ -369,6 +396,7 @@ impl Decode for f64 { }) } } +impl_borrow_decode!(f64); impl Decode for char { fn decode(decoder: &mut D) -> Result { @@ -398,6 +426,7 @@ impl Decode for char { Ok(res) } } +impl_borrow_decode!(char); impl<'a, 'de: 'a> BorrowDecode<'de> for &'a [u8] { fn borrow_decode>(decoder: &mut D) -> Result { @@ -407,18 +436,6 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a [u8] { } } -impl<'a, 'de: 'a> BorrowDecode<'de> for Option<&'a [u8]> { - fn borrow_decode>(decoder: &mut D) -> Result { - match super::decode_option_variant(decoder, core::any::type_name::>())? { - Some(_) => { - let val = BorrowDecode::borrow_decode(decoder)?; - Ok(Some(val)) - } - None => Ok(None), - } - } -} - impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str { fn borrow_decode>(decoder: &mut D) -> Result { let slice = <&[u8]>::borrow_decode(decoder)?; @@ -426,18 +443,6 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str { } } -impl<'a, 'de: 'a> BorrowDecode<'de> for Option<&'a str> { - fn borrow_decode>(decoder: &mut D) -> Result { - match super::decode_option_variant(decoder, core::any::type_name::>())? { - Some(_) => { - let val = BorrowDecode::borrow_decode(decoder)?; - Ok(Some(val)) - } - None => Ok(None), - } - } -} - impl Decode for [T; N] where T: Decode + Sized + 'static, @@ -479,17 +484,64 @@ where } } +impl<'de, T, const N: usize> BorrowDecode<'de> for [T; N] +where + T: BorrowDecode<'de> + Sized + 'static, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + if !D::C::SKIP_FIXED_ARRAY_LENGTH { + let length = super::decode_slice_len(decoder)?; + if length != N { + return Err(DecodeError::ArrayLengthMismatch { + found: length, + required: N, + }); + } + } + + decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?; + + // Optimize for `[u8; N]` + 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]; + + // 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() }; + Ok(res) + } else { + let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + T::borrow_decode(decoder) + })); + + // result is only None if N does not match the values of `(0..N)`, which it always should + // So this unwrap should never occur + result.unwrap() + } + } +} + impl Decode for () { fn decode(_: &mut D) -> Result { Ok(()) } } +impl_borrow_decode!(()); impl Decode for core::marker::PhantomData { fn decode(_: &mut D) -> Result { Ok(core::marker::PhantomData) } } +impl<'de, T> BorrowDecode<'de> for core::marker::PhantomData { + fn borrow_decode>(_: &mut D) -> Result { + Ok(core::marker::PhantomData) + } +} impl Decode for Option where @@ -506,6 +558,37 @@ where } } +impl<'de, T> BorrowDecode<'de> for Option +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + match super::decode_option_variant(decoder, core::any::type_name::>())? { + Some(_) => { + let val = T::borrow_decode(decoder)?; + Ok(Some(val)) + } + None => Ok(None), + } + } +} + +// BlockedTODO: https://github.com/rust-lang/rust/issues/37653 +// +// We'll want to implement BorrowDecode for both Option<&[u8]> and Option<&[T: Encode]>, +// but those implementations overlap because &'a [u8] also implements BorrowDecode +// impl<'a, 'de: 'a> BorrowDecode<'de> for Option<&'a [u8]> { +// fn borrow_decode>(decoder: &mut D) -> Result { +// match super::decode_option_variant(decoder, core::any::type_name::>())? { +// Some(_) => { +// let val = BorrowDecode::borrow_decode(decoder)?; +// Ok(Some(val)) +// } +// None => Ok(None), +// } +// } +// } + impl Decode for Result where T: Decode, @@ -531,6 +614,31 @@ where } } +impl<'de, T, U> BorrowDecode<'de> for Result +where + T: BorrowDecode<'de>, + U: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let is_ok = u32::decode(decoder)?; + match is_ok { + 0 => { + let t = T::borrow_decode(decoder)?; + Ok(Ok(t)) + } + 1 => { + let u = U::borrow_decode(decoder)?; + Ok(Err(u)) + } + x => Err(DecodeError::UnexpectedVariant { + found: x as u32, + allowed: crate::error::AllowedEnumVariants::Range { max: 1, min: 0 }, + type_name: core::any::type_name::>(), + }), + } + } +} + impl Decode for Cell where T: Decode, @@ -541,6 +649,16 @@ where } } +impl<'de, T> BorrowDecode<'de> for Cell +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(Cell::new(t)) + } +} + impl Decode for RefCell where T: Decode, @@ -551,6 +669,16 @@ where } } +impl<'de, T> BorrowDecode<'de> for RefCell +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(RefCell::new(t)) + } +} + impl Decode for Duration { fn decode(decoder: &mut D) -> Result { const NANOS_PER_SEC: u64 = 1_000_000_000; @@ -562,6 +690,7 @@ impl Decode for Duration { Ok(Duration::new(secs, nanos)) } } +impl_borrow_decode!(Duration); impl Decode for Range where @@ -573,6 +702,16 @@ where Ok(min..max) } } +impl<'de, T> BorrowDecode<'de> for Range +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let min = T::borrow_decode(decoder)?; + let max = T::borrow_decode(decoder)?; + Ok(min..max) + } +} impl Decode for RangeInclusive where @@ -585,6 +724,17 @@ where } } +impl<'de, T> BorrowDecode<'de> for RangeInclusive +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let min = T::borrow_decode(decoder)?; + let max = T::borrow_decode(decoder)?; + Ok(RangeInclusive::new(min, max)) + } +} + impl Decode for Bound where T: Decode, @@ -603,6 +753,24 @@ where } } +impl<'de, T> BorrowDecode<'de> for Bound +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + match u32::decode(decoder)? { + 0 => Ok(Bound::Unbounded), + 1 => Ok(Bound::Included(T::borrow_decode(decoder)?)), + 2 => Ok(Bound::Excluded(T::borrow_decode(decoder)?)), + x => Err(DecodeError::UnexpectedVariant { + allowed: crate::error::AllowedEnumVariants::Range { max: 2, min: 0 }, + found: x, + type_name: core::any::type_name::>(), + }), + } + } +} + 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 diff --git a/src/de/mod.rs b/src/de/mod.rs index a25d372..9348cb2 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -54,6 +54,16 @@ pub use self::decoder::DecoderImpl; /// }) /// } /// } +/// impl<'de> bincode::BorrowDecode<'de> for Entity { +/// fn borrow_decode>( +/// decoder: &mut D, +/// ) -> core::result::Result { +/// Ok(Self { +/// x: bincode::BorrowDecode::borrow_decode(decoder)?, +/// y: bincode::BorrowDecode::borrow_decode(decoder)?, +/// }) +/// } +/// } /// ``` /// /// From here you can add/remove fields, or add custom logic. @@ -70,8 +80,9 @@ pub use self::decoder::DecoderImpl; /// # Ok(Foo) /// # } /// # } +/// # bincode::impl_borrow_decode!(Foo); /// ``` -pub trait Decode: for<'de> BorrowDecode<'de> { +pub trait Decode: Sized { /// Attempt to decode this type with the given [Decode]. fn decode(decoder: &mut D) -> Result; } @@ -86,10 +97,18 @@ pub trait BorrowDecode<'de>: Sized { fn borrow_decode>(decoder: &mut D) -> Result; } -impl<'de, T: Decode> BorrowDecode<'de> for T { - fn borrow_decode(decoder: &mut D) -> Result { - Decode::decode(decoder) - } +/// Helper macro to implement `BorrowDecode` for any type that implements `Decode`. +#[macro_export] +macro_rules! impl_borrow_decode { + ($ty:ty) => { + impl<'de> $crate::BorrowDecode<'de> for $ty { + fn borrow_decode>( + decoder: &mut D, + ) -> core::result::Result { + $crate::Decode::decode(decoder) + } + } + }; } /// Any source that can decode basic types. This type is most notably implemented for [Decoder]. @@ -163,6 +182,24 @@ pub trait Decoder: Sealed { /// Ok(result) /// } /// } + /// impl<'de, T: bincode::BorrowDecode<'de>> bincode::BorrowDecode<'de> for Container { + /// fn borrow_decode>( + /// decoder: &mut D, + /// ) -> core::result::Result { + /// let len = u64::borrow_decode(decoder)?; + /// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?; + /// // Make sure we don't allocate too much memory + /// decoder.claim_bytes_read(len * core::mem::size_of::()); + /// + /// let mut result = Container::with_capacity(len); + /// for _ in 0..len { + /// // un-claim the memory + /// decoder.unclaim_bytes_read(core::mem::size_of::()); + /// result.push(T::borrow_decode(decoder)?) + /// } + /// Ok(result) + /// } + /// } /// ``` fn unclaim_bytes_read(&mut self, n: usize); } diff --git a/src/enc/impls.rs b/src/enc/impls.rs index 0f061ac..40e7234 100644 --- a/src/enc/impls.rs +++ b/src/enc/impls.rs @@ -283,12 +283,12 @@ impl Encode for char { } } -impl Encode for &'_ [u8] { - fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { - super::encode_slice_len(encoder, self.len())?; - encoder.writer().write(self) - } -} +// impl Encode for &'_ [u8] { +// fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { +// super::encode_slice_len(encoder, self.len())?; +// encoder.writer().write(self) +// } +// } const TAG_CONT: u8 = 0b1000_0000; const TAG_TWO_B: u8 = 0b1100_0000; @@ -327,25 +327,24 @@ fn encode_utf8(writer: &mut impl Writer, c: char) -> Result<(), EncodeError> { // BlockedTODO: https://github.com/rust-lang/rust/issues/37653 // // We'll want to implement encoding for both &[u8] and &[T: Encode], -// but those implementations overlap because u8 also implements Encodeabl -// -// default impl Encode for &'_ [u8] { -// fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { -// encoder.encode_slice(*self) -// } -// } -// -// impl Encode for &'_ [T] { -// fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { -// self.len().encode(encoder)?; -// for item in self.iter() { -// item.encode(encoder)?; -// } -// Ok(()) +// but those implementations overlap because u8 also implements Encode +// impl Encode for &'_ [u8] { +// fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { +// encoder.writer().write(*self) // } // } -impl Encode for &'_ str { +impl Encode for &'_ [T] { + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.len().encode(encoder)?; + for item in self.iter() { + item.encode(encoder)?; + } + Ok(()) + } +} + +impl Encode for str { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { self.as_bytes().encode(encoder) } @@ -409,7 +408,7 @@ where impl Encode for RefCell where - T: Encode, + T: Encode + ?Sized, { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { let borrow_guard = self @@ -476,7 +475,7 @@ where impl<'a, T> Encode for &'a T where - T: Encode, + T: Encode + ?Sized, { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { T::encode(self, encoder) diff --git a/src/features/impl_alloc.rs b/src/features/impl_alloc.rs index 5ab83a6..c56d735 100644 --- a/src/features/impl_alloc.rs +++ b/src/features/impl_alloc.rs @@ -1,10 +1,10 @@ use crate::{ - de::{Decode, Decoder}, + de::{BorrowDecoder, Decode, Decoder}, enc::{self, Encode, Encoder}, error::{DecodeError, EncodeError}, - Config, + impl_borrow_decode, BorrowDecode, Config, }; -#[cfg(feature = "atomic")] +#[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; use alloc::{ borrow::{Cow, ToOwned}, @@ -65,6 +65,25 @@ where Ok(map) } } +impl<'de, T> BorrowDecode<'de> for BinaryHeap +where + T: BorrowDecode<'de> + Ord, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::(len)?; + + let mut map = BinaryHeap::with_capacity(len); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + + let key = T::borrow_decode(decoder)?; + map.push(key); + } + Ok(map) + } +} impl Encode for BinaryHeap where @@ -100,6 +119,27 @@ where Ok(map) } } +impl<'de, K, V> BorrowDecode<'de> for BTreeMap +where + K: BorrowDecode<'de> + Ord, + V: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::<(K, V)>(len)?; + + let mut map = BTreeMap::new(); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>()); + + let key = K::borrow_decode(decoder)?; + let value = V::borrow_decode(decoder)?; + map.insert(key, value); + } + Ok(map) + } +} impl Encode for BTreeMap where @@ -135,6 +175,25 @@ where Ok(map) } } +impl<'de, T> BorrowDecode<'de> for BTreeSet +where + T: BorrowDecode<'de> + Ord, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::(len)?; + + let mut map = BTreeSet::new(); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + + let key = T::borrow_decode(decoder)?; + map.insert(key); + } + Ok(map) + } +} impl Encode for BTreeSet where @@ -168,6 +227,25 @@ where Ok(map) } } +impl<'de, T> BorrowDecode<'de> for VecDeque +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::(len)?; + + let mut map = VecDeque::with_capacity(len); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + + let key = T::borrow_decode(decoder)?; + map.push_back(key); + } + Ok(map) + } +} impl Encode for VecDeque where @@ -201,6 +279,25 @@ where } } +impl<'de, T> BorrowDecode<'de> for Vec +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::(len)?; + + let mut vec = Vec::with_capacity(len); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + + vec.push(T::borrow_decode(decoder)?); + } + Ok(vec) + } +} + impl Encode for Vec where T: Encode, @@ -222,6 +319,7 @@ impl Decode for String { }) } } +impl_borrow_decode!(String); impl Encode for String { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -238,10 +336,19 @@ where Ok(Box::new(t)) } } +impl<'de, T> BorrowDecode<'de> for Box +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(Box::new(t)) + } +} impl Encode for Box where - T: Encode, + T: Encode + ?Sized, { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { T::encode(self, encoder) @@ -258,6 +365,16 @@ where } } +impl<'de, T> BorrowDecode<'de> for Box<[T]> +where + T: BorrowDecode<'de> + 'de, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let vec = Vec::borrow_decode(decoder)?; + Ok(vec.into_boxed_slice()) + } +} + impl Encode for Box<[T]> where T: Encode, @@ -271,20 +388,6 @@ where } } -// BlockedTODO: https://github.com/rust-lang/rust/issues/31844 -// Cow should be able to decode a borrowed value -// Currently this conflicts with the owned `Decode` implementation below - -// impl<'cow, T> BorrowDecode<'cow> for Cow<'cow, T> -// where -// T: BorrowDecode<'cow>, -// { -// fn borrow_decode>(decoder: &mut D) -> Result { -// let t = T::borrow_decode(decoder)?; -// Ok(Cow::Borrowed(t)) -// } -// } - impl<'cow, T> Decode for Cow<'cow, T> where T: ToOwned + ?Sized, @@ -295,6 +398,16 @@ where Ok(Cow::Owned(t)) } } +impl<'cow, T> BorrowDecode<'cow> for Cow<'cow, T> +where + T: ToOwned + ?Sized, + &'cow T: BorrowDecode<'cow>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = <&T>::borrow_decode(decoder)?; + Ok(Cow::Borrowed(t)) + } +} impl<'cow, T> Encode for Cow<'cow, T> where @@ -316,16 +429,26 @@ where } } +impl<'de, T> BorrowDecode<'de> for Rc +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(Rc::new(t)) + } +} + impl Encode for Rc where - T: Encode, + T: Encode + ?Sized, { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { T::encode(self, encoder) } } -#[cfg(feature = "atomic")] +#[cfg(target_has_atomic = "ptr")] impl Decode for Arc where T: Decode, @@ -336,10 +459,37 @@ where } } -#[cfg(feature = "atomic")] +#[cfg(target_has_atomic = "ptr")] +impl Decode for Arc { + fn decode(decoder: &mut D) -> Result { + let decoded = String::decode(decoder)?; + Ok(decoded.into()) + } +} + +#[cfg(target_has_atomic = "ptr")] +impl<'de, T> BorrowDecode<'de> for Arc +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(Arc::new(t)) + } +} + +#[cfg(target_has_atomic = "ptr")] +impl<'de> BorrowDecode<'de> for Arc { + fn borrow_decode>(decoder: &mut D) -> Result { + let decoded = String::decode(decoder)?; + Ok(decoded.into()) + } +} + +#[cfg(target_has_atomic = "ptr")] impl Encode for Arc where - T: Encode, + T: Encode + ?Sized, { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { T::encode(self, encoder) diff --git a/src/features/impl_std.rs b/src/features/impl_std.rs index c2ce584..84e242c 100644 --- a/src/features/impl_std.rs +++ b/src/features/impl_std.rs @@ -3,6 +3,7 @@ use crate::{ de::{read::Reader, BorrowDecode, BorrowDecoder, Decode, Decoder, DecoderImpl}, enc::{write::Writer, Encode, Encoder, EncoderImpl}, error::{DecodeError, EncodeError}, + impl_borrow_decode, }; use core::time::Duration; use std::{ @@ -146,6 +147,7 @@ impl Decode for CString { CString::new(vec).map_err(|inner| DecodeError::CStringNulError { inner }) } } +impl_borrow_decode!(CString); impl Encode for Mutex where @@ -168,6 +170,15 @@ where Ok(Mutex::new(t)) } } +impl<'de, T> BorrowDecode<'de> for Mutex +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(Mutex::new(t)) + } +} impl Encode for RwLock where @@ -190,6 +201,15 @@ where Ok(RwLock::new(t)) } } +impl<'de, T> BorrowDecode<'de> for RwLock +where + T: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let t = T::borrow_decode(decoder)?; + Ok(RwLock::new(t)) + } +} impl Encode for SystemTime { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -212,6 +232,7 @@ impl Decode for SystemTime { } } } +impl_borrow_decode!(SystemTime); impl Encode for &'_ Path { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -241,6 +262,7 @@ impl Decode for PathBuf { Ok(string.into()) } } +impl_borrow_decode!(PathBuf); impl Encode for IpAddr { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -270,6 +292,7 @@ impl Decode for IpAddr { } } } +impl_borrow_decode!(IpAddr); impl Encode for Ipv4Addr { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -284,6 +307,7 @@ impl Decode for Ipv4Addr { Ok(Self::from(buff)) } } +impl_borrow_decode!(Ipv4Addr); impl Encode for Ipv6Addr { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -298,6 +322,7 @@ impl Decode for Ipv6Addr { Ok(Self::from(buff)) } } +impl_borrow_decode!(Ipv6Addr); impl Encode for SocketAddr { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -327,6 +352,7 @@ impl Decode for SocketAddr { } } } +impl_borrow_decode!(SocketAddr); impl Encode for SocketAddrV4 { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -342,6 +368,7 @@ impl Decode for SocketAddrV4 { Ok(Self::new(ip, port)) } } +impl_borrow_decode!(SocketAddrV4); impl Encode for SocketAddrV6 { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -357,6 +384,7 @@ impl Decode for SocketAddrV6 { Ok(Self::new(ip, port, 0, 0)) } } +impl_borrow_decode!(SocketAddrV6); impl std::error::Error for EncodeError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { @@ -416,6 +444,27 @@ where Ok(map) } } +impl<'de, K, V> BorrowDecode<'de> for HashMap +where + K: BorrowDecode<'de> + Eq + std::hash::Hash, + V: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::<(K, V)>(len)?; + + let mut map = HashMap::with_capacity(len); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>()); + + let k = K::borrow_decode(decoder)?; + let v = V::borrow_decode(decoder)?; + map.insert(k, v); + } + Ok(map) + } +} impl Decode for HashSet where @@ -439,6 +488,27 @@ where } } +impl<'de, T, S> BorrowDecode<'de> for HashSet +where + T: BorrowDecode<'de> + Eq + Hash, + S: std::hash::BuildHasher + Default, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = crate::de::decode_slice_len(decoder)?; + decoder.claim_container_read::(len)?; + + let mut map = HashSet::with_capacity_and_hasher(len, S::default()); + for _ in 0..len { + // See the documentation on `unclaim_bytes_read` as to why we're doing this here + decoder.unclaim_bytes_read(core::mem::size_of::()); + + let key = T::borrow_decode(decoder)?; + map.insert(key); + } + Ok(map) + } +} + impl Encode for HashSet where T: Encode, diff --git a/src/features/serde/mod.rs b/src/features/serde/mod.rs index d7e5911..fc3952f 100644 --- a/src/features/serde/mod.rs +++ b/src/features/serde/mod.rs @@ -193,6 +193,17 @@ where T::deserialize(serde_decoder).map(Compat) } } +impl<'de, T> crate::BorrowDecode<'de> for Compat +where + T: serde::de::DeserializeOwned, +{ + fn borrow_decode>( + decoder: &mut D, + ) -> Result { + let serde_decoder = de_owned::SerdeDecoder { de: decoder }; + T::deserialize(serde_decoder).map(Compat) + } +} impl crate::Encode for Compat where diff --git a/src/lib.rs b/src/lib.rs index f2f5176..9c13e47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ use enc::write::Writer; pub use features::*; pub mod config; +#[macro_use] pub mod de; pub mod enc; pub mod error; @@ -136,7 +137,23 @@ pub fn encode_into_writer( /// See the [config] module for more information on configurations. /// /// [config]: config/index.html -pub fn decode_from_slice<'a, D: de::BorrowDecode<'a>, C: Config>( +pub fn decode_from_slice( + src: &[u8], + config: C, +) -> Result<(D, usize), error::DecodeError> { + let reader = de::read::SliceReader::new(src); + let mut decoder = de::DecoderImpl::<_, C>::new(reader, config); + let result = D::decode(&mut decoder)?; + let bytes_read = src.len() - decoder.reader().slice.len(); + Ok((result, bytes_read)) +} + +/// Attempt to decode a given type `D` from the given slice. +/// +/// See the [config] module for more information on configurations. +/// +/// [config]: config/index.html +pub fn borrow_decode_from_slice<'a, D: de::BorrowDecode<'a>, C: Config>( src: &'a [u8], config: C, ) -> Result<(D, usize), error::DecodeError> { diff --git a/src/varint/decode_unsigned.rs b/src/varint/decode_unsigned.rs index 1d53751..7b0fc27 100644 --- a/src/varint/decode_unsigned.rs +++ b/src/varint/decode_unsigned.rs @@ -496,7 +496,7 @@ fn test_decode_u64() { (&[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, + 720_575_940_379_279_360, 10, ), ]; @@ -574,7 +574,7 @@ fn test_decode_u128() { (&[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, + 720_575_940_379_279_360, 10, ), ( diff --git a/src/varint/encode_unsigned.rs b/src/varint/encode_unsigned.rs index 6c1138d..c0966e0 100644 --- a/src/varint/encode_unsigned.rs +++ b/src/varint/encode_unsigned.rs @@ -275,7 +275,7 @@ fn test_encode_u64() { // 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] { + for i in [u32::MAX as u64 + 1, 5_000_000_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); @@ -351,7 +351,7 @@ fn test_encode_u128() { // 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] { + for i in [u32::MAX as u128 + 1, 5_000_000_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); diff --git a/tests/alloc.rs b/tests/alloc.rs index 37b55bb..b308605 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -1,3 +1,4 @@ +#![allow(clippy::blacklisted_name)] #![cfg(feature = "alloc")] extern crate alloc; @@ -8,7 +9,7 @@ use alloc::borrow::Cow; use alloc::collections::*; #[cfg(not(feature = "serde"))] use alloc::rc::Rc; -#[cfg(all(feature = "atomic", not(feature = "serde")))] +#[cfg(all(target_has_atomic = "ptr", not(feature = "serde")))] use alloc::sync::Arc; use utils::{the_same, the_same_with_comparer}; @@ -38,6 +39,7 @@ impl bincode::Decode for Foo { }) } } +bincode::impl_borrow_decode!(Foo); #[test] fn test_vec() { @@ -49,6 +51,30 @@ fn test_vec() { assert_eq!(foo.a, 5); assert_eq!(foo.b, 10); assert_eq!(len, 2); + + let vec: Vec = bincode::decode_from_slice( + &[4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4], + bincode::config::legacy(), + ) + .unwrap() + .0; + assert_eq!(vec, &[1, 2, 3, 4]); + + let vec: Vec> = bincode::decode_from_slice( + &[4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4], + bincode::config::legacy(), + ) + .unwrap() + .0; + assert_eq!( + vec, + &[ + Cow::Borrowed(&1), + Cow::Borrowed(&2), + Cow::Borrowed(&3), + Cow::Borrowed(&4) + ] + ); } #[test] @@ -59,12 +85,16 @@ fn test_alloc_commons() { the_same(Box::<[u32]>::from(vec![1, 2, 3, 4, 5])); the_same(Cow::::Owned(5)); the_same(Cow::::Borrowed(&5)); - // Serde doesn't support Rc #[cfg(not(feature = "serde"))] - the_same(Rc::::new(5)); - // serde doesn't support Arc - #[cfg(all(feature = "atomic", not(feature = "serde")))] - the_same(Arc::::new(5)); + { + // Serde doesn't support Rc or Arc + the_same(Rc::::new(5)); + #[cfg(target_has_atomic = "ptr")] + { + the_same(Arc::::new(5)); + } + } + the_same_with_comparer( { let mut map = BinaryHeap::::new(); @@ -75,7 +105,7 @@ fn test_alloc_commons() { map.push(5); map }, - |a, b| a.into_iter().collect::>() == b.into_iter().collect::>(), + |a, b| a.iter().collect::>() == b.iter().collect::>(), ); the_same({ let mut map = BTreeMap::::new(); @@ -97,7 +127,7 @@ fn test_alloc_commons() { #[test] fn test_container_limits() { - use bincode::{error::DecodeError, Decode}; + use bincode::{error::DecodeError, BorrowDecode, Decode}; const DECODE_LIMIT: usize = 100_000; @@ -112,7 +142,7 @@ fn test_container_limits() { bincode::encode_to_vec(DECODE_LIMIT as u64, bincode::config::standard()).unwrap(), ]; - fn validate_fail(slice: &[u8]) { + fn validate_fail BorrowDecode<'de> + core::fmt::Debug>(slice: &[u8]) { let result = bincode::decode_from_slice::( slice, bincode::config::standard().with_limit::(), @@ -134,7 +164,6 @@ fn test_container_limits() { validate_fail::>(slice); validate_fail::>(slice); validate_fail::(slice); - validate_fail::>(slice); #[cfg(feature = "std")] { validate_fail::>(slice); @@ -142,3 +171,22 @@ fn test_container_limits() { } } } + +#[cfg(target_has_atomic = "ptr")] +#[test] +fn test_arc_str() { + use alloc::sync::Arc; + + let start: Arc = Arc::from("Example String"); + let mut target = [0u8; 100]; + let config = bincode::config::standard(); + + let len = { + let start: Arc = Arc::clone(&start); + bincode::encode_into_slice(start, &mut target, config).unwrap() + }; + let slice = &target[..len]; + + let decoded: Arc = bincode::borrow_decode_from_slice(slice, config).unwrap().0; + assert_eq!(decoded, start); +} diff --git a/tests/atomic.rs b/tests/atomic.rs index 41e53e8..136d3fd 100644 --- a/tests/atomic.rs +++ b/tests/atomic.rs @@ -1,48 +1,65 @@ -#![cfg(feature = "atomic")] - mod utils; -use core::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, - AtomicU64, AtomicU8, AtomicUsize, Ordering, -}; +use core::sync::atomic::Ordering; +#[cfg(target_has_atomic = "8")] +use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; +#[cfg(target_has_atomic = "16")] +use core::sync::atomic::{AtomicI16, AtomicU16}; +#[cfg(target_has_atomic = "32")] +use core::sync::atomic::{AtomicI32, AtomicU32}; +#[cfg(target_has_atomic = "64")] +use core::sync::atomic::{AtomicI64, AtomicU64}; +#[cfg(target_has_atomic = "ptr")] +use core::sync::atomic::{AtomicIsize, AtomicUsize}; use utils::the_same_with_comparer; #[test] fn test_atomic_commons() { + #[cfg(target_has_atomic = "8")] the_same_with_comparer(AtomicBool::new(true), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "8")] the_same_with_comparer(AtomicBool::new(false), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "8")] the_same_with_comparer(AtomicU8::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "16")] the_same_with_comparer(AtomicU16::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "32")] the_same_with_comparer(AtomicU32::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "64")] the_same_with_comparer(AtomicU64::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "ptr")] the_same_with_comparer(AtomicUsize::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "8")] the_same_with_comparer(AtomicI8::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "16")] the_same_with_comparer(AtomicI16::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "32")] the_same_with_comparer(AtomicI32::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "64")] the_same_with_comparer(AtomicI64::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); + #[cfg(target_has_atomic = "ptr")] the_same_with_comparer(AtomicIsize::new(0), |a, b| { a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) }); diff --git a/tests/basic_types.rs b/tests/basic_types.rs index db6ae72..a69c3de 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -138,7 +138,7 @@ fn test_slice() { assert_eq!(&buffer[..8], &[7, 1, 2, 3, 4, 5, 6, 7]); let (output, len): (&[u8], usize) = - bincode::decode_from_slice(&mut buffer[..8], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..8], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, 8); } @@ -151,7 +151,7 @@ fn test_option_slice() { assert_eq!(&buffer[..n], &[1, 7, 1, 2, 3, 4, 5, 6, 7]); let (output, len): (Option<&[u8]>, usize) = - bincode::decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, n); @@ -161,7 +161,7 @@ fn test_option_slice() { assert_eq!(&buffer[..n], &[0]); let (output, len): (Option<&[u8]>, usize) = - bincode::decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, n); } @@ -177,7 +177,7 @@ fn test_str() { ); let (output, len): (&str, usize) = - bincode::decode_from_slice(&mut buffer[..12], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..12], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, 12); } @@ -193,7 +193,7 @@ fn test_option_str() { ); let (output, len): (Option<&str>, usize) = - bincode::decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, n); @@ -203,7 +203,7 @@ fn test_option_str() { assert_eq!(&buffer[..n], &[0]); let (output, len): (Option<&str>, usize) = - bincode::decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, n); } @@ -219,7 +219,7 @@ fn test_array() { ); let (output, len): ([u8; 10], usize) = - bincode::decode_from_slice(&mut buffer[..11], bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&buffer[..11], bincode::config::standard()).unwrap(); assert_eq!(input, output); assert_eq!(len, 11); @@ -234,7 +234,7 @@ fn test_array() { assert_eq!(&buffer[..9], &[1, 0, 0, 0, 0, 0, 0, 0, 1]); let (output, len): (&[u8], usize) = - bincode::decode_from_slice(&mut buffer[..9], config).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..9], config).unwrap(); assert_eq!(input, output); assert_eq!(len, 9); } @@ -251,7 +251,7 @@ fn test_duration_out_of_range() { .unwrap(); let result: Result<(std::time::Duration, usize), _> = - bincode::decode_from_slice(&mut input, bincode::config::standard()); + bincode::decode_from_slice(&input, bincode::config::standard()); assert_eq!( result.unwrap_err(), @@ -274,7 +274,7 @@ fn test_duration_wrapping() { .unwrap(); let (result, _): (std::time::Duration, _) = - bincode::decode_from_slice(&mut input, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&input, bincode::config::standard()).unwrap(); assert_eq!(result.as_secs(), u64::MAX); diff --git a/tests/derive.rs b/tests/derive.rs index dfb7d4e..2ef7a70 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -20,12 +20,40 @@ fn test_encode() { assert_eq!(bytes_written, 3); assert_eq!(&slice[..bytes_written], &[10, 10, 20]); } -#[derive(bincode::Decode, PartialEq, Debug, Eq)] +#[derive(PartialEq, Debug, Eq)] pub struct Test2 { a: T, b: u32, c: u32, } +impl ::bincode::Decode for Test2 +where + T: ::bincode::Decode, +{ + fn decode( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + a: ::bincode::Decode::decode(decoder)?, + b: ::bincode::Decode::decode(decoder)?, + c: ::bincode::Decode::decode(decoder)?, + }) + } +} +impl<'__de, T> ::bincode::BorrowDecode<'__de> for Test2 +where + T: ::bincode::BorrowDecode<'__de> + '__de, +{ + fn borrow_decode>( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + a: ::bincode::BorrowDecode::borrow_decode(decoder)?, + b: ::bincode::BorrowDecode::borrow_decode(decoder)?, + c: ::bincode::BorrowDecode::borrow_decode(decoder)?, + }) + } +} #[test] fn test_decode() { @@ -62,7 +90,7 @@ fn test_encode_decode_str() { let len = bincode::encode_into_slice(&start, &mut slice, bincode::config::standard()).unwrap(); assert_eq!(len, 21); let (end, len): (Test3, usize) = - bincode::decode_from_slice(&slice[..len], bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&slice[..len], bincode::config::standard()).unwrap(); assert_eq!(end, start); assert_eq!(len, 21); } @@ -83,9 +111,9 @@ fn test_encode_tuple() { #[test] fn test_decode_tuple() { let start = TestTupleStruct(5, 10, 1024); - let mut slice = [5, 10, 251, 0, 4]; + let slice = [5, 10, 251, 0, 4]; let (result, len): (TestTupleStruct, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 5); } @@ -109,9 +137,9 @@ fn test_encode_enum_struct_variant() { #[test] fn test_decode_enum_struct_variant() { let start = TestEnum::Bar { name: 5u32 }; - let mut slice = [1, 5]; + let slice = [1, 5]; let (result, len): (TestEnum, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 2); } @@ -119,9 +147,9 @@ fn test_decode_enum_struct_variant() { #[test] fn test_decode_enum_unit_variant() { let start = TestEnum::Foo; - let mut slice = [0]; + let slice = [0]; let (result, len): (TestEnum, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 1); } @@ -149,9 +177,9 @@ fn test_encode_enum_tuple_variant() { #[test] fn test_decode_enum_tuple_variant() { let start = TestEnum::Baz(5, 10, 1024); - let mut slice = [2, 5, 10, 251, 0, 4]; + let slice = [2, 5, 10, 251, 0, 4]; let (result, len): (TestEnum, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 6); } @@ -176,9 +204,9 @@ fn test_encode_borrowed_enum_struct_variant() { #[test] fn test_decode_borrowed_enum_struct_variant() { let start = TestEnum2::Bar { name: "foo" }; - let mut slice = [1, 3, 102, 111, 111]; + let slice = [1, 3, 102, 111, 111]; let (result, len): (TestEnum2, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 5); } @@ -186,9 +214,9 @@ fn test_decode_borrowed_enum_struct_variant() { #[test] fn test_decode_borrowed_enum_unit_variant() { let start = TestEnum2::Foo; - let mut slice = [0]; + let slice = [0]; let (result, len): (TestEnum2, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 1); } @@ -216,9 +244,9 @@ fn test_encode_borrowed_enum_tuple_variant() { #[test] fn test_decode_borrowed_enum_tuple_variant() { let start = TestEnum2::Baz(5, 10, 1024); - let mut slice = [2, 5, 10, 251, 0, 4]; + let slice = [2, 5, 10, 251, 0, 4]; let (result, len): (TestEnum2, usize) = - bincode::decode_from_slice(&mut slice, bincode::config::standard()).unwrap(); + bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap(); assert_eq!(result, start); assert_eq!(len, 6); } @@ -365,3 +393,45 @@ fn test_enum_with_generics_roundtrip() { .0; assert_eq!(start, decoded); } + +#[cfg(feature = "alloc")] +mod zoxide { + extern crate alloc; + + use alloc::borrow::Cow; + use bincode::{Decode, Encode}; + + pub type Rank = f64; + pub type Epoch = u64; + + #[derive(Encode, Decode)] + pub struct Dir<'a> { + pub path: Cow<'a, str>, + pub rank: Rank, + pub last_accessed: Epoch, + } + + #[test] + fn test() { + let dirs = &[ + Dir { + path: Cow::Borrowed("Foo"), + rank: 1.23, + last_accessed: 5, + }, + Dir { + path: Cow::Owned(String::from("Bar")), + rank: 2.34, + last_accessed: 10, + }, + ]; + let config = bincode::config::standard(); + + let slice = bincode::encode_to_vec(dirs, config).unwrap(); + let decoded: Vec = bincode::borrow_decode_from_slice(&slice, config).unwrap().0; + + assert_eq!(decoded.len(), 2); + assert!(matches!(decoded[0].path, Cow::Borrowed("Foo"))); + assert!(matches!(decoded[1].path, Cow::Borrowed("Bar"))); + } +} diff --git a/tests/issues/issue_431.rs b/tests/issues/issue_431.rs index e405c28..7b9520d 100644 --- a/tests/issues/issue_431.rs +++ b/tests/issues/issue_431.rs @@ -6,12 +6,14 @@ use bincode::{Decode, Encode}; use std::borrow::Cow; use std::string::String; -#[derive(Encode, Decode, PartialEq, Debug)] +#[derive(Decode, Encode, PartialEq, Debug)] +#[bincode(borrow_decode_bounds = "&'__de U<'a, A>: ::bincode::de::BorrowDecode<'__de> + '__de")] struct T<'a, A: Clone + Encode + Decode> { t: Cow<'a, U<'a, A>>, } -#[derive(Clone, Encode, Decode, PartialEq, Debug)] +#[derive(Clone, Decode, Encode, PartialEq, Debug)] +#[bincode(borrow_decode_bounds = "&'__de A: ::bincode::de::BorrowDecode<'__de> + '__de")] struct U<'a, A: Clone + Encode + Decode> { u: Cow<'a, A>, } diff --git a/tests/issues/issue_474.rs b/tests/issues/issue_474.rs index 466ef51..941e8c5 100644 --- a/tests/issues/issue_474.rs +++ b/tests/issues/issue_474.rs @@ -66,7 +66,7 @@ impl MemCache { let encoded = bincode::serde::encode_to_vec(&cache_data, config)?; let cache_item = CacheItem::new(encoded, expire_seconds); - guard.insert(key.clone(), cache_item); + guard.insert(*key, cache_item); Ok(()) } diff --git a/tests/serde.rs b/tests/serde.rs index 48eb8bb..d742db7 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -178,7 +178,7 @@ mod derive { assert_eq!(len, expected_len); let slice = &slice[..len]; let (result, len): (T, usize) = - bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap(); + bincode::decode_from_slice(slice, bincode::config::standard()).unwrap(); assert_eq!(start, result); assert_eq!(len, expected_len); diff --git a/tests/std.rs b/tests/std.rs index e4a392d..79fad9f 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -1,3 +1,4 @@ +#![allow(clippy::blacklisted_name)] #![cfg(feature = "std")] mod utils; @@ -89,10 +90,10 @@ fn test_std_commons() { 0, ))); the_same_with_comparer(Mutex::new("Hello world".to_string()), |a, b| { - &*a.lock().unwrap() == &*b.lock().unwrap() + *a.lock().unwrap() == *b.lock().unwrap() }); the_same_with_comparer(RwLock::new("Hello world".to_string()), |a, b| { - &*a.read().unwrap() == &*b.read().unwrap() + *a.read().unwrap() == *b.read().unwrap() }); let mut map = std::collections::HashMap::new(); @@ -128,7 +129,7 @@ fn test_std_commons() { let cstr = CStr::from_bytes_with_nul(b"Hello world\0").unwrap(); let len = bincode::encode_into_slice(cstr, &mut buffer, config).unwrap(); let (decoded, len): (CString, usize) = - bincode::decode_from_slice(&mut buffer[..len], config).unwrap(); + bincode::decode_from_slice(&buffer[..len], config).unwrap(); assert_eq!(cstr, decoded.as_c_str()); assert_eq!(len, 12); @@ -136,17 +137,17 @@ fn test_std_commons() { let path = Path::new("C:/Program Files/Foo"); let len = bincode::encode_into_slice(path, &mut buffer, config).unwrap(); let (decoded, len): (&Path, usize) = - bincode::decode_from_slice(&mut buffer[..len], config).unwrap(); + bincode::borrow_decode_from_slice(&buffer[..len], config).unwrap(); assert_eq!(path, decoded); assert_eq!(len, 21); } #[test] fn test_system_time_out_of_range() { - let mut input = [0xfd, 0x90, 0x0c, 0xfd, 0xfd, 0x90, 0x0c, 0xfd, 0x90, 0x90]; + let input = [0xfd, 0x90, 0x0c, 0xfd, 0xfd, 0x90, 0x0c, 0xfd, 0x90, 0x90]; let result: Result<(std::time::SystemTime, usize), _> = - bincode::decode_from_slice(&mut input, bincode::config::standard()); + bincode::decode_from_slice(&input, bincode::config::standard()); assert_eq!( result.unwrap_err(), diff --git a/tests/utils.rs b/tests/utils.rs index a861b9e..a1bac55 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -15,11 +15,10 @@ where &buffer[..len], core::any::type_name::() ); - let (decoded, decoded_len): (V, usize) = - bincode::decode_from_slice(&mut buffer, config).unwrap(); + let (decoded, decoded_len): (V, usize) = bincode::decode_from_slice(&buffer, config).unwrap(); assert!( - cmp(&element, &decoded), + cmp(element, &decoded), "Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}", decoded, element, @@ -57,7 +56,7 @@ where ); assert!( - cmp(&element, &decoded), + cmp(element, &decoded), "Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}", decoded, element,