Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add faster serde serialization, sacrificing invariant-safety for speed in release mode; test that it roudtrips #252

Closed
wants to merge 4 commits into from

Add an external serde code generator to cut down on compile time

  • Loading branch information
erickt authored and Manishearth committed Dec 17, 2016
commit 7f319577d303c5ce6f7b25c7a6691d2ce89ec261
@@ -0,0 +1,7 @@
[package]
name = "serde-code-generator"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]

[dependencies]
serde_codegen = { version = "^0.8" }
@@ -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`.
@@ -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();
}
@@ -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<HostInternal, __D::Error> 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<HostInternal, __V::Error> 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), }
@@ -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),
}
@@ -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<S>(&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<D>(deserializer: &mut D) -> Result<Self, D::Error> 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<S> From<Host<S>> for HostInternal {
fn from(host: Host<S>) -> HostInternal {
match host {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.