From b196559818622f432942604303a374c6b475072c Mon Sep 17 00:00:00 2001 From: Arthur Silva Date: Tue, 2 May 2017 19:51:52 +0200 Subject: [PATCH] Add serde support behind serde feature (#96) --- .travis.yml | 3 ++ Cargo.toml | 3 +- README.md | 9 +++++ ci/script.sh | 4 +-- src/lib.rs | 5 +++ src/serde.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++ tests/test_serde.rs | 21 ++++++++++++ 7 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 src/serde.rs create mode 100644 tests/test_serde.rs diff --git a/.travis.yml b/.travis.yml index 9fc0dc9..eb0d1eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,9 @@ matrix: - env: RUST_TEST_THREADS=1 TARGET=powerpc-unknown-linux-gnu - env: RUST_TEST_THREADS=1 TARGET=powerpc64-unknown-linux-gnu + # Serde implementation + - env: EXTRA_ARGS="--features serde" + before_install: set -e install: diff --git a/Cargo.toml b/Cargo.toml index 81499be..189513f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ categories = ["network-programming", "data-structures"] [dependencies] byteorder = "1.0.0" iovec = "0.1" +serde = { version = "1.0", optional = true } [dev-dependencies] -tokio-core = "0.1.0" +serde_test = "1.0" diff --git a/README.md b/README.md index 13d3aca..3a88c56 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,15 @@ extern crate bytes; use bytes::{Bytes, BytesMut, Buf, BufMut}; ``` +## Serde support + +Serde support is optional and disabled by default. To enable use the feature `serde`. + +```toml +[dependencies] +bytes = { version = "0.4", features = ["serde"] } +``` + # License `bytes` is primarily distributed under the terms of both the MIT license and the diff --git a/ci/script.sh b/ci/script.sh index e61e155..d1ed7f9 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -3,13 +3,13 @@ set -ex main() { - cross build --target $TARGET + cross build --target $TARGET $EXTRA_ARGS if [ ! -z $DISABLE_TESTS ]; then return fi - cross test --target $TARGET + cross test --target $TARGET $EXTRA_ARGS } # we don't run the "test phase" when doing deploys diff --git a/src/lib.rs b/src/lib.rs index f4bb087..fcea800 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,3 +93,8 @@ mod debug; pub use bytes::{Bytes, BytesMut}; pub use byteorder::{ByteOrder, BigEndian, LittleEndian}; + +// Optional Serde support +#[cfg(feature = "serde")] +#[doc(hidden)] +pub mod serde; diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 0000000..d45caff --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,82 @@ +extern crate serde; + +use std::{cmp, fmt}; +use self::serde::{Serialize, Serializer, Deserialize, Deserializer, de}; +use super::{Bytes, BytesMut}; + +macro_rules! serde_impl { + ($ty:ident, $visitor_ty:ident) => ( + impl Serialize for $ty { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_bytes(&self) + } + } + + struct $visitor_ty; + + impl<'de> de::Visitor<'de> for $visitor_ty { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + #[inline] + fn visit_seq(self, mut seq: V) -> Result + where V: de::SeqAccess<'de> + { + let len = cmp::min(seq.size_hint().unwrap_or(0), 4096); + let mut values = Vec::with_capacity(len); + + while let Some(value) = try!(seq.next_element()) { + values.push(value); + } + + Ok(values.into()) + } + + #[inline] + fn visit_bytes(self, v: &[u8]) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_byte_buf(self, v: Vec) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_str(self, v: &str) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_string(self, v: String) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + } + + impl<'de> Deserialize<'de> for $ty { + #[inline] + fn deserialize(deserializer: D) -> Result<$ty, D::Error> + where D: Deserializer<'de> + { + deserializer.deserialize_byte_buf($visitor_ty) + } + } + ); +} + +serde_impl!(Bytes, BytesVisitor); +serde_impl!(BytesMut, BytesMutVisitor); diff --git a/tests/test_serde.rs b/tests/test_serde.rs new file mode 100644 index 0000000..ff44024 --- /dev/null +++ b/tests/test_serde.rs @@ -0,0 +1,21 @@ +#![cfg(feature = "serde")] + +extern crate bytes; +extern crate serde_test; +use serde_test::{Token, assert_tokens}; + +#[test] +fn test_ser_de_empty() { + let b = bytes::Bytes::new(); + assert_tokens(&b, &[Token::Bytes(b"")]); + let b = bytes::BytesMut::with_capacity(0); + assert_tokens(&b, &[Token::Bytes(b"")]); +} + +#[test] +fn test_ser_de() { + let b = bytes::Bytes::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); + let b = bytes::BytesMut::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); +}