diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index be4a6301..b20d9ac7 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -868,71 +868,19 @@ map_impl!( //////////////////////////////////////////////////////////////////////////////// -macro_rules! count { - () => { - 0 - }; - ($first: expr $(,$rest: expr)*) => { - 1 + count!($($rest),*) - } -} - #[cfg(feature = "std")] macro_rules! parse_ip_impl { - ($ty:ty; $($size: expr),*) => { + ($ty:ty; $size: expr) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - struct ParseVisitor; - impl<'de> Visitor<'de> for ParseVisitor { - type Value = $ty; - - #[allow(unused_assignments)] - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "Expected bytes of length ")?; - let mut i = 0; - $( - let sep = match i { - 0 => "", - _ if i + 1 == count!($size) => " or ", - _ => ", ", - }; - write!(formatter, "{}{}", sep, $size)?; - i += 1; - )* - Ok(()) - } - - fn visit_str(self, value: &str) -> Result<$ty, E> - where - E: Error, - { - value.parse().map_err(Error::custom) - } - - fn visit_bytes(self, value: &[u8]) -> Result<$ty, E> - where - E: Error, - { - match value.len() { - $( - $size => { - let mut buffer = [0; $size]; - buffer.copy_from_slice(value); - Ok(<$ty>::from(buffer)) - } - )* - _ => Err(Error::invalid_length(value.len(), &self)), - } - } - } if deserializer.is_human_readable() { let s = try!(String::deserialize(deserializer)); s.parse().map_err(Error::custom) } else { - deserializer.deserialize_bytes(ParseVisitor) + <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) } } } @@ -940,7 +888,40 @@ macro_rules! parse_ip_impl { } #[cfg(feature = "std")] -parse_ip_impl!(net::IpAddr; 16, 4); +impl<'de> Deserialize<'de> for net::IpAddr { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + let s = try!(String::deserialize(deserializer)); + s.parse().map_err(Error::custom) + } else { + struct EnumVisitor; + impl<'de> Visitor<'de> for EnumVisitor { + type Value = net::IpAddr; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a IpAddr") + } + + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + match try!(data.variant()) { + (0u32, v) => v.newtype_variant().map(net::IpAddr::V4), + (1u32, v) => v.newtype_variant().map(net::IpAddr::V6), + (_, _) => Err(Error::custom("Invalid IpAddr variant")), + } + } + } + const VARIANTS: &[&str] = &["V4", "V6"]; + deserializer.deserialize_enum("IpAddr", VARIANTS, EnumVisitor) + } + } +} #[cfg(feature = "std")] parse_ip_impl!(net::Ipv4Addr; 4); diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 7fecd69f..014a6c52 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -569,7 +569,7 @@ impl Serialize for net::SocketAddrV4 { const MAX_LEN: usize = 21; serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { - (self.ip().octets(), self.port()).serialize(serializer) + (self.ip(), self.port()).serialize(serializer) } } } @@ -585,7 +585,7 @@ impl Serialize for net::SocketAddrV6 { const MAX_LEN: usize = 47; serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { - (self.ip().octets(), self.port()).serialize(serializer) + (self.ip(), self.port()).serialize(serializer) } } } diff --git a/test_suite/tests/macros/mod.rs b/test_suite/tests/macros/mod.rs index 4f6ea66e..9a917bcf 100644 --- a/test_suite/tests/macros/mod.rs +++ b/test_suite/tests/macros/mod.rs @@ -73,3 +73,29 @@ macro_rules! hashmap { } } } + +macro_rules! seq_impl { + (seq $first:expr,) => { + seq_impl!(seq $first) + }; + ($first:expr,) => { + seq_impl!($first) + }; + (seq $first:expr) => { + $first.into_iter() + }; + ($first:expr) => { + Some($first).into_iter() + }; + (seq $first:expr , $( $elem: tt)*) => { + $first.into_iter().chain(seq!( $($elem)* )) + }; + ($first:expr , $($elem: tt)*) => { + Some($first).into_iter().chain(seq!( $($elem)* )) + } +} +macro_rules! seq { + ($($tt: tt)*) => { + seq_impl!($($tt)*).collect::>() + }; +} diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index e1a015e2..ec0100bd 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -110,15 +110,15 @@ enum EnumSkipAll { ////////////////////////////////////////////////////////////////////////// macro_rules! declare_test { - ($name:ident { $($value:expr => $tokens:expr,)+ }) => { + ($name:ident $readable: ident { $($value:expr => $tokens:expr,)+ }) => { #[test] fn $name() { $( // Test ser/de roundtripping - assert_de_tokens(&$value, $tokens); + assert_de_tokens_readable(&$value, $tokens, $readable); // Test that the tokens are ignorable - assert_de_tokens_ignore($tokens); + assert_de_tokens_ignore($tokens, true); )+ } } @@ -127,7 +127,7 @@ macro_rules! declare_test { macro_rules! declare_tests { ($($name:ident { $($value:expr => $tokens:expr,)+ })+) => { $( - declare_test!($name { $($value => $tokens,)+ }); + declare_test!($name true { $($value => $tokens,)+ }); )+ } } @@ -143,7 +143,16 @@ macro_rules! declare_error_tests { } } -fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { +macro_rules! declare_non_human_readable_tests { + ($($name:ident { $($value:expr => $tokens:expr,)+ })+) => { + $( + declare_test!($name false { $($value => $tokens,)+ }); + )+ + } +} + + +fn assert_de_tokens_ignore(ignorable_tokens: &[Token], readable: bool) { #[derive(PartialEq, Debug, Deserialize)] struct IgnoreBase { a: i32, @@ -163,7 +172,7 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) { .chain(vec![Token::MapEnd].into_iter()) .collect(); - let mut de = serde_test::Deserializer::new(&concated_tokens); + let mut de = serde_test::Deserializer::readable(&concated_tokens, readable); let base = IgnoreBase::deserialize(&mut de).unwrap(); assert_eq!(base, IgnoreBase { a: 1 }); } @@ -754,6 +763,70 @@ declare_tests! { } } +declare_non_human_readable_tests!{ + test_non_human_readable_net_ipv4addr { + net::Ipv4Addr::from(*b"1234") => &seq![ + Token::Tuple { len: 4 }, + seq b"1234".iter().map(|&b| Token::U8(b)), + Token::TupleEnd + ], + } + test_non_human_readable_net_ipv6addr { + net::Ipv6Addr::from(*b"1234567890123456") => &seq![ + Token::Tuple { len: 4 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd + ], + + } + test_non_human_readable_net_socketaddr { + net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![ + Token::Tuple { len: 2 }, + Token::Enum { name: "IpAddr" }, + Token::U32(1), + + Token::Tuple { len: 16 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd + ], + net::SocketAddr::from((*b"1234", 1234)) => &seq![ + Token::Tuple { len: 2 }, + Token::Enum { name: "IpAddr" }, + Token::U32(0), + + Token::Tuple { len: 4 }, + seq b"1234".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd + ], + net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![ + Token::Tuple { len: 2 }, + + Token::Tuple { len: 4 }, + seq b"1234".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd + ], + net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![ + Token::Tuple { len: 2 }, + + Token::Tuple { len: 16 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd + ], + } +} + #[cfg(feature = "unstable")] declare_tests! { test_rc_dst { @@ -795,7 +868,7 @@ fn test_osstring() { ]; assert_de_tokens(&value, &tokens); - assert_de_tokens_ignore(&tokens); + assert_de_tokens_ignore(&tokens, true); } #[cfg(windows)] @@ -815,7 +888,7 @@ fn test_osstring() { ]; assert_de_tokens(&value, &tokens); - assert_de_tokens_ignore(&tokens); + assert_de_tokens_ignore(&tokens, true); } #[cfg(feature = "unstable")] diff --git a/test_suite/tests/test_ser.rs b/test_suite/tests/test_ser.rs index a623e5d6..ce1ae654 100644 --- a/test_suite/tests/test_ser.rs +++ b/test_suite/tests/test_ser.rs @@ -78,6 +78,19 @@ macro_rules! declare_tests { } } +macro_rules! declare_non_human_readable_tests { + ($($name:ident { $($value:expr => $tokens:expr,)+ })+) => { + $( + #[test] + fn $name() { + $( + assert_ser_tokens_readable(&$value, $tokens, false); + )+ + } + )+ + } +} + declare_tests! { test_unit { () => &[Token::Unit], @@ -398,6 +411,55 @@ declare_tests! { } } +declare_non_human_readable_tests!{ + test_non_human_readable_net_ipv4addr { + net::Ipv4Addr::from(*b"1234") => &seq![ + Token::Tuple { len: 4 }, + seq b"1234".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + ], + } + test_non_human_readable_net_ipv6addr { + net::Ipv6Addr::from(*b"1234567890123456") => &seq![ + Token::Tuple { len: 16 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + ], + } + test_non_human_readable_net_socketaddr { + net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![ + Token::Tuple { len: 2 }, + + Token::Tuple { len: 16 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd, + ], + net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![ + Token::Tuple { len: 2 }, + + Token::Tuple { len: 4 }, + seq b"1234".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd, + ], + net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![ + Token::Tuple { len: 2 }, + + Token::Tuple { len: 16 }, + seq b"1234567890123456".iter().map(|&b| Token::U8(b)), + Token::TupleEnd, + + Token::U16(1234), + Token::TupleEnd, + ], + } +} + // Serde's implementation is not unstable, but the constructors are. #[cfg(feature = "unstable")] declare_tests! {