diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index ef3e20e6..be4a6301 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -868,38 +868,113 @@ map_impl!( //////////////////////////////////////////////////////////////////////////////// +macro_rules! count { + () => { + 0 + }; + ($first: expr $(,$rest: expr)*) => { + 1 + count!($($rest),*) + } +} + #[cfg(feature = "std")] -macro_rules! parse_impl { - ($ty:ty) => { +macro_rules! parse_ip_impl { + ($ty:ty; $($size: expr),*) => { impl<'de> Deserialize<'de> for $ty { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - let s = try!(String::deserialize(deserializer)); - s.parse().map_err(Error::custom) + 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) + } } } } } #[cfg(feature = "std")] -parse_impl!(net::IpAddr); +parse_ip_impl!(net::IpAddr; 16, 4); #[cfg(feature = "std")] -parse_impl!(net::Ipv4Addr); +parse_ip_impl!(net::Ipv4Addr; 4); #[cfg(feature = "std")] -parse_impl!(net::Ipv6Addr); +parse_ip_impl!(net::Ipv6Addr; 16); #[cfg(feature = "std")] -parse_impl!(net::SocketAddr); +macro_rules! parse_socket_impl { + ($ty:ty, $new: expr) => { + impl<'de> Deserialize<'de> for $ty { + 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 { + <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port)) + } + } + } + } +} #[cfg(feature = "std")] -parse_impl!(net::SocketAddrV4); +parse_socket_impl!(net::SocketAddr, net::SocketAddr::new); #[cfg(feature = "std")] -parse_impl!(net::SocketAddrV6); +parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new); + +#[cfg(feature = "std")] +parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0)); //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index ea59b78d..7fecd69f 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -519,9 +519,13 @@ impl Serialize for net::Ipv4Addr { where S: Serializer, { - /// "101.102.103.104".len() - const MAX_LEN: usize = 15; - serialize_display_bounded_length!(self, MAX_LEN, serializer) + if serializer.is_human_readable() { + /// "101.102.103.104".len() + const MAX_LEN: usize = 15; + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } } } @@ -531,9 +535,13 @@ impl Serialize for net::Ipv6Addr { where S: Serializer, { - /// "1000:1002:1003:1004:1005:1006:1007:1008".len() - const MAX_LEN: usize = 39; - serialize_display_bounded_length!(self, MAX_LEN, serializer) + if serializer.is_human_readable() { + /// "1000:1002:1003:1004:1005:1006:1007:1008".len() + const MAX_LEN: usize = 39; + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } } } @@ -556,9 +564,13 @@ impl Serialize for net::SocketAddrV4 { where S: Serializer, { - /// "101.102.103.104:65000".len() - const MAX_LEN: usize = 21; - serialize_display_bounded_length!(self, MAX_LEN, serializer) + if serializer.is_human_readable() { + /// "101.102.103.104:65000".len() + const MAX_LEN: usize = 21; + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip().octets(), self.port()).serialize(serializer) + } } } @@ -568,9 +580,13 @@ impl Serialize for net::SocketAddrV6 { where S: Serializer, { - /// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len() - const MAX_LEN: usize = 47; - serialize_display_bounded_length!(self, MAX_LEN, serializer) + if serializer.is_human_readable() { + /// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len() + const MAX_LEN: usize = 47; + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip().octets(), self.port()).serialize(serializer) + } } }