diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 41460c85..026f0cdf 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -1245,6 +1245,8 @@ mod content { match self.content { Content::String(v) => visitor.visit_string(v), Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), _ => Err(self.invalid_type(&visitor)), } } @@ -1261,8 +1263,11 @@ mod content { V: Visitor<'de>, { match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), Content::ByteBuf(v) => visitor.visit_byte_buf(v), Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(v) => visit_content_seq(v, visitor), _ => Err(self.invalid_type(&visitor)), } } @@ -1966,6 +1971,8 @@ mod content { match *self.content { Content::String(ref v) => visitor.visit_str(v), Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), _ => Err(self.invalid_type(&visitor)), } } @@ -1982,8 +1989,11 @@ mod content { V: Visitor<'de>, { match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), Content::ByteBuf(ref v) => visitor.visit_bytes(v), Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), _ => Err(self.invalid_type(&visitor)), } } diff --git a/test_suite/tests/bytes/mod.rs b/test_suite/tests/bytes/mod.rs new file mode 100644 index 00000000..d21d9830 --- /dev/null +++ b/test_suite/tests/bytes/mod.rs @@ -0,0 +1,52 @@ +use serde::de::{Deserializer, Visitor, SeqAccess, Error}; +use std::fmt; + +pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where D: Deserializer<'de> +{ + deserializer.deserialize_byte_buf(ByteBufVisitor) +} + +struct ByteBufVisitor; + +impl<'de> Visitor<'de> for ByteBufVisitor { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + fn visit_seq(self, mut visitor: V) -> Result + where V: SeqAccess<'de> + { + let mut values = Vec::new(); + while let Some(value) = try!(visitor.next_element()) { + values.push(value); + } + Ok(values) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where E: Error + { + Ok(v.to_vec()) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where E: Error + { + Ok(v) + } + + fn visit_str(self, v: &str) -> Result + where E: Error + { + Ok(v.as_bytes().to_vec()) + } + + fn visit_string(self, v: String) -> Result + where E: Error + { + Ok(v.into_bytes()) + } +} diff --git a/test_suite/tests/test_macros.rs b/test_suite/tests/test_macros.rs index ca38cbd7..dc17c525 100644 --- a/test_suite/tests/test_macros.rs +++ b/test_suite/tests/test_macros.rs @@ -13,7 +13,11 @@ #[macro_use] extern crate serde_derive; +extern crate serde; extern crate serde_test; + +mod bytes; + use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token}; @@ -779,6 +783,158 @@ fn test_internally_tagged_enum() { ); } +#[test] +fn test_internally_tagged_bytes() { + #[derive(Debug, PartialEq, Deserialize)] + #[serde(tag = "type")] + enum InternallyTagged { + String { + string: String, + }, + Bytes { + #[serde(with = "bytes")] + bytes: Vec, + }, + } + + assert_de_tokens( + &InternallyTagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("type"), + Token::Str("String"), + Token::Str("string"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("type"), + Token::Str("String"), + Token::Str("string"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("type"), + Token::Str("String"), + Token::Str("string"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "String", + len: 2, + }, + Token::Str("type"), + Token::Str("String"), + Token::Str("string"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("type"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("type"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("type"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("type"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &InternallyTagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Bytes", + len: 2, + }, + Token::Str("type"), + Token::Str("Bytes"), + Token::Str("bytes"), + Token::Seq { len: Some(1) }, + Token::U8(0), + Token::SeqEnd, + Token::StructEnd, + ], + ); +} + #[test] fn test_internally_tagged_struct_variant_containing_unit_variant() { #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -1246,6 +1402,140 @@ fn test_enum_in_untagged_enum() { ); } +#[test] +fn test_untagged_bytes() { + #[derive(Debug, PartialEq, Deserialize)] + #[serde(untagged)] + enum Untagged { + String { + string: String, + }, + Bytes { + #[serde(with = "bytes")] + bytes: Vec, + }, + } + + assert_de_tokens( + &Untagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::String { string: "\0".to_owned() }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("string"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Str("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::String("\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Bytes(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::ByteBuf(b"\0"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &Untagged::Bytes { bytes: vec![0] }, + &[ + Token::Struct { + name: "Untagged", + len: 1, + }, + Token::Str("bytes"), + Token::Seq { len: Some(1) }, + Token::U8(0), + Token::SeqEnd, + Token::StructEnd, + ], + ); +} + #[test] fn test_rename_all() { #[derive(Serialize, Deserialize, Debug, PartialEq)]