From 78fab25c5cec133c254ec1997aa11597d59f0b09 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 2 Nov 2017 14:52:25 +0100 Subject: [PATCH 1/4] implement Serializer for Readable/Compact --- serde_test/src/configure.rs | 374 ++++++++++++++++++++++++++++++++++++ serde_test/src/lib.rs | 1 + 2 files changed, 375 insertions(+) create mode 100644 serde_test/src/configure.rs diff --git a/serde_test/src/configure.rs b/serde_test/src/configure.rs new file mode 100644 index 00000000..fa4233bb --- /dev/null +++ b/serde_test/src/configure.rs @@ -0,0 +1,374 @@ +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}; + +pub struct Readable(T); +pub struct Compact(T); + +pub trait Configure { + fn readable(&self) -> Readable<&Self> { + Readable(self) + } + fn compact(&self) -> Compact<&Self> { + Compact(self) + } +} + +impl Configure for T {} +pub trait Configuration { + fn is_human_readable(&self) -> bool { + true + } +} +impl Configuration for Readable {} + +fn assert(_: T) +where + T: Configure, +{ + +} + +impl Serialize for Readable +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(Readable(serializer)) + } +} +impl Serialize for Compact +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(Compact(serializer)) + } +} +impl<'de, T> Deserialize<'de> for Readable +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(Readable(deserializer)).map(Readable) + } +} +impl<'de, T> Deserialize<'de> for Compact +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(Compact(deserializer)).map(Compact) + } +} + + +macro_rules! forward_method { + ($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => { + fn $name (self $(, $arg : $arg_type)* ) -> $return_type { + (self.0).$name( $($arg),* ) + } + }; +} + +macro_rules! forward_serialize_methods { + ( $( $name: ident $arg_type: ty ),* ) => { + $( + forward_method!($name(self, v : $arg_type) -> Result); + )* + }; +} + +macro_rules! impl_serializer { + ($wrapper: ident, $is_human_readable : expr) => { + impl Serializer for $wrapper + where + S: Serializer, + { + type Ok = S::Ok; + type Error = S::Error; + + type SerializeSeq = $wrapper; + type SerializeTuple = $wrapper; + type SerializeTupleStruct = $wrapper; + type SerializeTupleVariant = $wrapper; + type SerializeMap = $wrapper; + type SerializeStruct = $wrapper; + type SerializeStructVariant = $wrapper; + + fn is_human_readable(&self) -> bool { + $is_human_readable + } + + + forward_serialize_methods!{ + serialize_bool bool, + serialize_i8 i8, + serialize_i16 i16, + serialize_i32 i32, + serialize_i64 i64, + serialize_u8 u8, + serialize_u16 u16, + serialize_u32 u32, + serialize_u64 u64, + serialize_f32 f32, + serialize_f64 f64, + serialize_char char, + serialize_str &str, + serialize_bytes &[u8], + serialize_unit_struct &'static str + + } + + fn serialize_unit(self) -> Result { + self.0.serialize_unit() + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + self.0.serialize_unit_variant(name, variant_index, variant) + } + + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: Serialize, + { + self.0.serialize_newtype_struct(name, &$wrapper(value)) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: Serialize, + { + self.0 + .serialize_newtype_variant(name, variant_index, variant, &$wrapper(value)) + } + + fn serialize_none(self) -> Result { + self.0.serialize_none() + } + + fn serialize_some(self, value: &T) -> Result + where + T: Serialize, + { + self.0.serialize_some(&$wrapper(value)) + } + + fn serialize_seq(self, len: Option) -> Result { + self.0.serialize_seq(len).map($wrapper) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.0.serialize_tuple(len).map($wrapper) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + self.0.serialize_tuple_struct(name, len).map($wrapper) + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + self.0 + .serialize_tuple_variant(name, variant_index, variant, len) + .map($wrapper) + } + + fn serialize_map(self, len: Option) -> Result { + self.0.serialize_map(len).map($wrapper) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + self.0.serialize_struct(name, len).map($wrapper) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + self.0 + .serialize_struct_variant(name, variant_index, variant, len) + .map($wrapper) + } + } + + impl SerializeSeq for $wrapper + where + S: SerializeSeq, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_element(&mut self, value: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_element(&$wrapper(value)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeTuple for $wrapper + where + S: SerializeTuple, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_element(&mut self, value: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_element(&$wrapper(value)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeTupleStruct for $wrapper + where + S: SerializeTupleStruct, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_field(&mut self, value: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_field(&$wrapper(value)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeTupleVariant for $wrapper + where + S: SerializeTupleVariant, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_field(&mut self, value: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_field(&$wrapper(value)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeMap for $wrapper + where + S: SerializeMap, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_key(&mut self, key: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_key(&$wrapper(key)) + } + fn serialize_value(&mut self, value: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_value(&$wrapper(value)) + } + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), S::Error> + where + K: Serialize, + V: Serialize, + { + self.0.serialize_entry(key, &$wrapper(value)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeStruct for $wrapper + where + S: SerializeStruct, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_field(&mut self, name: &'static str, field: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_field(name, &$wrapper(field)) + } + fn end(self) -> Result { + self.0.end() + } + } + + impl SerializeStructVariant for $wrapper + where + S: SerializeStructVariant, + { + type Ok = S::Ok; + type Error = S::Error; + fn serialize_field(&mut self, name: &'static str, field: &T) -> Result<(), S::Error> + where + T: Serialize, + { + self.0.serialize_field(name, &$wrapper(field)) + } + fn end(self) -> Result { + self.0.end() + } + } + } +} + +impl_serializer!(Readable, true); +impl_serializer!(Compact, false); diff --git a/serde_test/src/lib.rs b/serde_test/src/lib.rs index 4068e58b..79b1a96a 100644 --- a/serde_test/src/lib.rs +++ b/serde_test/src/lib.rs @@ -164,6 +164,7 @@ mod ser; mod de; mod error; +mod configure; mod token; mod assert; From 39e05ffad2384dba90b14c765bd201a7608dcd86 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 2 Nov 2017 15:38:39 +0100 Subject: [PATCH 2/4] Implement Deserializer for Readable/Compact --- serde_test/src/configure.rs | 247 ++++++++++++++++++++++++++++++++++-- 1 file changed, 234 insertions(+), 13 deletions(-) diff --git a/serde_test/src/configure.rs b/serde_test/src/configure.rs index fa4233bb..e92ccafc 100644 --- a/serde_test/src/configure.rs +++ b/serde_test/src/configure.rs @@ -1,3 +1,5 @@ +use std::fmt; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}; @@ -15,19 +17,6 @@ pub trait Configure { } impl Configure for T {} -pub trait Configuration { - fn is_human_readable(&self) -> bool { - true - } -} -impl Configuration for Readable {} - -fn assert(_: T) -where - T: Configure, -{ - -} impl Serialize for Readable where @@ -76,6 +65,33 @@ where } } +impl<'de, T> DeserializeSeed<'de> for Readable +where + T: DeserializeSeed<'de>, +{ + type Value = T::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.0.deserialize(Readable(deserializer)) + } +} +impl<'de, T> DeserializeSeed<'de> for Compact +where + T: DeserializeSeed<'de>, +{ + type Value = T::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.0.deserialize(Compact(deserializer)) + } +} + macro_rules! forward_method { ($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => { @@ -372,3 +388,208 @@ macro_rules! impl_serializer { impl_serializer!(Readable, true); impl_serializer!(Compact, false); + + +use serde::de::{Visitor, EnumAccess, VariantAccess, MapAccess, DeserializeSeed, SeqAccess, Error}; + +macro_rules! forward_deserialize_methods { + ( $wrapper : ident ( $( $name: ident ),* ) ) => { + $( + fn $name(self, visitor: V) -> Result where V: Visitor<'de> { + (self.0).$name($wrapper(visitor)) + } + )* + }; +} + + +macro_rules! impl_deserializer { + ($wrapper : ident, $is_human_readable : expr) => { + impl <'de, D> Deserializer<'de> for $wrapper where D: Deserializer<'de> { + type Error = D::Error; + + forward_deserialize_methods! { + $wrapper ( + deserialize_any, + deserialize_bool, + deserialize_u8, + deserialize_u16, + deserialize_u32, + deserialize_u64, + deserialize_i8, + deserialize_i16, + deserialize_i32, + deserialize_i64, + deserialize_f32, + deserialize_f64, + deserialize_char, + deserialize_str, + deserialize_string, + deserialize_bytes, + deserialize_byte_buf, + deserialize_option, + deserialize_unit, + deserialize_seq, + deserialize_map, + deserialize_identifier, + deserialize_ignored_any + ) + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_unit_struct(name, $wrapper(visitor)) + } + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_newtype_struct(name, $wrapper(visitor)) + } + fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_tuple(len, $wrapper(visitor)) + } + fn deserialize_tuple_struct(self, name: &'static str, len: usize, visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_tuple_struct(name, len, $wrapper(visitor)) + } + fn deserialize_struct(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_struct(name, fields, $wrapper(visitor)) + } + fn deserialize_enum(self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de> { + self.0.deserialize_enum(name, variants, $wrapper(visitor)) + } + + fn is_human_readable(&self) -> bool { + $is_human_readable + } + } + + impl<'de, D> Visitor<'de> for $wrapper where D: Visitor<'de> { + type Value = D::Value; + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.0.expecting(formatter) + } + fn visit_bool(self, v: bool) -> Result where E: Error { + self.0.visit_bool(v) + } + fn visit_i8(self, v: i8) -> Result where E: Error { + self.0.visit_i8(v) + } + fn visit_i16(self, v: i16) -> Result where E: Error { + self.0.visit_i16(v) + } + fn visit_i32(self, v: i32) -> Result where E: Error { + self.0.visit_i32(v) + } + fn visit_i64(self, v: i64) -> Result where E: Error { + self.0.visit_i64(v) + } + fn visit_u8(self, v: u8) -> Result where E: Error { + self.0.visit_u8(v) + } + fn visit_u16(self, v: u16) -> Result where E: Error { + self.0.visit_u16(v) + } + fn visit_u32(self, v: u32) -> Result where E: Error { + self.0.visit_u32(v) + } + fn visit_u64(self, v: u64) -> Result where E: Error { + self.0.visit_u64(v) + } + fn visit_f32(self, v: f32) -> Result where E: Error { + self.0.visit_f32(v) + } + fn visit_f64(self, v: f64) -> Result where E: Error { + self.0.visit_f64(v) + } + fn visit_char(self, v: char) -> Result where E: Error { + self.0.visit_char(v) + } + fn visit_str(self, v: &str) -> Result where E: Error { + self.0.visit_str(v) + } + fn visit_borrowed_str(self, v: &'de str) -> Result where E: Error { + self.0.visit_borrowed_str(v) + } + fn visit_string(self, v: String) -> Result where E: Error { + self.0.visit_string(v) + } + fn visit_bytes(self, v: &[u8]) -> Result where E: Error { + self.0.visit_bytes(v) + } + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result where E: Error { + self.0.visit_borrowed_bytes(v) + } + fn visit_byte_buf(self, v: Vec) -> Result where E: Error { + self.0.visit_byte_buf(v) + } + fn visit_none(self) -> Result where E: Error { + self.0.visit_none() + } + fn visit_some(self, deserializer: D2) -> Result where D2: Deserializer<'de> { + self.0.visit_some($wrapper(deserializer)) + } + fn visit_unit(self) -> Result where E: Error { + self.0.visit_unit() + } + fn visit_newtype_struct(self, deserializer: D2) -> Result where D2: Deserializer<'de> { + self.0.visit_newtype_struct($wrapper(deserializer)) + } + fn visit_seq(self, seq: V) -> Result where V: SeqAccess<'de> { + self.0.visit_seq($wrapper(seq)) + } + fn visit_map(self, map: V) -> Result where V: MapAccess<'de> { + self.0.visit_map($wrapper(map)) + } + fn visit_enum(self, data: V) -> Result where V: EnumAccess<'de> { + self.0.visit_enum($wrapper(data)) + } + } + + impl<'de, D> SeqAccess<'de> for $wrapper where D: SeqAccess<'de> { + type Error = D::Error; + fn next_element_seed(&mut self, seed: T) -> Result, D::Error> where T: DeserializeSeed<'de> { + self.0.next_element_seed($wrapper(seed)) + } + fn size_hint(&self) -> Option { + self.0.size_hint() + } + } + + impl<'de, D> MapAccess<'de> for $wrapper where D: MapAccess<'de> { + type Error = D::Error; + fn next_key_seed(&mut self, seed: K) -> Result, D::Error> where K: DeserializeSeed<'de> { + self.0.next_key_seed($wrapper(seed)) + } + fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de> { + self.0.next_value_seed($wrapper(seed)) + } + fn size_hint(&self) -> Option { + self.0.size_hint() + } + } + + impl<'de, D> EnumAccess<'de> for $wrapper where D: EnumAccess<'de> { + type Error = D::Error; + type Variant = $wrapper; + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de> { + self.0.variant_seed($wrapper(seed)).map(|(value, variant)| (value, $wrapper(variant))) + } + } + + impl<'de, D> VariantAccess<'de> for $wrapper where D: VariantAccess<'de> { + type Error = D::Error; + fn unit_variant(self) -> Result<(), D::Error> { + self.0.unit_variant() + } + fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de> { + self.0.newtype_variant_seed($wrapper(seed)) + } + fn tuple_variant(self, len: usize, visitor: V) -> Result where V: Visitor<'de> { + self.0.tuple_variant(len, $wrapper(visitor)) + } + fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de> { + self.0.struct_variant(fields, $wrapper(visitor)) + } + } + } +} + +impl_deserializer!(Readable, true); +impl_deserializer!(Compact, false); From 1b9a096fa7a97a183326a13d2729a0386374d99b Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 2 Nov 2017 16:03:50 +0100 Subject: [PATCH 3/4] Export configure api --- serde_test/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/serde_test/src/lib.rs b/serde_test/src/lib.rs index 79b1a96a..94fa5fd4 100644 --- a/serde_test/src/lib.rs +++ b/serde_test/src/lib.rs @@ -172,6 +172,8 @@ pub use token::Token; pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens, assert_de_tokens_error}; +pub use configure::{Configure, Compact, Readable}; + // Not public API. #[doc(hidden)] pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable}; From aad7a7987f423218b817488654a328c5800f777e Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Fri, 3 Nov 2017 16:12:43 +0100 Subject: [PATCH 4/4] Add an example to the Configure trait --- serde_test/src/assert.rs | 43 ++--------------- serde_test/src/configure.rs | 74 +++++++++++++++++++++++++++-- serde_test/src/de.rs | 22 ++------- serde_test/src/lib.rs | 10 ++-- serde_test/src/ser.rs | 42 ++++++++-------- test_suite/tests/test_de.rs | 34 ++++++------- test_suite/tests/test_identifier.rs | 7 +-- test_suite/tests/test_remote.rs | 64 ++++++++----------------- test_suite/tests/test_roundtrip.rs | 14 ++---- test_suite/tests/test_ser.rs | 33 +++++-------- 10 files changed, 157 insertions(+), 186 deletions(-) diff --git a/serde_test/src/assert.rs b/serde_test/src/assert.rs index 34eb6a75..95c7b923 100644 --- a/serde_test/src/assert.rs +++ b/serde_test/src/assert.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use de::Deserializer; use ser::Serializer; @@ -47,20 +47,8 @@ pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token]) where T: Serialize + Deserialize<'de> + PartialEq + Debug, { - assert_tokens_readable(value, tokens, None); -} - -// Not public API -#[doc(hidden)] -/// Runs both `assert_ser_tokens` and `assert_de_tokens`. -/// -/// See: `assert_tokens` -pub fn assert_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option) -where - T: Serialize + Deserialize<'de> + PartialEq + Debug, -{ - assert_ser_tokens_readable(value, tokens, human_readable); - assert_de_tokens_readable(value, tokens, human_readable); + assert_ser_tokens(value, tokens); + assert_de_tokens(value, tokens); } /// Asserts that `value` serializes to the given `tokens`. @@ -96,19 +84,7 @@ pub fn assert_ser_tokens(value: &T, tokens: &[Token]) where T: Serialize, { - assert_ser_tokens_readable(value, tokens, None) -} - -// Not public API -#[doc(hidden)] -/// Asserts that `value` serializes to the given `tokens`. -/// -/// See: `assert_ser_tokens` -pub fn assert_ser_tokens_readable(value: &T, tokens: &[Token], human_readable: Option) -where - T: Serialize, -{ - let mut ser = Serializer::readable(tokens, human_readable); + let mut ser = Serializer::new(tokens); match value.serialize(&mut ser) { Ok(_) => {} Err(err) => panic!("value failed to serialize: {}", err), @@ -207,16 +183,7 @@ pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token]) where T: Deserialize<'de> + PartialEq + Debug, { - assert_de_tokens_readable(value, tokens, None) -} - -// Not public API -#[doc(hidden)] -pub fn assert_de_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option) -where - T: Deserialize<'de> + PartialEq + Debug, -{ - let mut de = Deserializer::readable(tokens, human_readable); + let mut de = Deserializer::new(tokens); match T::deserialize(&mut de) { Ok(v) => assert_eq!(v, *value), Err(e) => panic!("tokens failed to deserialize: {}", e), diff --git a/serde_test/src/configure.rs b/serde_test/src/configure.rs index e92ccafc..57384745 100644 --- a/serde_test/src/configure.rs +++ b/serde_test/src/configure.rs @@ -4,19 +4,85 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant}; +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Readable(T); +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Compact(T); -pub trait Configure { - fn readable(&self) -> Readable<&Self> { +/// Trait which lets values mark wheter they should serialize or deserialize to or from their +/// human-readable or compact representation. +/// +/// ``` +/// extern crate serde; +/// extern crate serde_test; +/// +/// use serde::{Deserialize, Deserializer, Serialize, Serializer}; +/// use serde_test::{Configure, Token, assert_tokens}; +/// +/// #[derive(Debug, PartialEq)] +/// struct Example(u8, u8); +/// +/// impl Serialize for Example { +/// fn serialize(&self, serializer: S) -> Result +/// where S: Serializer, +/// { +/// if serializer.is_human_readable() { +/// format!("{}.{}", self.0, self.1).serialize(serializer) +/// } else { +/// (self.0, self.1).serialize(serializer) +/// } +/// } +/// } +/// +/// impl<'de> Deserialize<'de> for Example { +/// fn deserialize(deserializer: D) -> Result +/// where D: Deserializer<'de>, +/// { +/// use serde::de::Error; +/// if deserializer.is_human_readable() { +/// let s = String::deserialize(deserializer)?; +/// let parts: Vec<_> = s.split('.').collect(); +/// Ok(Example( +/// parts[0].parse().map_err(D::Error::custom)?, +/// parts[1].parse().map_err(D::Error::custom)?, +/// )) +/// } else { +/// let (x, y) = Deserialize::deserialize(deserializer)?; +/// Ok(Example(x, y)) +/// } +/// } +/// } +/// +/// fn main() { +/// assert_tokens( +/// &Example(1, 0).compact(), +/// &[ +/// Token::Tuple { len: 2 }, +/// Token::U8(1), +/// Token::U8(0), +/// Token::TupleEnd, +/// ], +/// ); +/// assert_tokens( +/// &Example(1, 0).readable(), +/// &[ +/// Token::Str("1.0"), +/// ], +/// ); +/// } +/// ``` +pub trait Configure : Sized { + /// Marks `self` as using `is_human_readable == true` + fn readable(self) -> Readable { Readable(self) } - fn compact(&self) -> Compact<&Self> { + /// Marks `self` as using `is_human_readable == false` + fn compact(self) -> Compact { Compact(self) } } -impl Configure for T {} +impl Configure for T {} impl Serialize for Readable where diff --git a/serde_test/src/de.rs b/serde_test/src/de.rs index 782e706b..623d11b8 100644 --- a/serde_test/src/de.rs +++ b/serde_test/src/de.rs @@ -16,7 +16,6 @@ use token::Token; #[derive(Debug)] pub struct Deserializer<'de> { tokens: &'de [Token], - is_human_readable: Option, } macro_rules! assert_next_token { @@ -49,13 +48,7 @@ macro_rules! end_of_tokens { impl<'de> Deserializer<'de> { pub fn new(tokens: &'de [Token]) -> Self { - Deserializer::readable(tokens, None) - } - - // Not public API - #[doc(hidden)] - pub fn readable(tokens: &'de [Token], is_human_readable: Option) -> Self { - Deserializer { tokens: tokens, is_human_readable: is_human_readable } + Deserializer { tokens: tokens } } fn peek_token_opt(&self) -> Option { @@ -373,15 +366,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } fn is_human_readable(&self) -> bool { - match self.is_human_readable { - Some(is) => is, - None => { - panic!("There is no serde_test API currently for testing types \ - that have different human-readable and compact \ - representation. See \ - https://github.com/serde-rs/serde/issues/1065."); - } - } + panic!( + "Types which have different human-readable and compact representations\ + must explicitly mark their test cases with `serde_test::Configure`" + ); } } diff --git a/serde_test/src/lib.rs b/serde_test/src/lib.rs index 94fa5fd4..7d5c65ac 100644 --- a/serde_test/src/lib.rs +++ b/serde_test/src/lib.rs @@ -169,14 +169,10 @@ mod token; mod assert; pub use token::Token; -pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, - assert_de_tokens, assert_de_tokens_error}; +pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, + assert_ser_tokens_error, assert_tokens}; -pub use configure::{Configure, Compact, Readable}; - -// Not public API. -#[doc(hidden)] -pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable}; +pub use configure::{Compact, Configure, Readable}; // Not public API. #[doc(hidden)] diff --git a/serde_test/src/ser.rs b/serde_test/src/ser.rs index 5fd5ecf5..d443c883 100644 --- a/serde_test/src/ser.rs +++ b/serde_test/src/ser.rs @@ -15,19 +15,12 @@ use token::Token; #[derive(Debug)] pub struct Serializer<'a> { tokens: &'a [Token], - is_human_readable: Option, } impl<'a> Serializer<'a> { /// Creates the serializer. pub fn new(tokens: &'a [Token]) -> Self { - Serializer::readable(tokens, None) - } - - // Not public API - #[doc(hidden)] - pub fn readable(tokens: &'a [Token], is_human_readable: Option) -> Self { - Serializer { tokens: tokens, is_human_readable: is_human_readable } + Serializer { tokens: tokens } } /// Pulls the next token off of the serializer, ignoring it. @@ -254,10 +247,16 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> { assert_next_token!(self, Str(variant)); let len = Some(len); assert_next_token!(self, Seq { len }); - Ok(Variant { ser: self, end: Token::SeqEnd }) + Ok(Variant { + ser: self, + end: Token::SeqEnd, + }) } else { assert_next_token!(self, TupleVariant { name, variant, len }); - Ok(Variant { ser: self, end: Token::TupleVariantEnd }) + Ok(Variant { + ser: self, + end: Token::TupleVariantEnd, + }) } } @@ -283,23 +282,24 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> { assert_next_token!(self, Str(variant)); let len = Some(len); assert_next_token!(self, Map { len }); - Ok(Variant { ser: self, end: Token::MapEnd }) + Ok(Variant { + ser: self, + end: Token::MapEnd, + }) } else { assert_next_token!(self, StructVariant { name, variant, len }); - Ok(Variant { ser: self, end: Token::StructVariantEnd }) + Ok(Variant { + ser: self, + end: Token::StructVariantEnd, + }) } } fn is_human_readable(&self) -> bool { - match self.is_human_readable { - Some(is) => is, - None => { - panic!("There is no serde_test API currently for testing types \ - that have different human-readable and compact \ - representation. See \ - https://github.com/serde-rs/serde/issues/1065."); - } - } + panic!( + "Types which have different human-readable and compact representations\ + must explicitly mark their test cases with `serde_test::Configure`" + ); } } diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index 5adae5ac..f5780936 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -29,7 +29,7 @@ extern crate fnv; use self::fnv::FnvHasher; extern crate serde_test; -use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error, assert_de_tokens_readable}; +use self::serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token}; #[macro_use] mod macros; @@ -49,16 +49,14 @@ struct TupleStruct(i32, i32, i32); struct Struct { a: i32, b: i32, - #[serde(skip_deserializing)] - c: i32, + #[serde(skip_deserializing)] c: i32, } #[derive(PartialEq, Debug, Deserialize)] #[serde(deny_unknown_fields)] struct StructDenyUnknown { a: i32, - #[serde(skip_deserializing)] - b: i32, + #[serde(skip_deserializing)] b: i32, } #[derive(PartialEq, Debug, Deserialize)] @@ -79,15 +77,13 @@ impl Default for StructDefault { #[derive(PartialEq, Debug, Deserialize)] struct StructSkipAll { - #[serde(skip_deserializing)] - a: i32, + #[serde(skip_deserializing)] a: i32, } #[derive(PartialEq, Debug, Deserialize)] #[serde(deny_unknown_fields)] struct StructSkipAllDenyUnknown { - #[serde(skip_deserializing)] - a: i32, + #[serde(skip_deserializing)] a: i32, } #[derive(PartialEq, Debug, Deserialize)] @@ -112,7 +108,7 @@ enum EnumSkipAll { macro_rules! declare_tests { ( - readable: $readable:tt + $readable:tt $($name:ident { $($value:expr => $tokens:expr,)+ })+ ) => { $( @@ -120,7 +116,7 @@ macro_rules! declare_tests { fn $name() { $( // Test ser/de roundtripping - assert_de_tokens_readable(&$value, $tokens, Some($readable)); + assert_de_tokens(&$value.$readable(), $tokens); // Test that the tokens are ignorable assert_de_tokens_ignore($tokens); @@ -168,13 +164,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { Token::Map { len: Some(2) }, Token::Str("a"), Token::I32(1), - Token::Str("ignored"), - ] - .into_iter() - .chain(ignorable_tokens.to_vec().into_iter()) - .chain(vec![Token::MapEnd].into_iter()) - .collect(); + ].into_iter() + .chain(ignorable_tokens.to_vec().into_iter()) + .chain(vec![Token::MapEnd].into_iter()) + .collect(); let mut de = serde_test::Deserializer::new(&concated_tokens); let base = IgnoreBase::deserialize(&mut de).unwrap(); @@ -774,7 +768,8 @@ declare_tests! { } declare_tests! { - readable: true + readable + test_net_ipv4addr_readable { "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], } @@ -792,7 +787,8 @@ declare_tests! { } declare_tests! { - readable: false + compact + test_net_ipv4addr_compact { net::Ipv4Addr::from(*b"1234") => &seq![ Token::Tuple { len: 4 }, diff --git a/test_suite/tests/test_identifier.rs b/test_suite/tests/test_identifier.rs index 83a0d3b1..b13b6695 100644 --- a/test_suite/tests/test_identifier.rs +++ b/test_suite/tests/test_identifier.rs @@ -9,10 +9,8 @@ #[macro_use] extern crate serde_derive; -extern crate serde; - extern crate serde_test; -use serde_test::{Token, assert_de_tokens}; +use serde_test::{assert_de_tokens, Token}; #[test] fn test_variant_identifier() { @@ -51,8 +49,7 @@ fn test_unit_fallthrough() { enum F { Aaa, Bbb, - #[serde(other)] - Other, + #[serde(other)] Other, } assert_de_tokens(&F::Other, &[Token::Str("x")]); diff --git a/test_suite/tests/test_remote.rs b/test_suite/tests/test_remote.rs index 30ccbb27..c0b2700e 100644 --- a/test_suite/tests/test_remote.rs +++ b/test_suite/tests/test_remote.rs @@ -9,8 +9,6 @@ #[macro_use] extern crate serde_derive; -extern crate serde; - mod remote { pub struct Unit; @@ -87,32 +85,23 @@ mod remote { #[derive(Serialize, Deserialize)] struct Test { - #[serde(with = "UnitDef")] - unit: remote::Unit, + #[serde(with = "UnitDef")] unit: remote::Unit, - #[serde(with = "PrimitivePrivDef")] - primitive_priv: remote::PrimitivePriv, + #[serde(with = "PrimitivePrivDef")] primitive_priv: remote::PrimitivePriv, - #[serde(with = "PrimitivePubDef")] - primitive_pub: remote::PrimitivePub, + #[serde(with = "PrimitivePubDef")] primitive_pub: remote::PrimitivePub, - #[serde(with = "NewtypePrivDef")] - newtype_priv: remote::NewtypePriv, + #[serde(with = "NewtypePrivDef")] newtype_priv: remote::NewtypePriv, - #[serde(with = "NewtypePubDef")] - newtype_pub: remote::NewtypePub, + #[serde(with = "NewtypePubDef")] newtype_pub: remote::NewtypePub, - #[serde(with = "TuplePrivDef")] - tuple_priv: remote::TuplePriv, + #[serde(with = "TuplePrivDef")] tuple_priv: remote::TuplePriv, - #[serde(with = "TuplePubDef")] - tuple_pub: remote::TuplePub, + #[serde(with = "TuplePubDef")] tuple_pub: remote::TuplePub, - #[serde(with = "StructPrivDef")] - struct_priv: remote::StructPriv, + #[serde(with = "StructPrivDef")] struct_priv: remote::StructPriv, - #[serde(with = "StructPubDef")] - struct_pub: remote::StructPub, + #[serde(with = "StructPubDef")] struct_pub: remote::StructPub, } #[derive(Serialize, Deserialize)] @@ -121,10 +110,7 @@ struct UnitDef; #[derive(Serialize, Deserialize)] #[serde(remote = "remote::PrimitivePriv")] -struct PrimitivePrivDef( - #[serde(getter = "remote::PrimitivePriv::get")] - u8 -); +struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::PrimitivePub")] @@ -133,53 +119,41 @@ struct PrimitivePubDef(u8); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::NewtypePriv")] struct NewtypePrivDef( - #[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] - remote::Unit + #[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit, ); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::NewtypePub")] -struct NewtypePubDef( - #[serde(with = "UnitDef")] - remote::Unit -); +struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::TuplePriv")] struct TuplePrivDef( - #[serde(getter = "remote::TuplePriv::first")] - u8, - #[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] - remote::Unit + #[serde(getter = "remote::TuplePriv::first")] u8, + #[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit, ); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::TuplePub")] -struct TuplePubDef( - u8, - #[serde(with = "UnitDef")] - remote::Unit -); +struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit); #[derive(Serialize, Deserialize)] #[serde(remote = "remote::StructPriv")] struct StructPrivDef { - #[serde(getter = "remote::StructPriv::a")] - a: u8, + #[serde(getter = "remote::StructPriv::a")] a: u8, #[serde(getter = "remote::StructPriv::b")] - #[serde(with= "UnitDef")] + #[serde(with = "UnitDef")] b: remote::Unit, } #[derive(Serialize, Deserialize)] #[serde(remote = "remote::StructPub")] struct StructPubDef { - #[allow(dead_code)] - a: u8, + #[allow(dead_code)] a: u8, #[allow(dead_code)] - #[serde(with= "UnitDef")] + #[serde(with = "UnitDef")] b: remote::Unit, } diff --git a/test_suite/tests/test_roundtrip.rs b/test_suite/tests/test_roundtrip.rs index 0e417341..300fe8d3 100644 --- a/test_suite/tests/test_roundtrip.rs +++ b/test_suite/tests/test_roundtrip.rs @@ -7,7 +7,7 @@ // except according to those terms. extern crate serde_test; -use self::serde_test::{Token, assert_tokens_readable}; +use self::serde_test::{assert_tokens, Configure, Token}; use std::net; @@ -17,9 +17,8 @@ mod macros; #[test] fn ip_addr_roundtrip() { - - assert_tokens_readable( - &net::IpAddr::from(*b"1234"), + assert_tokens( + &net::IpAddr::from(*b"1234").compact(), &seq![ Token::NewtypeVariant { name: "IpAddr", variant: "V4" }, @@ -27,15 +26,13 @@ fn ip_addr_roundtrip() { seq b"1234".iter().map(|&b| Token::U8(b)), Token::TupleEnd, ], - Some(false), ); } #[test] fn socked_addr_roundtrip() { - - assert_tokens_readable( - &net::SocketAddr::from((*b"1234567890123456", 1234)), + assert_tokens( + &net::SocketAddr::from((*b"1234567890123456", 1234)).compact(), &seq![ Token::NewtypeVariant { name: "SocketAddr", variant: "V6" }, @@ -48,6 +45,5 @@ fn socked_addr_roundtrip() { Token::U16(1234), Token::TupleEnd, ], - Some(false), ); } diff --git a/test_suite/tests/test_ser.rs b/test_suite/tests/test_ser.rs index 4198d566..7b1af691 100644 --- a/test_suite/tests/test_ser.rs +++ b/test_suite/tests/test_ser.rs @@ -21,11 +21,8 @@ use std::num::Wrapping; #[cfg(unix)] use std::str; -extern crate serde; - extern crate serde_test; -use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error, - assert_ser_tokens_readable}; +use self::serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token}; extern crate fnv; use self::fnv::FnvHasher; @@ -54,28 +51,24 @@ enum Enum { One(i32), Seq(i32, i32), Map { a: i32, b: i32 }, - #[serde(skip_serializing)] - SkippedUnit, - #[serde(skip_serializing)] - SkippedOne(i32), - #[serde(skip_serializing)] - SkippedSeq(i32, i32), - #[serde(skip_serializing)] - SkippedMap { _a: i32, _b: i32 }, + #[serde(skip_serializing)] SkippedUnit, + #[serde(skip_serializing)] SkippedOne(i32), + #[serde(skip_serializing)] SkippedSeq(i32, i32), + #[serde(skip_serializing)] SkippedMap { _a: i32, _b: i32 }, } ////////////////////////////////////////////////////////////////////////// macro_rules! declare_tests { ( - readable: $readable:tt + $readable:tt $($name:ident { $($value:expr => $tokens:expr,)+ })+ ) => { $( #[test] fn $name() { $( - assert_ser_tokens_readable(&$value, $tokens, Some($readable)); + assert_ser_tokens(&$value.$readable(), $tokens); )+ } )+ @@ -408,7 +401,8 @@ declare_tests! { } declare_tests! { - readable: true + readable + test_net_ipv4addr_readable { "1.2.3.4".parse::().unwrap() => &[Token::Str("1.2.3.4")], } @@ -426,7 +420,8 @@ declare_tests! { } declare_tests! { - readable: false + compact + test_net_ipv4addr_compact { net::Ipv4Addr::from(*b"1234") => &seq![ Token::Tuple { len: 4 }, @@ -524,11 +519,7 @@ fn test_cannot_serialize_paths() { let mut path_buf = PathBuf::new(); path_buf.push(path); - assert_ser_tokens_error( - &path_buf, - &[], - "path contains invalid UTF-8 characters", - ); + assert_ser_tokens_error(&path_buf, &[], "path contains invalid UTF-8 characters"); } #[test]