Serialize non-human-readble ip addresses as tuples
Since we know exactly how many bytes we should serialize as we can hint to the serializer that it is not required which further reduces the serialized size when compared to just serializing as bytes.
This commit is contained in:
parent
40c670e625
commit
ad3335e5d6
@ -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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<E>(self, value: &str) -> Result<$ty, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
value.parse().map_err(Error::custom)
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
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);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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::<Vec<_>>()
|
||||
};
|
||||
}
|
||||
|
@ -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")]
|
||||
|
@ -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! {
|
||||
|
Loading…
Reference in New Issue
Block a user