From 665d6140b19a41f699b074599240b21beafd22d2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 5 Jan 2019 23:31:09 -0800 Subject: [PATCH] Add support for Serde 1.0 --- Cargo.toml | 1 + src/host.rs | 56 -------------------------------- src/legacy.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 40 +++++++---------------- src/serde.rs | 45 ++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 85 deletions(-) create mode 100644 src/legacy.rs create mode 100644 src/serde.rs diff --git a/Cargo.toml b/Cargo.toml index 40e6b64f5..43f440e76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ matches = "0.1" percent-encoding = { version = "1.0.0", path = "./percent_encoding" } rustc-serialize = {version = "0.3", optional = true} serde = {version = ">=0.6.1, <0.9", optional = true} +serde1 = {version = "1.0", optional = true} [[bench]] name = "parse_url" diff --git a/src/host.rs b/src/host.rs index 38e88a3bb..99123d9d7 100644 --- a/src/host.rs +++ b/src/host.rs @@ -27,38 +27,6 @@ pub enum HostInternal { #[cfg(feature = "heapsize")] known_heap_size!(0, HostInternal); -#[cfg(feature="serde")] -impl ::serde::Serialize for HostInternal { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: ::serde::Serializer { - // This doesn’t use `derive` because that involves - // large dependencies (that take a long time to build), and - // either Macros 1.1 which are not stable yet or a cumbersome build script. - // - // Implementing `Serializer` correctly for an enum is tricky, - // so let’s use existing enums that already do. - use std::net::IpAddr; - match *self { - HostInternal::None => None, - HostInternal::Domain => Some(None), - HostInternal::Ipv4(addr) => Some(Some(IpAddr::V4(addr))), - HostInternal::Ipv6(addr) => Some(Some(IpAddr::V6(addr))), - }.serialize(serializer) - } -} - -#[cfg(feature="serde")] -impl ::serde::Deserialize for HostInternal { - fn deserialize(deserializer: &mut D) -> Result where D: ::serde::Deserializer { - use std::net::IpAddr; - Ok(match ::serde::Deserialize::deserialize(deserializer)? { - None => HostInternal::None, - Some(None) => HostInternal::Domain, - Some(Some(IpAddr::V4(addr))) => HostInternal::Ipv4(addr), - Some(Some(IpAddr::V6(addr))) => HostInternal::Ipv6(addr), - }) - } -} - impl From> for HostInternal { fn from(host: Host) -> HostInternal { match host { @@ -91,30 +59,6 @@ pub enum Host { Ipv6(Ipv6Addr), } -#[cfg(feature="serde")] -impl ::serde::Serialize for Host { - fn serialize(&self, serializer: &mut R) -> Result<(), R::Error> where R: ::serde::Serializer { - use std::net::IpAddr; - match *self { - Host::Domain(ref s) => Ok(s), - Host::Ipv4(addr) => Err(IpAddr::V4(addr)), - Host::Ipv6(addr) => Err(IpAddr::V6(addr)), - }.serialize(serializer) - } -} - -#[cfg(feature="serde")] -impl ::serde::Deserialize for Host { - fn deserialize(deserializer: &mut D) -> Result where D: ::serde::Deserializer { - use std::net::IpAddr; - Ok(match ::serde::Deserialize::deserialize(deserializer)? { - Ok(s) => Host::Domain(s), - Err(IpAddr::V4(addr)) => Host::Ipv4(addr), - Err(IpAddr::V6(addr)) => Host::Ipv6(addr), - }) - } -} - #[cfg(feature = "heapsize")] impl HeapSizeOf for Host { fn heap_size_of_children(&self) -> usize { diff --git a/src/legacy.rs b/src/legacy.rs new file mode 100644 index 000000000..61f386c09 --- /dev/null +++ b/src/legacy.rs @@ -0,0 +1,89 @@ +use std::error::Error; +use std::net::IpAddr; + +use legacy_serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +use host::HostInternal; +use Host; +use Url; + +/// Serializes this URL into a `serde` stream. +/// +/// This implementation is only available if the `serde` Cargo feature is enabled. +impl Serialize for Url { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +/// Deserializes this URL from a `serde` stream. +/// +/// This implementation is only available if the `serde` Cargo feature is enabled. +impl Deserialize for Url { + fn deserialize(deserializer: &mut D) -> Result + where + D: Deserializer, + { + let string_representation = String::deserialize(deserializer)?; + Url::parse(&string_representation).map_err(|err| { + de::Error::invalid_value(err.description()) + }) + } +} + +impl Serialize for HostInternal { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where + S: Serializer, + { + match *self { + HostInternal::None => None, + HostInternal::Domain => Some(None), + HostInternal::Ipv4(addr) => Some(Some(IpAddr::V4(addr))), + HostInternal::Ipv6(addr) => Some(Some(IpAddr::V6(addr))), + }.serialize(serializer) + } +} + +impl Deserialize for HostInternal { + fn deserialize(deserializer: &mut D) -> Result + where + D: Deserializer, + { + Ok(match Deserialize::deserialize(deserializer)? { + None => HostInternal::None, + Some(None) => HostInternal::Domain, + Some(Some(IpAddr::V4(addr))) => HostInternal::Ipv4(addr), + Some(Some(IpAddr::V6(addr))) => HostInternal::Ipv6(addr), + }) + } +} + +impl Serialize for Host { + fn serialize(&self, serializer: &mut R) -> Result<(), R::Error> + where + R: Serializer, + { + match *self { + Host::Domain(ref s) => Ok(s), + Host::Ipv4(addr) => Err(IpAddr::V4(addr)), + Host::Ipv6(addr) => Err(IpAddr::V6(addr)), + }.serialize(serializer) + } +} + +impl Deserialize for Host { + fn deserialize(deserializer: &mut D) -> Result + where + D: Deserializer, + { + Ok(match Deserialize::deserialize(deserializer)? { + Ok(s) => Host::Domain(s), + Err(IpAddr::V4(addr)) => Host::Ipv4(addr), + Err(IpAddr::V6(addr)) => Host::Ipv6(addr), + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 53348c396..a1de758fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,8 @@ assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css"); #[cfg(feature="rustc-serialize")] extern crate rustc_serialize; #[macro_use] extern crate matches; -#[cfg(feature="serde")] extern crate serde; +#[cfg(feature="serde")] extern crate serde as legacy_serde; +#[cfg(feature="serde1")] extern crate serde1; #[cfg(feature="heapsize")] #[macro_use] extern crate heapsize; pub extern crate idna; @@ -123,7 +124,6 @@ use percent_encoding::{PATH_SEGMENT_ENCODE_SET, USERINFO_ENCODE_SET, percent_encode, percent_decode, utf8_percent_encode}; use std::borrow::Borrow; use std::cmp; -#[cfg(feature = "serde")] use std::error::Error; use std::fmt::{self, Write, Debug, Formatter}; use std::hash; use std::io; @@ -146,6 +146,11 @@ mod path_segments; mod parser; mod slicing; +#[cfg(feature = "serde")] +mod legacy; +#[cfg(feature = "serde1")] +mod serde; + pub mod form_urlencoded; #[doc(hidden)] pub mod quirks; @@ -2028,8 +2033,8 @@ impl Url { /// This method is only available if the `serde` Cargo feature is enabled. #[cfg(feature = "serde")] #[deny(unused)] - pub fn serialize_internal(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { - use serde::Serialize; + pub fn serialize_internal(&self, serializer: &mut S) -> Result<(), S::Error> where S: legacy_serde::Serializer { + use legacy_serde::Serialize; // Destructuring first lets us ensure that adding or removing fields forces this method // to be updated let Url { ref serialization, ref scheme_end, @@ -2050,8 +2055,8 @@ impl Url { /// This method is only available if the `serde` Cargo feature is enabled. #[cfg(feature = "serde")] #[deny(unused)] - pub fn deserialize_internal(deserializer: &mut D) -> Result where D: serde::Deserializer { - use serde::{Deserialize, Error}; + pub fn deserialize_internal(deserializer: &mut D) -> Result where D: legacy_serde::Deserializer { + use legacy_serde::{Deserialize, Error}; let (serialization, scheme_end, username_end, host_start, host_end, host, port, path_start, query_start, fragment_start) = Deserialize::deserialize(deserializer)?; @@ -2242,29 +2247,6 @@ impl rustc_serialize::Decodable for Url { } } -/// Serializes this URL into a `serde` stream. -/// -/// This implementation is only available if the `serde` Cargo feature is enabled. -#[cfg(feature="serde")] -impl serde::Serialize for Url { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { - serializer.serialize_str(self.as_str()) - } -} - -/// Deserializes this URL from a `serde` stream. -/// -/// This implementation is only available if the `serde` Cargo feature is enabled. -#[cfg(feature="serde")] -impl serde::Deserialize for Url { - fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { - let string_representation: String = serde::Deserialize::deserialize(deserializer)?; - Url::parse(&string_representation).map_err(|err| { - serde::Error::invalid_value(err.description()) - }) - } -} - #[cfg(any(unix, target_os = "redox"))] fn path_to_file_url_segments(path: &Path, serialization: &mut String) -> Result<(u32, HostInternal), ()> { diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 000000000..8ee1d70f3 --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,45 @@ +use std::fmt; + +use serde1::de::{self, Deserialize, Deserializer, Visitor}; +use serde1::ser::{Serialize, Serializer}; + +use Url; + +/// This implementation is only available if the `serde1` Cargo feature is +/// enabled. +impl Serialize for Url { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +/// This implementation is only available if the `serde1` Cargo feature is +/// enabled. +impl<'de> Deserialize<'de> for Url { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct UrlVisitor; + + impl<'de> Visitor<'de> for UrlVisitor { + type Value = Url; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a URL string") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + s.parse().map_err(de::Error::custom) + } + } + + deserializer.deserialize_str(UrlVisitor) + } +}