mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-17 06:51:04 +00:00
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:
+36
-55
@@ -868,71 +868,19 @@ map_impl!(
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! count {
|
|
||||||
() => {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
($first: expr $(,$rest: expr)*) => {
|
|
||||||
1 + count!($($rest),*)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
macro_rules! parse_ip_impl {
|
macro_rules! parse_ip_impl {
|
||||||
($ty:ty; $($size: expr),*) => {
|
($ty:ty; $size: expr) => {
|
||||||
impl<'de> Deserialize<'de> for $ty {
|
impl<'de> Deserialize<'de> for $ty {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
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() {
|
if deserializer.is_human_readable() {
|
||||||
let s = try!(String::deserialize(deserializer));
|
let s = try!(String::deserialize(deserializer));
|
||||||
s.parse().map_err(Error::custom)
|
s.parse().map_err(Error::custom)
|
||||||
} else {
|
} else {
|
||||||
deserializer.deserialize_bytes(ParseVisitor)
|
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -940,7 +888,40 @@ macro_rules! parse_ip_impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[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")]
|
#[cfg(feature = "std")]
|
||||||
parse_ip_impl!(net::Ipv4Addr; 4);
|
parse_ip_impl!(net::Ipv4Addr; 4);
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ impl Serialize for net::SocketAddrV4 {
|
|||||||
const MAX_LEN: usize = 21;
|
const MAX_LEN: usize = 21;
|
||||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||||
} else {
|
} 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;
|
const MAX_LEN: usize = 47;
|
||||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||||
} else {
|
} 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 {
|
macro_rules! declare_test {
|
||||||
($name:ident { $($value:expr => $tokens:expr,)+ }) => {
|
($name:ident $readable: ident { $($value:expr => $tokens:expr,)+ }) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
$(
|
$(
|
||||||
// Test ser/de roundtripping
|
// Test ser/de roundtripping
|
||||||
assert_de_tokens(&$value, $tokens);
|
assert_de_tokens_readable(&$value, $tokens, $readable);
|
||||||
|
|
||||||
// Test that the tokens are ignorable
|
// 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 {
|
macro_rules! declare_tests {
|
||||||
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
|
($($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)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
struct IgnoreBase {
|
struct IgnoreBase {
|
||||||
a: i32,
|
a: i32,
|
||||||
@@ -163,7 +172,7 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
|
|||||||
.chain(vec![Token::MapEnd].into_iter())
|
.chain(vec![Token::MapEnd].into_iter())
|
||||||
.collect();
|
.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();
|
let base = IgnoreBase::deserialize(&mut de).unwrap();
|
||||||
assert_eq!(base, IgnoreBase { a: 1 });
|
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")]
|
#[cfg(feature = "unstable")]
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
test_rc_dst {
|
test_rc_dst {
|
||||||
@@ -795,7 +868,7 @@ fn test_osstring() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
assert_de_tokens(&value, &tokens);
|
assert_de_tokens(&value, &tokens);
|
||||||
assert_de_tokens_ignore(&tokens);
|
assert_de_tokens_ignore(&tokens, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -815,7 +888,7 @@ fn test_osstring() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
assert_de_tokens(&value, &tokens);
|
assert_de_tokens(&value, &tokens);
|
||||||
assert_de_tokens_ignore(&tokens);
|
assert_de_tokens_ignore(&tokens, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[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! {
|
declare_tests! {
|
||||||
test_unit {
|
test_unit {
|
||||||
() => &[Token::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.
|
// Serde's implementation is not unstable, but the constructors are.
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
|
|||||||
Reference in New Issue
Block a user