From 508e3e5e35615f9173d9bb7317e108a8132a692e Mon Sep 17 00:00:00 2001 From: Mark Juggurnauth-Thomas Date: Thu, 2 Feb 2023 13:02:29 +0000 Subject: [PATCH] Add optional Bincode 2 support Bincode 2.0 will include its own traits for encoding and decoding, which are more efficient than going via `serde`. Add implementations of these traits for `SmallVec` if the `bincode2` feature is enabled. --- Cargo.toml | 1 + src/lib.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tests.rs | 24 ++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 90209b7..6278306 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ debugger_visualizer = [] [dependencies] serde = { version = "1", optional = true, default-features = false } arbitrary = { version = "1", optional = true } +bincode2 = { package = "bincode", version = "2.0.0-rc", optional = true, default-features = false } [dev_dependencies] bincode = "1.0.1" diff --git a/src/lib.rs b/src/lib.rs index a335ca4..c9013df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,11 @@ //! When this optional dependency is enabled, `SmallVec` implements the `serde::Serialize` and //! `serde::Deserialize` traits. //! +//! ### `bincode2` +//! +//! When this optional dependency is enabled, `SmallVec` implements the `bincode::Encode`, +//! `bincode::Decode` and `bincode::BorrowDecode` traits from Bincode 2. +//! //! ### `write` //! //! When this feature is enabled, `SmallVec<[u8; _]>` implements the `std::io::Write` trait. @@ -119,6 +124,14 @@ use serde::{ ser::{Serialize, SerializeSeq, Serializer}, }; +#[cfg(feature = "bincode2")] +use bincode2::{ + de::{BorrowDecoder, Decode, Decoder}, + enc::{Encode, Encoder}, + error::{DecodeError, EncodeError}, + BorrowDecode, +}; + #[cfg(feature = "serde")] use core::marker::PhantomData; @@ -1670,6 +1683,63 @@ where } } +#[cfg(feature = "bincode2")] +impl Decode for SmallVec +where + A: Array, + A::Item: Decode, +{ + fn decode(decoder: &mut D) -> Result { + let len = usize::decode(decoder)?; + decoder.claim_container_read::(len)?; + + let mut vec = SmallVec::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(A::Item::decode(decoder)?); + } + Ok(vec) + } +} + +#[cfg(feature = "bincode2")] +impl<'de, A> BorrowDecode<'de> for SmallVec +where + A: Array, + A::Item: BorrowDecode<'de>, +{ + fn borrow_decode>(decoder: &mut D) -> Result { + let len = usize::decode(decoder)?; + decoder.claim_container_read::(len)?; + + let mut vec = SmallVec::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(A::Item::borrow_decode(decoder)?); + } + Ok(vec) + } +} + +#[cfg(feature = "bincode2")] +impl Encode for SmallVec +where + A: Array, + A::Item: Encode, +{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.len().encode(encoder)?; + for item in self.iter() { + item.encode(encoder)?; + } + Ok(()) + } +} + #[cfg(feature = "specialization")] trait SpecFrom { fn spec_from(slice: S) -> SmallVec; diff --git a/src/tests.rs b/src/tests.rs index 7643fd7..99d37ce 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -983,3 +983,27 @@ fn test_clone_from() { b.clone_from(&c); assert_eq!(&*b, &[20, 21, 22]); } + +#[cfg(feature = "bincode2")] +#[test] +fn test_bincode2() { + let config = bincode2::config::standard(); + let mut small_vec: SmallVec<[i32; 2]> = SmallVec::new(); + let mut buffer = [0u8; 128]; + small_vec.push(1); + let bytes_written = bincode2::encode_into_slice(&small_vec, &mut buffer, config).unwrap(); + let (decoded, bytes_read) = + bincode2::decode_from_slice::, _>(&buffer, config).unwrap(); + assert_eq!(bytes_written, bytes_read); + assert_eq!(small_vec, decoded); + small_vec.push(2); + // Spill the vec + small_vec.push(3); + small_vec.push(4); + // Check again after spilling. + let bytes_written = bincode2::encode_into_slice(&small_vec, &mut buffer, config).unwrap(); + let (decoded, bytes_read) = + bincode2::decode_from_slice::, _>(&buffer, config).unwrap(); + assert_eq!(bytes_written, bytes_read); + assert_eq!(small_vec, decoded); +}