From cb3daf280f64673e027d0e87ac443b1d7deaef4a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 17 Dec 2016 12:46:49 -0800 Subject: [PATCH 1/2] Add faster serde serialization, sacrificing invariant-safety for speed in release mode; test that it roudtrips --- Cargo.toml | 4 +++- src/host.rs | 36 ++++++++++++++++++++++++++++ src/lib.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++------ tests/data.rs | 20 +++++++++++++--- 4 files changed, 114 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d0b4d573..840ce830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ test = false [dev-dependencies] rustc-test = "0.1" rustc-serialize = "0.3" +serde = "0.8.20" +bincode = {version = "0.6.0", features = ["serde"] } [features] query_encoding = ["encoding"] @@ -35,4 +37,4 @@ heapsize = {version = ">=0.1.1, <0.4", optional = true} idna = { version = "0.1.0", path = "./idna" } matches = "0.1" rustc-serialize = {version = "0.3", optional = true} -serde = {version = ">=0.6.1, <0.9", optional = true} +serde = {version = "0.8.20", optional = true} diff --git a/src/host.rs b/src/host.rs index e420ca8b..d78ce83d 100644 --- a/src/host.rs +++ b/src/host.rs @@ -16,6 +16,9 @@ use parser::{ParseResult, ParseError}; use percent_encoding::percent_decode; use idna; +#[cfg(feature="serde")] +use serde; + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum HostInternal { None, @@ -27,6 +30,39 @@ 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 { + match *self { + HostInternal::None => 0u8.serialize(serializer), + HostInternal::Domain => 1u8.serialize(serializer), + HostInternal::Ipv4(addr) => { + 2u8.serialize(serializer)?; + addr.serialize(serializer) + } + HostInternal::Ipv6(addr) => { + 3u8.serialize(serializer)?; + addr.serialize(serializer) + } + } + } +} + +#[cfg(feature="serde")] +impl serde::Deserialize for HostInternal { + fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { + use serde::{Deserialize, Error}; + let discr: u8 = Deserialize::deserialize(deserializer)?; + match discr { + 0 => Ok(HostInternal::None), + 1 => Ok(HostInternal::Domain), + 2 => Ok(HostInternal::Ipv4(Deserialize::deserialize(deserializer)?)), + 3 => Ok(HostInternal::Ipv6(Deserialize::deserialize(deserializer)?)), + _ => Err(D::Error::unknown_variant("Unknown variant")), + } + } +} + impl From> for HostInternal { fn from(host: Host) -> HostInternal { match host { diff --git a/src/lib.rs b/src/lib.rs index 9f273cbb..39ec3768 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -312,17 +312,23 @@ impl Url { self.serialization } + #[doc(hidden)] + pub fn assert_invariants(&self) { + self.assert_invariants_result().unwrap() + } + /// For internal testing, not part of the public API. /// /// Methods of the `Url` struct assume a number of invariants. /// This checks each of these invariants and panic if one is not met. /// This is for testing rust-url itself. #[doc(hidden)] - pub fn assert_invariants(&self) { + pub fn assert_invariants_result(&self) -> Result<(), String> { macro_rules! assert { ($x: expr) => { if !$x { - panic!("!( {} ) for URL {:?}", stringify!($x), self.serialization) + return Err(format!("!( {} ) for URL {:?}", + stringify!($x), self.serialization)) } } } @@ -333,8 +339,9 @@ impl Url { let a = $a; let b = $b; if a != b { - panic!("{:?} != {:?} ({} != {}) for URL {:?}", - a, b, stringify!($a), stringify!($b), self.serialization) + return Err(format!("{:?} != {:?} ({} != {}) for URL {:?}", + a, b, stringify!($a), stringify!($b), + self.serialization)) } } } @@ -415,6 +422,7 @@ impl Url { assert_eq!(self.path_start, other.path_start); assert_eq!(self.query_start, other.query_start); assert_eq!(self.fragment_start, other.fragment_start); + Ok(()) } /// Return the origin of this URL (https://url.spec.whatwg.org/#origin) @@ -1506,9 +1514,24 @@ impl rustc_serialize::Decodable for Url { /// /// This implementation is only available if the `serde` Cargo feature is enabled. #[cfg(feature="serde")] +#[deny(unused)] impl serde::Serialize for Url { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { - format!("{}", self).serialize(serializer) + let Url { ref serialization, ref scheme_end, + ref username_end, ref host_start, + ref host_end, ref host, ref port, + ref path_start, ref query_start, + ref fragment_start} = *self; + serialization.serialize(serializer)?; + scheme_end.serialize(serializer)?; + username_end.serialize(serializer)?; + host_start.serialize(serializer)?; + host_end.serialize(serializer)?; + host.serialize(serializer)?; + port.serialize(serializer)?; + path_start.serialize(serializer)?; + query_start.serialize(serializer)?; + fragment_start.serialize(serializer) } } @@ -1516,10 +1539,38 @@ impl serde::Serialize for Url { /// /// This implementation is only available if the `serde` Cargo feature is enabled. #[cfg(feature="serde")] +#[deny(unused)] impl serde::Deserialize for Url { fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { - let string_representation: String = try!(serde::Deserialize::deserialize(deserializer)); - Ok(Url::parse(&string_representation).unwrap()) + use serde::{Deserialize, Error}; + let serialization = Deserialize::deserialize(deserializer)?; + let scheme_end = Deserialize::deserialize(deserializer)?; + let username_end = Deserialize::deserialize(deserializer)?; + let host_start = Deserialize::deserialize(deserializer)?; + let host_end = Deserialize::deserialize(deserializer)?; + let host = Deserialize::deserialize(deserializer)?; + let port = Deserialize::deserialize(deserializer)?; + let path_start = Deserialize::deserialize(deserializer)?; + let query_start = Deserialize::deserialize(deserializer)?; + let fragment_start = Deserialize::deserialize(deserializer)?; + let url = Url { + serialization: serialization, + scheme_end: scheme_end, + username_end: username_end, + host_start: host_start, + host_end: host_end, + host: host, + port: port, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start + }; + #[cfg(debug_assertions)] { + if let Err(s) = url.assert_invariants_result() { + return Err(Error::invalid_value(&s)) + } + } + Ok(url) } } diff --git a/tests/data.rs b/tests/data.rs index b8945aa4..c88be5b9 100644 --- a/tests/data.rs +++ b/tests/data.rs @@ -8,13 +8,27 @@ //! Data-driven tests +extern crate bincode; extern crate rustc_serialize; +#[cfg(feature="serde")] +extern crate serde; extern crate test; extern crate url; use rustc_serialize::json::{self, Json}; use url::{Url, quirks}; +fn assert_invariants(url: &Url) { + url.assert_invariants(); + #[cfg(feature="serde")] { + use bincode::SizeLimit; + use bincode::serde::{deserialize, serialize}; + let bytes = serialize(url, SizeLimit::Infinite).unwrap(); + let new_url: Url = deserialize(&bytes).unwrap(); + assert_eq!(url, &new_url); + } +} + fn run_parsing(input: String, base: String, expected: Result) { let base = match Url::parse(&base) { @@ -28,7 +42,7 @@ fn run_parsing(input: String, base: String, expected: Result panic!("Expected a parse error for URL {:?}", input), }; - url.assert_invariants(); + assert_invariants(&url); macro_rules! assert_eq { ($expected: expr, $got: expr) => { @@ -144,11 +158,11 @@ fn collect_setters(add_test: &mut F) where F: FnMut(String, test::TestFn) { let mut expected = test.take("expected").unwrap(); add_test(name, test::TestFn::dyn_test_fn(move || { let mut url = Url::parse(&href).unwrap(); - url.assert_invariants(); + assert_invariants(&url); let _ = quirks::$setter(&mut url, &new_value); assert_attributes!(url, expected, href protocol username password host hostname port pathname search hash); - url.assert_invariants(); + assert_invariants(&url); })) } }} From 8823ca792208168690b9cae38570c3b2ab6af51b Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sat, 17 Dec 2016 14:25:17 -0800 Subject: [PATCH 2/2] Add an external serde code generator to cut down on compile time --- serde-code-generator/Cargo.toml | 7 + serde-code-generator/README.md | 11 + serde-code-generator/src/main.rs | 15 + serde-code-generator/url.rs | 486 ++++++++++++++++++++++++++++++ src/codegen/host.rs | 154 ++++++++++ src/codegen/host.rs.in | 12 + src/codegen/url.rs | 492 +++++++++++++++++++++++++++++++ src/codegen/url.rs.in | 30 ++ src/host.rs | 44 +-- src/lib.rs | 90 +----- 10 files changed, 1209 insertions(+), 132 deletions(-) create mode 100644 serde-code-generator/Cargo.toml create mode 100644 serde-code-generator/README.md create mode 100644 serde-code-generator/src/main.rs create mode 100644 serde-code-generator/url.rs create mode 100644 src/codegen/host.rs create mode 100644 src/codegen/host.rs.in create mode 100644 src/codegen/url.rs create mode 100644 src/codegen/url.rs.in diff --git a/serde-code-generator/Cargo.toml b/serde-code-generator/Cargo.toml new file mode 100644 index 00000000..bbcd2d22 --- /dev/null +++ b/serde-code-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "serde-code-generator" +version = "0.1.0" +authors = ["Erick Tryzelaar "] + +[dependencies] +serde_codegen = { version = "^0.8" } diff --git a/serde-code-generator/README.md b/serde-code-generator/README.md new file mode 100644 index 00000000..f9e7dd3c --- /dev/null +++ b/serde-code-generator/README.md @@ -0,0 +1,11 @@ +# Serde Code Generator + +It's complicated to write full featured serde implementations, but we don't +want to force our dependenices to depend on +[serde_codegen](https://serde.rs/codegen-stable.html), which takes a while to +compile. This executable avoids that overhead by externally regenerating these +implementations, so only the rust-url developers need to pay the cost of +compiling `serde_codegen`. It does come at the price of having to remember to +re-run the code generator if the types ever change. + +To run, just execute `cargo run` and it will update the files in `src/codegen`. diff --git a/serde-code-generator/src/main.rs b/serde-code-generator/src/main.rs new file mode 100644 index 00000000..eb958508 --- /dev/null +++ b/serde-code-generator/src/main.rs @@ -0,0 +1,15 @@ +extern crate serde_codegen; + +use std::path::Path; + +pub fn main() { + let src = Path::new("../src/codegen/url.rs.in"); + let dst = Path::new("../src/codegen/url.rs"); + + serde_codegen::expand(&src, &dst).unwrap(); + + let src = Path::new("../src/codegen/host.rs.in"); + let dst = Path::new("../src/codegen/host.rs"); + + serde_codegen::expand(&src, &dst).unwrap(); +} diff --git a/serde-code-generator/url.rs b/serde-code-generator/url.rs new file mode 100644 index 00000000..415e629c --- /dev/null +++ b/serde-code-generator/url.rs @@ -0,0 +1,486 @@ + +// Components +// Before ':' +// Before ':' (if a password is given) or '@' (if not) +// Before initial '/', if any +// Before '?', unlike Position::QueryStart +// Before '#', unlike Position::FragmentStart +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +const _IMPL_DESERIALIZE_FOR_Url: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::de::Deserialize for Url { + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result where + __D: _serde::de::Deserializer { + #[allow(non_camel_case_types)] + enum __Field { + __field0, + __field1, + __field2, + __field3, + __field4, + __field5, + __field6, + __field7, + __field8, + __field9, + __ignore, + } + impl _serde::de::Deserialize for __Field { + #[inline] + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result<__Field, __D::Error> where + __D: _serde::de::Deserializer { + struct __FieldVisitor; + impl _serde::de::Visitor for __FieldVisitor { + type + Value + = + __Field; + fn visit_usize<__E>(&mut self, value: usize) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + 0usize => { Ok(__Field::__field0) } + 1usize => { Ok(__Field::__field1) } + 2usize => { Ok(__Field::__field2) } + 3usize => { Ok(__Field::__field3) } + 4usize => { Ok(__Field::__field4) } + 5usize => { Ok(__Field::__field5) } + 6usize => { Ok(__Field::__field6) } + 7usize => { Ok(__Field::__field7) } + 8usize => { Ok(__Field::__field8) } + 9usize => { Ok(__Field::__field9) } + _ => Ok(__Field::__ignore), + } + } + fn visit_str<__E>(&mut self, value: &str) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + "serialization" => { + Ok(__Field::__field0) + } + "scheme_end" => { Ok(__Field::__field1) } + "username_end" => { + Ok(__Field::__field2) + } + "host_start" => { Ok(__Field::__field3) } + "host_end" => { Ok(__Field::__field4) } + "host" => { Ok(__Field::__field5) } + "port" => { Ok(__Field::__field6) } + "path_start" => { Ok(__Field::__field7) } + "query_start" => { Ok(__Field::__field8) } + "fragment_start" => { + Ok(__Field::__field9) + } + _ => Ok(__Field::__ignore), + } + } + fn visit_bytes<__E>(&mut self, value: &[u8]) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + b"serialization" => { + Ok(__Field::__field0) + } + b"scheme_end" => { Ok(__Field::__field1) } + b"username_end" => { + Ok(__Field::__field2) + } + b"host_start" => { Ok(__Field::__field3) } + b"host_end" => { Ok(__Field::__field4) } + b"host" => { Ok(__Field::__field5) } + b"port" => { Ok(__Field::__field6) } + b"path_start" => { Ok(__Field::__field7) } + b"query_start" => { + Ok(__Field::__field8) + } + b"fragment_start" => { + Ok(__Field::__field9) + } + _ => Ok(__Field::__ignore), + } + } + } + deserializer.deserialize_struct_field(__FieldVisitor) + } + } + struct __Visitor; + impl _serde::de::Visitor for __Visitor { + type + Value + = + Url; + #[inline] + fn visit_seq<__V>(&mut self, mut visitor: __V) + -> ::std::result::Result where + __V: _serde::de::SeqVisitor { + let __field0 = + match try!(visitor . visit :: < String > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(0usize)); + } + }; + let __field1 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(1usize)); + } + }; + let __field2 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(2usize)); + } + }; + let __field3 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(3usize)); + } + }; + let __field4 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(4usize)); + } + }; + let __field5 = + match try!(visitor . visit :: < HostInternal > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(5usize)); + } + }; + let __field6 = + match try!(visitor . visit :: < Option < u16 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(6usize)); + } + }; + let __field7 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(7usize)); + } + }; + let __field8 = + match try!(visitor . visit :: < Option < u32 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(8usize)); + } + }; + let __field9 = + match try!(visitor . visit :: < Option < u32 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(9usize)); + } + }; + try!(visitor . end ( )); + Ok(Url{serialization: __field0, + scheme_end: __field1, + username_end: __field2, + host_start: __field3, + host_end: __field4, + host: __field5, + port: __field6, + path_start: __field7, + query_start: __field8, + fragment_start: __field9,}) + } + #[inline] + fn visit_map<__V>(&mut self, mut visitor: __V) + -> ::std::result::Result where + __V: _serde::de::MapVisitor { + let mut __field0: Option = None; + let mut __field1: Option = None; + let mut __field2: Option = None; + let mut __field3: Option = None; + let mut __field4: Option = None; + let mut __field5: Option = None; + let mut __field6: Option> = None; + let mut __field7: Option = None; + let mut __field8: Option> = None; + let mut __field9: Option> = None; + while let Some(key) = + try!(visitor . visit_key :: < __Field > ( + )) { + match key { + __Field::__field0 => { + if __field0.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("serialization")); + } + __field0 = + Some(try!(visitor . visit_value :: < + String > ( ))); + } + __Field::__field1 => { + if __field1.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("scheme_end")); + } + __field1 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field2 => { + if __field2.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("username_end")); + } + __field2 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field3 => { + if __field3.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host_start")); + } + __field3 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field4 => { + if __field4.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host_end")); + } + __field4 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field5 => { + if __field5.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host")); + } + __field5 = + Some(try!(visitor . visit_value :: < + HostInternal > ( ))); + } + __Field::__field6 => { + if __field6.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("port")); + } + __field6 = + Some(try!(visitor . visit_value :: < + Option < u16 > > ( ))); + } + __Field::__field7 => { + if __field7.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("path_start")); + } + __field7 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field8 => { + if __field8.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("query_start")); + } + __field8 = + Some(try!(visitor . visit_value :: < + Option < u32 > > ( ))); + } + __Field::__field9 => { + if __field9.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("fragment_start")); + } + __field9 = + Some(try!(visitor . visit_value :: < + Option < u32 > > ( ))); + } + _ => { + let _ = + try!(visitor . visit_value :: < _serde + :: de :: impls :: IgnoredAny > ( + )); + } + } + } + try!(visitor . end ( )); + let __field0 = + match __field0 { + Some(__field0) => __field0, + None => + try!(visitor . missing_field ( "serialization" + )), + }; + let __field1 = + match __field1 { + Some(__field1) => __field1, + None => + try!(visitor . missing_field ( "scheme_end" + )), + }; + let __field2 = + match __field2 { + Some(__field2) => __field2, + None => + try!(visitor . missing_field ( "username_end" + )), + }; + let __field3 = + match __field3 { + Some(__field3) => __field3, + None => + try!(visitor . missing_field ( "host_start" + )), + }; + let __field4 = + match __field4 { + Some(__field4) => __field4, + None => + try!(visitor . missing_field ( "host_end" )), + }; + let __field5 = + match __field5 { + Some(__field5) => __field5, + None => + try!(visitor . missing_field ( "host" )), + }; + let __field6 = + match __field6 { + Some(__field6) => __field6, + None => + try!(visitor . missing_field ( "port" )), + }; + let __field7 = + match __field7 { + Some(__field7) => __field7, + None => + try!(visitor . missing_field ( "path_start" + )), + }; + let __field8 = + match __field8 { + Some(__field8) => __field8, + None => + try!(visitor . missing_field ( "query_start" + )), + }; + let __field9 = + match __field9 { + Some(__field9) => __field9, + None => + try!(visitor . missing_field ( + "fragment_start" )), + }; + Ok(Url{serialization: __field0, + scheme_end: __field1, + username_end: __field2, + host_start: __field3, + host_end: __field4, + host: __field5, + port: __field6, + path_start: __field7, + query_start: __field8, + fragment_start: __field9,}) + } + } + const FIELDS: &'static [&'static str] = + &["serialization", "scheme_end", "username_end", + "host_start", "host_end", "host", "port", "path_start", + "query_start", "fragment_start"]; + deserializer.deserialize_struct("Url", FIELDS, __Visitor) + } + } + }; +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +const _IMPL_SERIALIZE_FOR_Url: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::ser::Serialize for Url { + fn serialize<__S>(&self, _serializer: &mut __S) + -> ::std::result::Result<(), __S::Error> where + __S: _serde::ser::Serializer { + let mut __serde_state = + try!(_serializer . serialize_struct ( + "Url" , 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "serialization" , & self . + serialization )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "scheme_end" , & self . scheme_end + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "username_end" , & self . + username_end )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host_start" , & self . host_start + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host_end" , & self . host_end )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host" , & self . host )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "port" , & self . port )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "path_start" , & self . path_start + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "query_start" , & self . + query_start )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "fragment_start" , & self . + fragment_start )); + _serializer.serialize_struct_end(__serde_state) + } + } + }; +/// A parsed URL record. +#[derive(Clone)] +pub struct Url { + /// Syntax in pseudo-BNF: + /// + /// url = scheme ":" [ hierarchical | non-hierarchical ] [ "?" query ]? [ "#" fragment ]? + /// non-hierarchical = non-hierarchical-path + /// non-hierarchical-path = /* Does not start with "/" */ + /// hierarchical = authority? hierarchical-path + /// authority = "//" userinfo? host [ ":" port ]? + /// userinfo = username [ ":" password ]? "@" + /// hierarchical-path = [ "/" path-segment ]+ + serialization: String, + scheme_end: u32, + username_end: u32, + host_start: u32, + host_end: u32, + host: HostInternal, + port: Option, + path_start: u32, + query_start: Option, + fragment_start: Option, +} diff --git a/src/codegen/host.rs b/src/codegen/host.rs new file mode 100644 index 00000000..8638674b --- /dev/null +++ b/src/codegen/host.rs @@ -0,0 +1,154 @@ +// WARNING: Do not modify this file if it is `host.rs`. +// +// Instead, modify `host.rs.in` and rerun the `serde-code-generator`. + +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +#[cfg(feature = "serde")] +const _IMPL_DESERIALIZE_FOR_HostInternal: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::de::Deserialize for HostInternal { + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result where + __D: _serde::de::Deserializer { + #[allow(non_camel_case_types)] + enum __Field { + __field0, + __field1, + __field2, + __field3, + __ignore, + } + impl _serde::de::Deserialize for __Field { + #[inline] + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result<__Field, __D::Error> where + __D: _serde::de::Deserializer { + struct __FieldVisitor; + impl _serde::de::Visitor for __FieldVisitor { + type + Value + = + __Field; + fn visit_usize<__E>(&mut self, value: usize) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + 0usize => { Ok(__Field::__field0) } + 1usize => { Ok(__Field::__field1) } + 2usize => { Ok(__Field::__field2) } + 3usize => { Ok(__Field::__field3) } + _ => + Err(_serde::de::Error::invalid_value("expected a variant")), + } + } + fn visit_str<__E>(&mut self, value: &str) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + "None" => { Ok(__Field::__field0) } + "Domain" => { Ok(__Field::__field1) } + "Ipv4" => { Ok(__Field::__field2) } + "Ipv6" => { Ok(__Field::__field3) } + _ => + Err(_serde::de::Error::unknown_variant(value)), + } + } + fn visit_bytes<__E>(&mut self, value: &[u8]) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + b"None" => { Ok(__Field::__field0) } + b"Domain" => { Ok(__Field::__field1) } + b"Ipv4" => { Ok(__Field::__field2) } + b"Ipv6" => { Ok(__Field::__field3) } + _ => { + let value = + ::std::string::String::from_utf8_lossy(value); + Err(_serde::de::Error::unknown_variant(&value)) + } + } + } + } + deserializer.deserialize_struct_field(__FieldVisitor) + } + } + struct __Visitor; + impl _serde::de::EnumVisitor for __Visitor { + type + Value + = + HostInternal; + fn visit<__V>(&mut self, mut visitor: __V) + -> ::std::result::Result where + __V: _serde::de::VariantVisitor { + match try!(visitor . visit_variant ( )) { + __Field::__field0 => { + try!(visitor . visit_unit ( )); + Ok(HostInternal::None) + } + __Field::__field1 => { + try!(visitor . visit_unit ( )); + Ok(HostInternal::Domain) + } + __Field::__field2 => + Ok(HostInternal::Ipv4(try!(visitor . visit_newtype + :: < Ipv4Addr > ( + )))), + __Field::__field3 => + Ok(HostInternal::Ipv6(try!(visitor . visit_newtype + :: < Ipv6Addr > ( + )))), + __Field::__ignore => { + Err(_serde::de::Error::end_of_stream()) + } + } + } + } + const VARIANTS: &'static [&'static str] = + &["None", "Domain", "Ipv4", "Ipv6"]; + deserializer.deserialize_enum("HostInternal", VARIANTS, + __Visitor) + } + } + }; +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +#[cfg(feature = "serde")] +const _IMPL_SERIALIZE_FOR_HostInternal: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::ser::Serialize for HostInternal { + fn serialize<__S>(&self, _serializer: &mut __S) + -> ::std::result::Result<(), __S::Error> where + __S: _serde::ser::Serializer { + match *self { + HostInternal::None => + _serde::ser::Serializer::serialize_unit_variant(_serializer, + "HostInternal", + 0usize, + "None"), + HostInternal::Domain => + _serde::ser::Serializer::serialize_unit_variant(_serializer, + "HostInternal", + 1usize, + "Domain"), + HostInternal::Ipv4(ref __simple_value) => + _serde::ser::Serializer::serialize_newtype_variant(_serializer, + "HostInternal", + 2usize, + "Ipv4", + __simple_value), + HostInternal::Ipv6(ref __simple_value) => + _serde::ser::Serializer::serialize_newtype_variant(_serializer, + "HostInternal", + 3usize, + "Ipv6", + __simple_value), + } + } + } + }; +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub enum HostInternal { None, Domain, Ipv4(Ipv4Addr), Ipv6(Ipv6Addr), } diff --git a/src/codegen/host.rs.in b/src/codegen/host.rs.in new file mode 100644 index 00000000..564af844 --- /dev/null +++ b/src/codegen/host.rs.in @@ -0,0 +1,12 @@ +// WARNING: Do not modify this file if it is `host.rs`. +// +// Instead, modify `host.rs.in` and rerun the `serde-code-generator`. + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature="serde", derive(Serialize, Deserialize))] +pub enum HostInternal { + None, + Domain, + Ipv4(Ipv4Addr), + Ipv6(Ipv6Addr), +} diff --git a/src/codegen/url.rs b/src/codegen/url.rs new file mode 100644 index 00000000..6dcc69a7 --- /dev/null +++ b/src/codegen/url.rs @@ -0,0 +1,492 @@ +// WARNING: Do not modify this file if it is `url.rs`. +// +// Instead, modify `url.rs.in` and rerun the `serde-code-generator`. + + +// Components +// Before ':' +// Before ':' (if a password is given) or '@' (if not) +// Before initial '/', if any +// Before '?', unlike Position::QueryStart +// Before '#', unlike Position::FragmentStart +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +#[cfg(feature = "serde")] +const _IMPL_DESERIALIZE_FOR_Url: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::de::Deserialize for Url { + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result where + __D: _serde::de::Deserializer { + #[allow(non_camel_case_types)] + enum __Field { + __field0, + __field1, + __field2, + __field3, + __field4, + __field5, + __field6, + __field7, + __field8, + __field9, + __ignore, + } + impl _serde::de::Deserialize for __Field { + #[inline] + fn deserialize<__D>(deserializer: &mut __D) + -> ::std::result::Result<__Field, __D::Error> where + __D: _serde::de::Deserializer { + struct __FieldVisitor; + impl _serde::de::Visitor for __FieldVisitor { + type + Value + = + __Field; + fn visit_usize<__E>(&mut self, value: usize) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + 0usize => { Ok(__Field::__field0) } + 1usize => { Ok(__Field::__field1) } + 2usize => { Ok(__Field::__field2) } + 3usize => { Ok(__Field::__field3) } + 4usize => { Ok(__Field::__field4) } + 5usize => { Ok(__Field::__field5) } + 6usize => { Ok(__Field::__field6) } + 7usize => { Ok(__Field::__field7) } + 8usize => { Ok(__Field::__field8) } + 9usize => { Ok(__Field::__field9) } + _ => Ok(__Field::__ignore), + } + } + fn visit_str<__E>(&mut self, value: &str) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + "serialization" => { + Ok(__Field::__field0) + } + "scheme_end" => { Ok(__Field::__field1) } + "username_end" => { + Ok(__Field::__field2) + } + "host_start" => { Ok(__Field::__field3) } + "host_end" => { Ok(__Field::__field4) } + "host" => { Ok(__Field::__field5) } + "port" => { Ok(__Field::__field6) } + "path_start" => { Ok(__Field::__field7) } + "query_start" => { Ok(__Field::__field8) } + "fragment_start" => { + Ok(__Field::__field9) + } + _ => Ok(__Field::__ignore), + } + } + fn visit_bytes<__E>(&mut self, value: &[u8]) + -> ::std::result::Result<__Field, __E> where + __E: _serde::de::Error { + match value { + b"serialization" => { + Ok(__Field::__field0) + } + b"scheme_end" => { Ok(__Field::__field1) } + b"username_end" => { + Ok(__Field::__field2) + } + b"host_start" => { Ok(__Field::__field3) } + b"host_end" => { Ok(__Field::__field4) } + b"host" => { Ok(__Field::__field5) } + b"port" => { Ok(__Field::__field6) } + b"path_start" => { Ok(__Field::__field7) } + b"query_start" => { + Ok(__Field::__field8) + } + b"fragment_start" => { + Ok(__Field::__field9) + } + _ => Ok(__Field::__ignore), + } + } + } + deserializer.deserialize_struct_field(__FieldVisitor) + } + } + struct __Visitor; + impl _serde::de::Visitor for __Visitor { + type + Value + = + Url; + #[inline] + fn visit_seq<__V>(&mut self, mut visitor: __V) + -> ::std::result::Result where + __V: _serde::de::SeqVisitor { + let __field0 = + match try!(visitor . visit :: < String > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(0usize)); + } + }; + let __field1 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(1usize)); + } + }; + let __field2 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(2usize)); + } + }; + let __field3 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(3usize)); + } + }; + let __field4 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(4usize)); + } + }; + let __field5 = + match try!(visitor . visit :: < HostInternal > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(5usize)); + } + }; + let __field6 = + match try!(visitor . visit :: < Option < u16 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(6usize)); + } + }; + let __field7 = + match try!(visitor . visit :: < u32 > ( )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(7usize)); + } + }; + let __field8 = + match try!(visitor . visit :: < Option < u32 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(8usize)); + } + }; + let __field9 = + match try!(visitor . visit :: < Option < u32 > > ( + )) { + Some(value) => { value } + None => { + try!(visitor . end ( )); + return Err(_serde::de::Error::invalid_length(9usize)); + } + }; + try!(visitor . end ( )); + Ok(Url{serialization: __field0, + scheme_end: __field1, + username_end: __field2, + host_start: __field3, + host_end: __field4, + host: __field5, + port: __field6, + path_start: __field7, + query_start: __field8, + fragment_start: __field9,}) + } + #[inline] + fn visit_map<__V>(&mut self, mut visitor: __V) + -> ::std::result::Result where + __V: _serde::de::MapVisitor { + let mut __field0: Option = None; + let mut __field1: Option = None; + let mut __field2: Option = None; + let mut __field3: Option = None; + let mut __field4: Option = None; + let mut __field5: Option = None; + let mut __field6: Option> = None; + let mut __field7: Option = None; + let mut __field8: Option> = None; + let mut __field9: Option> = None; + while let Some(key) = + try!(visitor . visit_key :: < __Field > ( + )) { + match key { + __Field::__field0 => { + if __field0.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("serialization")); + } + __field0 = + Some(try!(visitor . visit_value :: < + String > ( ))); + } + __Field::__field1 => { + if __field1.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("scheme_end")); + } + __field1 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field2 => { + if __field2.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("username_end")); + } + __field2 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field3 => { + if __field3.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host_start")); + } + __field3 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field4 => { + if __field4.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host_end")); + } + __field4 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field5 => { + if __field5.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("host")); + } + __field5 = + Some(try!(visitor . visit_value :: < + HostInternal > ( ))); + } + __Field::__field6 => { + if __field6.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("port")); + } + __field6 = + Some(try!(visitor . visit_value :: < + Option < u16 > > ( ))); + } + __Field::__field7 => { + if __field7.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("path_start")); + } + __field7 = + Some(try!(visitor . visit_value :: < + u32 > ( ))); + } + __Field::__field8 => { + if __field8.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("query_start")); + } + __field8 = + Some(try!(visitor . visit_value :: < + Option < u32 > > ( ))); + } + __Field::__field9 => { + if __field9.is_some() { + return Err(<__V::Error as + _serde::de::Error>::duplicate_field("fragment_start")); + } + __field9 = + Some(try!(visitor . visit_value :: < + Option < u32 > > ( ))); + } + _ => { + let _ = + try!(visitor . visit_value :: < _serde + :: de :: impls :: IgnoredAny > ( + )); + } + } + } + try!(visitor . end ( )); + let __field0 = + match __field0 { + Some(__field0) => __field0, + None => + try!(visitor . missing_field ( "serialization" + )), + }; + let __field1 = + match __field1 { + Some(__field1) => __field1, + None => + try!(visitor . missing_field ( "scheme_end" + )), + }; + let __field2 = + match __field2 { + Some(__field2) => __field2, + None => + try!(visitor . missing_field ( "username_end" + )), + }; + let __field3 = + match __field3 { + Some(__field3) => __field3, + None => + try!(visitor . missing_field ( "host_start" + )), + }; + let __field4 = + match __field4 { + Some(__field4) => __field4, + None => + try!(visitor . missing_field ( "host_end" )), + }; + let __field5 = + match __field5 { + Some(__field5) => __field5, + None => + try!(visitor . missing_field ( "host" )), + }; + let __field6 = + match __field6 { + Some(__field6) => __field6, + None => + try!(visitor . missing_field ( "port" )), + }; + let __field7 = + match __field7 { + Some(__field7) => __field7, + None => + try!(visitor . missing_field ( "path_start" + )), + }; + let __field8 = + match __field8 { + Some(__field8) => __field8, + None => + try!(visitor . missing_field ( "query_start" + )), + }; + let __field9 = + match __field9 { + Some(__field9) => __field9, + None => + try!(visitor . missing_field ( + "fragment_start" )), + }; + Ok(Url{serialization: __field0, + scheme_end: __field1, + username_end: __field2, + host_start: __field3, + host_end: __field4, + host: __field5, + port: __field6, + path_start: __field7, + query_start: __field8, + fragment_start: __field9,}) + } + } + const FIELDS: &'static [&'static str] = + &["serialization", "scheme_end", "username_end", + "host_start", "host_end", "host", "port", "path_start", + "query_start", "fragment_start"]; + deserializer.deserialize_struct("Url", FIELDS, __Visitor) + } + } + }; +#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] +#[cfg(feature = "serde")] +const _IMPL_SERIALIZE_FOR_Url: () = + { + extern crate serde as _serde; + #[automatically_derived] + impl _serde::ser::Serialize for Url { + fn serialize<__S>(&self, _serializer: &mut __S) + -> ::std::result::Result<(), __S::Error> where + __S: _serde::ser::Serializer { + let mut __serde_state = + try!(_serializer . serialize_struct ( + "Url" , 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "serialization" , & self . + serialization )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "scheme_end" , & self . scheme_end + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "username_end" , & self . + username_end )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host_start" , & self . host_start + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host_end" , & self . host_end )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "host" , & self . host )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "port" , & self . port )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "path_start" , & self . path_start + )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "query_start" , & self . + query_start )); + try!(_serializer . serialize_struct_elt ( + & mut __serde_state , "fragment_start" , & self . + fragment_start )); + _serializer.serialize_struct_end(__serde_state) + } + } + }; +/// A parsed URL record. +#[derive(Clone)] +pub struct Url { + /// Syntax in pseudo-BNF: + /// + /// url = scheme ":" [ hierarchical | non-hierarchical ] [ "?" query ]? [ "#" fragment ]? + /// non-hierarchical = non-hierarchical-path + /// non-hierarchical-path = /* Does not start with "/" */ + /// hierarchical = authority? hierarchical-path + /// authority = "//" userinfo? host [ ":" port ]? + /// userinfo = username [ ":" password ]? "@" + /// hierarchical-path = [ "/" path-segment ]+ + serialization: String, + scheme_end: u32, + username_end: u32, + host_start: u32, + host_end: u32, + host: HostInternal, + port: Option, + path_start: u32, + query_start: Option, + fragment_start: Option, +} diff --git a/src/codegen/url.rs.in b/src/codegen/url.rs.in new file mode 100644 index 00000000..bf606eb3 --- /dev/null +++ b/src/codegen/url.rs.in @@ -0,0 +1,30 @@ +// WARNING: Do not modify this file if it is `url.rs`. +// +// Instead, modify `url.rs.in` and rerun the `serde-code-generator`. + +/// A parsed URL record. +#[derive(Clone)] +#[cfg_attr(feature="serde", derive(Serialize, Deserialize))] +pub struct Url { + /// Syntax in pseudo-BNF: + /// + /// url = scheme ":" [ hierarchical | non-hierarchical ] [ "?" query ]? [ "#" fragment ]? + /// non-hierarchical = non-hierarchical-path + /// non-hierarchical-path = /* Does not start with "/" */ + /// hierarchical = authority? hierarchical-path + /// authority = "//" userinfo? host [ ":" port ]? + /// userinfo = username [ ":" password ]? "@" + /// hierarchical-path = [ "/" path-segment ]+ + serialization: String, + + // Components + scheme_end: u32, // Before ':' + username_end: u32, // Before ':' (if a password is given) or '@' (if not) + host_start: u32, + host_end: u32, + host: HostInternal, + port: Option, + path_start: u32, // Before initial '/', if any + query_start: Option, // Before '?', unlike Position::QueryStart + fragment_start: Option, // Before '#', unlike Position::FragmentStart +} diff --git a/src/host.rs b/src/host.rs index d78ce83d..1ea5a17e 100644 --- a/src/host.rs +++ b/src/host.rs @@ -16,53 +16,11 @@ use parser::{ParseResult, ParseError}; use percent_encoding::percent_decode; use idna; -#[cfg(feature="serde")] -use serde; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum HostInternal { - None, - Domain, - Ipv4(Ipv4Addr), - Ipv6(Ipv6Addr), -} +include!("codegen/host.rs"); #[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 { - match *self { - HostInternal::None => 0u8.serialize(serializer), - HostInternal::Domain => 1u8.serialize(serializer), - HostInternal::Ipv4(addr) => { - 2u8.serialize(serializer)?; - addr.serialize(serializer) - } - HostInternal::Ipv6(addr) => { - 3u8.serialize(serializer)?; - addr.serialize(serializer) - } - } - } -} - -#[cfg(feature="serde")] -impl serde::Deserialize for HostInternal { - fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { - use serde::{Deserialize, Error}; - let discr: u8 = Deserialize::deserialize(deserializer)?; - match discr { - 0 => Ok(HostInternal::None), - 1 => Ok(HostInternal::Domain), - 2 => Ok(HostInternal::Ipv4(Deserialize::deserialize(deserializer)?)), - 3 => Ok(HostInternal::Ipv6(Deserialize::deserialize(deserializer)?)), - _ => Err(D::Error::unknown_variant("Unknown variant")), - } - } -} - impl From> for HostInternal { fn from(host: Host) -> HostInternal { match host { diff --git a/src/lib.rs b/src/lib.rs index 39ec3768..f3d3aa34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,31 +152,7 @@ pub mod form_urlencoded; pub mod percent_encoding; pub mod quirks; -/// A parsed URL record. -#[derive(Clone)] -pub struct Url { - /// Syntax in pseudo-BNF: - /// - /// url = scheme ":" [ hierarchical | non-hierarchical ] [ "?" query ]? [ "#" fragment ]? - /// non-hierarchical = non-hierarchical-path - /// non-hierarchical-path = /* Does not start with "/" */ - /// hierarchical = authority? hierarchical-path - /// authority = "//" userinfo? host [ ":" port ]? - /// userinfo = username [ ":" password ]? "@" - /// hierarchical-path = [ "/" path-segment ]+ - serialization: String, - - // Components - scheme_end: u32, // Before ':' - username_end: u32, // Before ':' (if a password is given) or '@' (if not) - host_start: u32, - host_end: u32, - host: HostInternal, - port: Option, - path_start: u32, // Before initial '/', if any - query_start: Option, // Before '?', unlike Position::QueryStart - fragment_start: Option, // Before '#', unlike Position::FragmentStart -} +include!("codegen/url.rs"); #[cfg(feature = "heapsize")] impl HeapSizeOf for Url { @@ -1510,70 +1486,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")] -#[deny(unused)] -impl serde::Serialize for Url { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { - let Url { ref serialization, ref scheme_end, - ref username_end, ref host_start, - ref host_end, ref host, ref port, - ref path_start, ref query_start, - ref fragment_start} = *self; - serialization.serialize(serializer)?; - scheme_end.serialize(serializer)?; - username_end.serialize(serializer)?; - host_start.serialize(serializer)?; - host_end.serialize(serializer)?; - host.serialize(serializer)?; - port.serialize(serializer)?; - path_start.serialize(serializer)?; - query_start.serialize(serializer)?; - fragment_start.serialize(serializer) - } -} - -/// Deserializes this URL from a `serde` stream. -/// -/// This implementation is only available if the `serde` Cargo feature is enabled. -#[cfg(feature="serde")] -#[deny(unused)] -impl serde::Deserialize for Url { - fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { - use serde::{Deserialize, Error}; - let serialization = Deserialize::deserialize(deserializer)?; - let scheme_end = Deserialize::deserialize(deserializer)?; - let username_end = Deserialize::deserialize(deserializer)?; - let host_start = Deserialize::deserialize(deserializer)?; - let host_end = Deserialize::deserialize(deserializer)?; - let host = Deserialize::deserialize(deserializer)?; - let port = Deserialize::deserialize(deserializer)?; - let path_start = Deserialize::deserialize(deserializer)?; - let query_start = Deserialize::deserialize(deserializer)?; - let fragment_start = Deserialize::deserialize(deserializer)?; - let url = Url { - serialization: serialization, - scheme_end: scheme_end, - username_end: username_end, - host_start: host_start, - host_end: host_end, - host: host, - port: port, - path_start: path_start, - query_start: query_start, - fragment_start: fragment_start - }; - #[cfg(debug_assertions)] { - if let Err(s) = url.assert_invariants_result() { - return Err(Error::invalid_value(&s)) - } - } - Ok(url) - } -} - #[cfg(any(unix, target_os = "redox"))] fn path_to_file_url_segments(path: &Path, serialization: &mut String) -> Result<(), ()> { use std::os::unix::prelude::OsStrExt;