From 6e40dadaa3fead60076ee45f170390b583cb8f55 Mon Sep 17 00:00:00 2001 From: s4h Date: Wed, 4 Sep 2024 10:05:12 +0100 Subject: [PATCH 1/3] Fix Bytes serde support + add test --- Cargo.lock | 10 ++++++++++ Cargo.toml | 3 ++- src/bytes.rs | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fcdf1110..6512dc943 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -638,6 +638,7 @@ dependencies = [ "safer_ffi-proc_macros", "scopeguard", "serde", + "serde_test", "stabby", "tokio", "uninit", @@ -710,6 +711,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_test" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +dependencies = [ + "serde", +] + [[package]] name = "sha2-const-stable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 995b2f1d9..61b59ad4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docs)'] } safer-ffi.path = "." safer-ffi.features = ["internal-tests"] rand = "0.8.5" +serde_test = { version = "1.0.177" } [dependencies] async-compat.optional = true @@ -111,7 +112,7 @@ paste.version = "1.0.12" scopeguard.version = "1.1.0" scopeguard.default-features = false -serde.version = "1.0.204" +serde.version = "1.0.171" serde.optional = true serde.default-features = false diff --git a/src/bytes.rs b/src/bytes.rs index 0c10869c8..f36e661c6 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -826,8 +826,43 @@ impl<'a> serde::Serialize for Bytes<'a> { } #[cfg(feature = "serde")] -impl<'a, 'de: 'a> serde::Deserialize<'de> for Bytes<'a> { +struct BytesVisitor; + +#[cfg(feature = "serde")] +impl<'de> serde::de::Visitor<'de> for BytesVisitor { + type Value = Bytes<'de>; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a byte array") + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result { + Ok(Bytes::from_slice(v)) + } +} + +#[cfg(feature = "serde")] +impl<'de: 'a, 'a> serde::Deserialize<'de> for Bytes<'a> { fn deserialize>(deserializer: D) -> Result { - serde::Deserialize::deserialize(deserializer).map(|x: &[u8]| Bytes::from(x)) + deserializer.deserialize_bytes(BytesVisitor) + } +} + +#[cfg(all(feature = "serde", test))] +mod tests { + use serde_test::{assert_tokens, Token}; + + use super::*; + + #[test] + fn serde() { + let bytes: Bytes<'static> = Bytes::from_static(b"Hello there"); + + assert_tokens(&bytes, &[Token::BorrowedBytes(b"Hello there")]); + + let data = b"Hello there"; + let bytes: Bytes<'_> = Bytes::from(data); + + assert_tokens(&bytes, &[Token::BorrowedBytes(b"Hello there")]); } } From 3e7fbb44f6174a69f2a9b425dbcec276ff7228b9 Mon Sep 17 00:00:00 2001 From: s4h Date: Wed, 4 Sep 2024 10:19:29 +0100 Subject: [PATCH 2/3] Don't blow up when a deserializer returns a Seq --- src/bytes.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index f36e661c6..2af5c6bf0 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -839,6 +839,19 @@ impl<'de> serde::de::Visitor<'de> for BytesVisitor { fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result { Ok(Bytes::from_slice(v)) } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut buf = Vec::with_capacity(seq.size_hint().unwrap_or(64)); + + while let Some(c) = seq.next_element::()? { + buf.push(c); + } + + Ok(Bytes::from(buf)) + } } #[cfg(feature = "serde")] From 42072417ccf04bab22e258a8105b3087991a6c20 Mon Sep 17 00:00:00 2001 From: s4h Date: Wed, 4 Sep 2024 10:34:39 +0100 Subject: [PATCH 3/3] Cover byte/bytebuf cases --- src/bytes.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index 2af5c6bf0..4226029e4 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -840,6 +840,14 @@ impl<'de> serde::de::Visitor<'de> for BytesVisitor { Ok(Bytes::from_slice(v)) } + fn visit_bytes(self, v: &[u8]) -> Result { + Ok(Bytes::from_slice(v).upgrade()) + } + + fn visit_byte_buf(self, v: Vec) -> Result { + Ok(Bytes::from(v)) + } + fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, @@ -857,13 +865,13 @@ impl<'de> serde::de::Visitor<'de> for BytesVisitor { #[cfg(feature = "serde")] impl<'de: 'a, 'a> serde::Deserialize<'de> for Bytes<'a> { fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_bytes(BytesVisitor) + deserializer.deserialize_byte_buf(BytesVisitor) } } #[cfg(all(feature = "serde", test))] mod tests { - use serde_test::{assert_tokens, Token}; + use serde_test::{assert_de_tokens, assert_tokens, Token}; use super::*; @@ -877,5 +885,32 @@ mod tests { let bytes: Bytes<'_> = Bytes::from(data); assert_tokens(&bytes, &[Token::BorrowedBytes(b"Hello there")]); + + // deserialize from a sequence (like we get with serde_cbor) + assert_de_tokens( + &Bytes::from(&[0, 1, 2]), + &[ + Token::Seq { len: Some(3) }, + Token::U8(0), + Token::U8(1), + Token::U8(2), + Token::SeqEnd, + ], + ); + + assert_de_tokens( + &Bytes::from(&[0, 1, 2]), + &[ + Token::Seq { len: None }, + Token::U8(0), + Token::U8(1), + Token::U8(2), + Token::SeqEnd, + ], + ); + + assert_de_tokens(&Bytes::from(&[0, 1, 2]), &[Token::Bytes(&[0, 1, 2])]); + + assert_de_tokens(&Bytes::from(&[0, 1, 2]), &[Token::ByteBuf(&[0, 1, 2])]); } }