Merge pull request #1044 from Marwes/human_readable

Serialize to binary if the serde format is not human readable
This commit is contained in:
David Tolnay
2017-10-15 16:39:58 -07:00
committed by GitHub
12 changed files with 605 additions and 110 deletions
+181 -74
View File
@@ -869,37 +869,204 @@ map_impl!(
////////////////////////////////////////////////////////////////////////////////
#[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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
if deserializer.is_human_readable() {
let s = try!(String::deserialize(deserializer));
s.parse().map_err(Error::custom)
} else {
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
}
}
}
}
}
macro_rules! variant_identifier {
(
$name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
$expecting_message: expr,
$variants_name: ident
) => {
enum $name_kind {
$( $variant ),*
}
static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*];
impl<'de> Deserialize<'de> for $name_kind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct KindVisitor;
impl<'de> Visitor<'de> for KindVisitor {
type Value = $name_kind;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str($expecting_message)
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
$index => Ok($name_kind :: $variant),
)*
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
stringify!($variant) => Ok($name_kind :: $variant),
)*
_ => Err(Error::unknown_variant(value, $variants_name)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
$(
$bytes => Ok($name_kind :: $variant),
)*
_ => {
match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, $variants_name)),
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
}
}
}
}
}
deserializer.deserialize_identifier(KindVisitor)
}
}
}
}
macro_rules! deserialize_enum {
(
$name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
$expecting_message: expr,
$deserializer: expr
) => {
variant_identifier!{
$name_kind ( $($variant; $bytes; $index),* )
$expecting_message,
VARIANTS
}
struct EnumVisitor;
impl<'de> Visitor<'de> for EnumVisitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a ", stringify!($name)))
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
match try!(data.variant()) {
$(
($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant),
)*
}
}
}
$deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor)
}
}
#[cfg(feature = "std")]
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 {
use lib::net::IpAddr;
deserialize_enum!{
IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::IpAddr);
parse_ip_impl!(net::Ipv4Addr; 4);
#[cfg(feature = "std")]
parse_impl!(net::Ipv4Addr);
parse_ip_impl!(net::Ipv6Addr; 16);
#[cfg(feature = "std")]
parse_impl!(net::Ipv6Addr);
macro_rules! parse_socket_impl {
($ty:ty, $new: expr) => {
impl<'de> Deserialize<'de> for $ty {
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 {
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
}
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::SocketAddr);
impl<'de> Deserialize<'de> for net::SocketAddr {
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 {
use lib::net::SocketAddr;
deserialize_enum!{
SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
}
}
}
}
#[cfg(feature = "std")]
parse_impl!(net::SocketAddrV4);
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
#[cfg(feature = "std")]
parse_impl!(net::SocketAddrV6);
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0));
////////////////////////////////////////////////////////////////////////////////
@@ -984,70 +1151,10 @@ impl<'de> Deserialize<'de> for PathBuf {
// #[derive(Deserialize)]
// #[serde(variant_identifier)]
#[cfg(all(feature = "std", any(unix, windows)))]
enum OsStringKind {
Unix,
Windows,
}
#[cfg(all(feature = "std", any(unix, windows)))]
static OSSTR_VARIANTS: &'static [&'static str] = &["Unix", "Windows"];
#[cfg(all(feature = "std", any(unix, windows)))]
impl<'de> Deserialize<'de> for OsStringKind {
fn deserialize<D>(deserializer: D) -> Result<OsStringKind, D::Error>
where
D: Deserializer<'de>,
{
struct KindVisitor;
impl<'de> Visitor<'de> for KindVisitor {
type Value = OsStringKind;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`Unix` or `Windows`")
}
fn visit_u32<E>(self, value: u32) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
0 => Ok(OsStringKind::Unix),
1 => Ok(OsStringKind::Windows),
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
}
}
fn visit_str<E>(self, value: &str) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
"Unix" => Ok(OsStringKind::Unix),
"Windows" => Ok(OsStringKind::Windows),
_ => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<OsStringKind, E>
where
E: Error,
{
match value {
b"Unix" => Ok(OsStringKind::Unix),
b"Windows" => Ok(OsStringKind::Windows),
_ => {
match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
}
}
}
}
}
deserializer.deserialize_identifier(KindVisitor)
}
variant_identifier!{
OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1)
"`Unix` or `Windows`",
OSSTR_VARIANTS
}
#[cfg(all(feature = "std", any(unix, windows)))]
+9
View File
@@ -1011,6 +1011,15 @@ pub trait Deserializer<'de>: Sized {
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
/// Returns whether the serialized data is human readable or not.
///
/// Some formats are not intended to be human readable. For these formats
/// a type being serialized may opt to serialize into a more compact form.
///
/// NOTE: Implementing this method and returning `false` is considered a breaking
/// change as it may alter how any given type tries to deserialize itself.
fn is_human_readable(&self) -> bool { true }
}
////////////////////////////////////////////////////////////////////////////////
+52 -18
View File
@@ -506,9 +506,18 @@ impl Serialize for net::IpAddr {
where
S: Serializer,
{
match *self {
net::IpAddr::V4(ref a) => a.serialize(serializer),
net::IpAddr::V6(ref a) => a.serialize(serializer),
if serializer.is_human_readable() {
match *self {
net::IpAddr::V4(ref a) => a.serialize(serializer),
net::IpAddr::V6(ref a) => a.serialize(serializer),
}
} else {
match *self {
net::IpAddr::V4(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a),
net::IpAddr::V6(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a),
}
}
}
}
@@ -519,9 +528,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 +544,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)
}
}
}
@@ -543,9 +560,18 @@ impl Serialize for net::SocketAddr {
where
S: Serializer,
{
match *self {
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
if serializer.is_human_readable() {
match *self {
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
}
} else {
match *self {
net::SocketAddr::V4(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr),
net::SocketAddr::V6(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr),
}
}
}
}
@@ -556,9 +582,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(), self.port()).serialize(serializer)
}
}
}
@@ -568,9 +598,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(), self.port()).serialize(serializer)
}
}
}
+9
View File
@@ -1363,6 +1363,15 @@ pub trait Serializer: Sized {
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display;
/// Returns wheter the data format is human readable or not.
///
/// Some formats are not intended to be human readable. For these formats
/// a type being serialized may opt to serialize into a more compact form.
///
/// NOTE: Implementing this method and returning `false` is considered a breaking
/// change as it may alter how any given type tries to serialize itself.
fn is_human_readable(&self) -> bool { true }
}
/// Returned from `Serializer::serialize_seq`.