diff --git a/.travis.yml b/.travis.yml index 1140ebdc..87e33f84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,11 @@ sudo: false language: rust rust: +- 1.12.0 +- 1.13.0 - stable -- nightly -- 1.8.0 -- 1.9.0 - beta -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev +- nightly before_script: - pip install 'travis-cargo<0.2' --user - export PATH=$HOME/.local/bin:$PATH @@ -24,12 +18,10 @@ script: - (cd serde && travis-cargo --only nightly build -- --no-default-features --features collections) - (cd testing && travis-cargo --skip nightly test) - (cd testing && travis-cargo --only nightly test -- --features unstable-testing) -- (cd serde_macros && travis-cargo --only nightly test -- --features unstable-testing) +- (cd serde_derive && travis-cargo --only nightly test) - (cd examples/serde-syntex-example && travis-cargo --skip nightly run) - (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --no-default-features --features unstable) - (cd serde && travis-cargo --only stable doc) -after_success: -- (cd testing && travis-cargo --only stable coveralls --no-sudo) env: global: - TRAVIS_CARGO_NIGHTLY_FEATURE="" diff --git a/README.md b/README.md index 1cad02db..b46ceef3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) [![Clippy Linting Result](https://clippy.bashy.io/github/serde-rs/serde/master/badge.svg)](https://clippy.bashy.io/github/serde-rs/serde/master/log) +# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** @@ -11,12 +11,13 @@ You may be looking for: - [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html) - [Examples](https://serde.rs/examples.html) - [API documentation](https://docs.serde.rs/serde/) +- [Release notes](https://github.com/serde-rs/serde/releases) ## Serde in action ```rust -#![feature(plugin, custom_derive)] -#![plugin(serde_macros)] +#[macro_use] +extern crate serde_derive; extern crate serde_json; diff --git a/examples/serde-syntex-example/Cargo.toml b/examples/serde-syntex-example/Cargo.toml index 97de0a37..3c4527da 100644 --- a/examples/serde-syntex-example/Cargo.toml +++ b/examples/serde-syntex-example/Cargo.toml @@ -3,15 +3,16 @@ name = "serde-syntex-example" version = "0.1.0" authors = ["Erick Tryzelaar "] build = "build.rs" +publish = false [features] default = ["serde_codegen"] -unstable = ["serde_macros"] +unstable = ["serde_derive"] [build-dependencies] serde_codegen = { version = "^0.8", optional = true, path = "../../serde_codegen" } [dependencies] serde = "^0.8" +serde_derive = { version = "^0.8", optional = true, path = "../../serde_derive" } serde_json = "^0.8" -serde_macros = { version = "^0.8", optional = true, path = "../../serde_macros" } diff --git a/examples/serde-syntex-example/build.rs b/examples/serde-syntex-example/build.rs index 48728b8b..c775d665 100644 --- a/examples/serde-syntex-example/build.rs +++ b/examples/serde-syntex-example/build.rs @@ -1,4 +1,4 @@ -#[cfg(not(feature = "serde_macros"))] +#[cfg(not(feature = "serde_derive"))] mod inner { extern crate serde_codegen; @@ -15,7 +15,7 @@ mod inner { } } -#[cfg(feature = "serde_macros")] +#[cfg(feature = "serde_derive")] mod inner { pub fn main() {} } diff --git a/examples/serde-syntex-example/src/main.rs b/examples/serde-syntex-example/src/main.rs index 0a8804ab..1d6e2058 100644 --- a/examples/serde-syntex-example/src/main.rs +++ b/examples/serde-syntex-example/src/main.rs @@ -1,11 +1,14 @@ -#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))] -#![cfg_attr(feature = "serde_macros", plugin(serde_macros))] +#![cfg_attr(feature = "serde_derive", feature(proc_macro))] + +#[cfg(feature = "serde_derive")] +#[macro_use] +extern crate serde_derive; extern crate serde; extern crate serde_json; -#[cfg(feature = "serde_macros")] +#[cfg(feature = "serde_derive")] include!("main.rs.in"); -#[cfg(not(feature = "serde_macros"))] +#[cfg(not(feature = "serde_derive"))] include!(concat!(env!("OUT_DIR"), "/main.rs")); diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 59ffaf2a..4225585e 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde" -version = "0.8.4" +version = "0.8.21" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" @@ -11,6 +11,8 @@ readme = "../README.md" keywords = ["serde", "serialization"] include = ["Cargo.toml", "src/**/*.rs"] +publish = false # this branch contains breaking changes for 0.9 + [features] default = ["std"] diff --git a/serde/src/bytes.rs b/serde/src/bytes.rs index 67f8ce85..988c24a5 100644 --- a/serde/src/bytes.rs +++ b/serde/src/bytes.rs @@ -19,6 +19,15 @@ pub struct Bytes<'a> { bytes: &'a [u8], } +impl<'a> Bytes<'a> { + /// Wrap an existing `&[u8]`. + pub fn new(bytes: &'a [u8]) -> Self { + Bytes { + bytes: bytes, + } + } +} + impl<'a> fmt::Debug for Bytes<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(f.write_str("b\"")); @@ -31,18 +40,14 @@ impl<'a> fmt::Debug for Bytes<'a> { impl<'a> From<&'a [u8]> for Bytes<'a> { fn from(bytes: &'a [u8]) -> Self { - Bytes { - bytes: bytes, - } + Bytes::new(bytes) } } #[cfg(any(feature = "std", feature = "collections"))] impl<'a> From<&'a Vec> for Bytes<'a> { fn from(bytes: &'a Vec) -> Self { - Bytes { - bytes: bytes, - } + Bytes::new(bytes) } } @@ -79,7 +84,7 @@ mod bytebuf { use de; #[cfg(feature = "collections")] - use collections::Vec; + use collections::{String, Vec}; /// `ByteBuf` wraps a `Vec` and serializes as a byte array. #[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -90,15 +95,18 @@ mod bytebuf { impl ByteBuf { /// Construct a new, empty `ByteBuf`. pub fn new() -> Self { - ByteBuf { - bytes: Vec::new(), - } + ByteBuf::from(Vec::new()) } /// Construct a new, empty `ByteBuf` with the specified capacity. pub fn with_capacity(cap: usize) -> Self { + ByteBuf::from(Vec::with_capacity(cap)) + } + + /// Wrap existing bytes in a `ByteBuf`. + pub fn from>>(bytes: T) -> Self { ByteBuf { - bytes: Vec::with_capacity(cap) + bytes: bytes.into(), } } } @@ -121,9 +129,7 @@ mod bytebuf { impl From> for ByteBuf { fn from(bytes: Vec) -> Self { - ByteBuf { - bytes: bytes, - } + ByteBuf::from(bytes) } } @@ -179,9 +185,7 @@ mod bytebuf { fn visit_unit(&mut self) -> Result where E: de::Error, { - Ok(ByteBuf { - bytes: Vec::new(), - }) + Ok(ByteBuf::new()) } #[inline] @@ -197,25 +201,33 @@ mod bytebuf { try!(visitor.end()); - Ok(ByteBuf { - bytes: values, - }) + Ok(ByteBuf::from(values)) } #[inline] fn visit_bytes(&mut self, v: &[u8]) -> Result where E: de::Error, { - self.visit_byte_buf(v.to_vec()) + Ok(ByteBuf::from(v)) } #[inline] fn visit_byte_buf(&mut self, v: Vec) -> Result where E: de::Error, { - Ok(ByteBuf { - bytes: v, - }) + Ok(ByteBuf::from(v)) + } + + fn visit_str(&mut self, v: &str) -> Result + where E: de::Error, + { + Ok(ByteBuf::from(v)) + } + + fn visit_string(&mut self, v: String) -> Result + where E: de::Error, + { + Ok(ByteBuf::from(v)) } } diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index 6289e921..b6c67451 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -282,6 +282,12 @@ impl Visitor for StringVisitor { Ok(v) } + fn visit_unit(&mut self) -> Result + where E: Error, + { + Ok(String::new()) + } + fn visit_bytes(&mut self, v: &[u8]) -> Result where E: Error, { @@ -511,27 +517,26 @@ seq_impl!( /////////////////////////////////////////////////////////////////////////////// -struct ArrayVisitor0 { - marker: PhantomData, +struct ArrayVisitor { + marker: PhantomData, } -impl ArrayVisitor0 { - /// Construct a `ArrayVisitor0`. +impl ArrayVisitor { pub fn new() -> Self { - ArrayVisitor0 { + ArrayVisitor { marker: PhantomData, } } } -impl Visitor for ArrayVisitor0 where T: Deserialize + Default { +impl Visitor for ArrayVisitor<[T; 0]> where T: Deserialize { type Value = [T; 0]; #[inline] fn visit_unit(&mut self) -> Result<[T; 0], E> where E: Error, { - Ok([T::default(); 0]) + Ok([]) } #[inline] @@ -539,37 +544,24 @@ impl Visitor for ArrayVisitor0 where T: Deserialize + Default { where V: SeqVisitor, { try!(visitor.end()); - Ok([T::default(); 0]) + Ok([]) } } impl Deserialize for [T; 0] - where T: Deserialize + Default + where T: Deserialize { fn deserialize(deserializer: &mut D) -> Result<[T; 0], D::Error> where D: Deserializer, { - deserializer.deserialize_seq(ArrayVisitor0::new()) + deserializer.deserialize_seq_fixed_size(0, ArrayVisitor::<[T; 0]>::new()) } } macro_rules! array_impls { - ($($visitor:ident, $len:expr => ($($name:ident),+),)+) => { + ($($len:expr => ($($name:ident)+))+) => { $( - struct $visitor { - marker: PhantomData, - } - - impl $visitor { - /// Construct a `ArrayVisitor*`. - pub fn new() -> Self { - $visitor { - marker: PhantomData - } - } - } - - impl Visitor for $visitor where T: Deserialize { + impl Visitor for ArrayVisitor<[T; $len]> where T: Deserialize { type Value = [T; $len]; #[inline] @@ -579,13 +571,13 @@ macro_rules! array_impls { $( let $name = match try!(visitor.visit()) { Some(val) => val, - None => { return Err(Error::end_of_stream()); } + None => return Err(Error::end_of_stream()), }; - )+; + )+ try!(visitor.end()); - Ok([$($name,)+]) + Ok([$($name),+]) } } @@ -595,7 +587,7 @@ macro_rules! array_impls { fn deserialize(deserializer: &mut D) -> Result<[T; $len], D::Error> where D: Deserializer, { - deserializer.deserialize_seq_fixed_size($len, $visitor::new()) + deserializer.deserialize_seq_fixed_size($len, ArrayVisitor::<[T; $len]>::new()) } } )+ @@ -603,71 +595,58 @@ macro_rules! array_impls { } array_impls! { - ArrayVisitor1, 1 => (a), - ArrayVisitor2, 2 => (a, b), - ArrayVisitor3, 3 => (a, b, c), - ArrayVisitor4, 4 => (a, b, c, d), - ArrayVisitor5, 5 => (a, b, c, d, e), - ArrayVisitor6, 6 => (a, b, c, d, e, f), - ArrayVisitor7, 7 => (a, b, c, d, e, f, g), - ArrayVisitor8, 8 => (a, b, c, d, e, f, g, h), - ArrayVisitor9, 9 => (a, b, c, d, e, f, g, h, i), - ArrayVisitor10, 10 => (a, b, c, d, e, f, g, h, i, j), - ArrayVisitor11, 11 => (a, b, c, d, e, f, g, h, i, j, k), - ArrayVisitor12, 12 => (a, b, c, d, e, f, g, h, i, j, k, l), - ArrayVisitor13, 13 => (a, b, c, d, e, f, g, h, i, j, k, l, m), - ArrayVisitor14, 14 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n), - ArrayVisitor15, 15 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o), - ArrayVisitor16, 16 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p), - ArrayVisitor17, 17 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q), - ArrayVisitor18, 18 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r), - ArrayVisitor19, 19 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s), - ArrayVisitor20, 20 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s ,t), - ArrayVisitor21, 21 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u), - ArrayVisitor22, 22 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v), - ArrayVisitor23, 23 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w), - ArrayVisitor24, 24 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x), - ArrayVisitor25, 25 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y), - ArrayVisitor26, 26 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z), - ArrayVisitor27, 27 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa), - ArrayVisitor28, 28 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa, ab), - ArrayVisitor29, 29 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa, ab, ac), - ArrayVisitor30, 30 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa, ab, ac, ad), - ArrayVisitor31, 31 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa, ab, ac, ad, ae), - ArrayVisitor32, 32 => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, - y, z, aa, ab, ac, ad, ae, af), + 1 => (a) + 2 => (a b) + 3 => (a b c) + 4 => (a b c d) + 5 => (a b c d e) + 6 => (a b c d e f) + 7 => (a b c d e f g) + 8 => (a b c d e f g h) + 9 => (a b c d e f g h i) + 10 => (a b c d e f g h i j) + 11 => (a b c d e f g h i j k) + 12 => (a b c d e f g h i j k l) + 13 => (a b c d e f g h i j k l m) + 14 => (a b c d e f g h i j k l m n) + 15 => (a b c d e f g h i j k l m n o) + 16 => (a b c d e f g h i j k l m n o p) + 17 => (a b c d e f g h i j k l m n o p q) + 18 => (a b c d e f g h i j k l m n o p q r) + 19 => (a b c d e f g h i j k l m n o p q r s) + 20 => (a b c d e f g h i j k l m n o p q r s t) + 21 => (a b c d e f g h i j k l m n o p q r s t u) + 22 => (a b c d e f g h i j k l m n o p q r s t u v) + 23 => (a b c d e f g h i j k l m n o p q r s t u v w) + 24 => (a b c d e f g h i j k l m n o p q r s t u v w x) + 25 => (a b c d e f g h i j k l m n o p q r s t u v w x y) + 26 => (a b c d e f g h i j k l m n o p q r s t u v w x y z) + 27 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa) + 28 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab) + 29 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac) + 30 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad) + 31 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae) + 32 => (a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af) } /////////////////////////////////////////////////////////////////////////////// macro_rules! tuple_impls { - ($($len:expr => $visitor:ident => ($($name:ident),+),)+) => { + ($($len:expr => $visitor:ident => ($($name:ident)+))+) => { $( /// Construct a tuple visitor. pub struct $visitor<$($name,)+> { marker: PhantomData<($($name,)+)>, } - impl< - $($name: Deserialize,)+ - > $visitor<$($name,)+> { + impl<$($name: Deserialize,)+> $visitor<$($name,)+> { /// Construct a `TupleVisitor*`. pub fn new() -> Self { $visitor { marker: PhantomData } } } - - impl< - $($name: Deserialize,)+ - > Visitor for $visitor<$($name,)+> { + impl<$($name: Deserialize),+> Visitor for $visitor<$($name,)+> { type Value = ($($name,)+); #[inline] @@ -678,9 +657,9 @@ macro_rules! tuple_impls { $( let $name = match try!(visitor.visit()) { Some(value) => value, - None => { return Err(Error::end_of_stream()); } + None => return Err(Error::end_of_stream()), }; - )+; + )+ try!(visitor.end()); @@ -688,9 +667,7 @@ macro_rules! tuple_impls { } } - impl< - $($name: Deserialize),+ - > Deserialize for ($($name,)+) { + impl<$($name: Deserialize),+> Deserialize for ($($name,)+) { #[inline] fn deserialize(deserializer: &mut D) -> Result<($($name,)+), D::Error> where D: Deserializer, @@ -703,22 +680,22 @@ macro_rules! tuple_impls { } tuple_impls! { - 1 => TupleVisitor1 => (T0), - 2 => TupleVisitor2 => (T0, T1), - 3 => TupleVisitor3 => (T0, T1, T2), - 4 => TupleVisitor4 => (T0, T1, T2, T3), - 5 => TupleVisitor5 => (T0, T1, T2, T3, T4), - 6 => TupleVisitor6 => (T0, T1, T2, T3, T4, T5), - 7 => TupleVisitor7 => (T0, T1, T2, T3, T4, T5, T6), - 8 => TupleVisitor8 => (T0, T1, T2, T3, T4, T5, T6, T7), - 9 => TupleVisitor9 => (T0, T1, T2, T3, T4, T5, T6, T7, T8), - 10 => TupleVisitor10 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), - 11 => TupleVisitor11 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), - 12 => TupleVisitor12 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), - 13 => TupleVisitor13 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), - 14 => TupleVisitor14 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), - 15 => TupleVisitor15 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), - 16 => TupleVisitor16 => (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), + 1 => TupleVisitor1 => (T0) + 2 => TupleVisitor2 => (T0 T1) + 3 => TupleVisitor3 => (T0 T1 T2) + 4 => TupleVisitor4 => (T0 T1 T2 T3) + 5 => TupleVisitor5 => (T0 T1 T2 T3 T4) + 6 => TupleVisitor6 => (T0 T1 T2 T3 T4 T5) + 7 => TupleVisitor7 => (T0 T1 T2 T3 T4 T5 T6) + 8 => TupleVisitor8 => (T0 T1 T2 T3 T4 T5 T6 T7) + 9 => TupleVisitor9 => (T0 T1 T2 T3 T4 T5 T6 T7 T8) + 10 => TupleVisitor10 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9) + 11 => TupleVisitor11 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10) + 12 => TupleVisitor12 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11) + 13 => TupleVisitor13 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12) + 14 => TupleVisitor14 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13) + 15 => TupleVisitor15 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14) + 16 => TupleVisitor16 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15) } /////////////////////////////////////////////////////////////////////////////// @@ -808,7 +785,7 @@ map_impl!( /////////////////////////////////////////////////////////////////////////////// -#[cfg(all(feature = "unstable", feature = "std"))] +#[cfg(feature = "std")] impl Deserialize for net::IpAddr { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer, diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 5241d372..e356bc94 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -11,71 +11,6 @@ use collections::{String, Vec}; use core::fmt; /////////////////////////////////////////////////////////////////////////////// -/// Macro helper to not have to re-implement all the defaulted methods. -/// Every given method ignores all arguments and forwards to `deserialize`. -/// Note that `deserialize_enum` simply returns an `Error::invalid_type`. -macro_rules! de_forward_to_deserialize { - ($($func:ident),*) => { - $(de_forward_to_deserialize!{func: $func})* - }; - (func: deserialize_unit_struct) => { - de_forward_to_deserialize!{named: deserialize_unit_struct} - }; - (func: deserialize_newtype_struct) => { - de_forward_to_deserialize!{named: deserialize_newtype_struct} - }; - (func: deserialize_tuple) => { - de_forward_to_deserialize!{tup_fn: deserialize_tuple} - }; - (func: deserialize_seq_fixed_size) => { - de_forward_to_deserialize!{tup_fn: deserialize_seq_fixed_size} - }; - (func: deserialize_tuple_struct) => { - #[inline] - fn deserialize_tuple_struct<__V>(&mut self, _: &str, _: usize, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; - (func: deserialize_struct) => { - #[inline] - fn deserialize_struct<__V>(&mut self, _: &str, _: &[&str], visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; - (func: deserialize_enum) => { - #[inline] - fn deserialize_enum<__V>(&mut self, _: &str, _: &[&str], visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; - (named: $func:ident) => { - #[inline] - fn $func<__V>(&mut self, _: &str, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; - (tup_fn: $func: ident) => { - #[inline] - fn $func<__V>(&mut self, _: usize, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; - (func: $func:ident) => { - #[inline] - fn $func<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: $crate::de::Visitor { - self.deserialize(visitor) - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// modules come after macros pub mod impls; pub mod value; diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index b51de8f7..def6814e 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -178,20 +178,10 @@ impl de::Deserializer for UnitDeserializer { type Error = E; - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } fn deserialize(&mut self, mut visitor: V) -> Result @@ -229,21 +219,11 @@ macro_rules! primitive_deserializer { { type Error = E; - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str + string unit option seq seq_fixed_size bytes map unit_struct + newtype_struct tuple_struct struct struct_field tuple enum + ignored_any } fn deserialize(&mut self, mut visitor: V) -> Result @@ -311,20 +291,10 @@ impl<'a, E> de::Deserializer for StrDeserializer<'a, E> visitor.visit_enum(self) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple ignored_any } } @@ -407,20 +377,10 @@ impl de::Deserializer for StringDeserializer visitor.visit_enum(self) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple ignored_any } } @@ -505,20 +465,10 @@ impl<'a, E> de::Deserializer for CowStrDeserializer<'a, E> visitor.visit_enum(self) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple ignored_any } } @@ -596,21 +546,10 @@ impl de::Deserializer for SeqDeserializer visitor.visit_seq(self) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } } @@ -719,21 +658,10 @@ impl de::Deserializer for SeqVisitorDeserializer visitor.visit_seq(&mut self.visitor) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } } @@ -778,6 +706,15 @@ impl MapDeserializer marker: PhantomData, } } + + fn next(&mut self) -> Option<(K, V)> { + self.iter.next().map(|(k, v)| { + if let Some(len) = self.len.as_mut() { + *len -= 1; + } + (k, v) + }) + } } impl de::Deserializer for MapDeserializer @@ -794,21 +731,26 @@ impl de::Deserializer for MapDeserializer visitor.visit_map(self) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + fn deserialize_seq(&mut self, mut visitor: V_) -> Result + where V_: de::Visitor, + { + visitor.visit_seq(self) + } + + fn deserialize_seq_fixed_size(&mut self, len: usize, mut visitor: V_) -> Result + where V_: de::Visitor, + { + match self.len { + Some(map_len) if map_len == len => visitor.visit_seq(self), + Some(_) => Err(de::Error::invalid_length(len)), + None => visitor.visit_seq(self), + } + } + + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option bytes map unit_struct newtype_struct tuple_struct struct + struct_field tuple enum ignored_any } } @@ -823,14 +765,11 @@ impl de::MapVisitor for MapDeserializer fn visit_key(&mut self) -> Result, Self::Error> where T: de::Deserialize, { - match self.iter.next() { + match self.next() { Some((key, value)) => { - if let Some(len) = self.len.as_mut() { - *len -= 1; - } self.value = Some(value); let mut de = key.into_deserializer(); - Ok(Some(try!(de::Deserialize::deserialize(&mut de)))) + de::Deserialize::deserialize(&mut de).map(Some) } None => Ok(None), } @@ -864,6 +803,123 @@ impl de::MapVisitor for MapDeserializer } } +impl de::SeqVisitor for MapDeserializer + where I: Iterator, + K: ValueDeserializer, + V: ValueDeserializer, + E: de::Error, +{ + type Error = E; + + fn visit(&mut self) -> Result, Self::Error> + where T: de::Deserialize, + { + match self.next() { + Some(kv) => { + let mut de = PairDeserializer(Some(kv), PhantomData); + de::Deserialize::deserialize(&mut de).map(Some) + } + None => Ok(None), + } + } + + fn end(&mut self) -> Result<(), Self::Error> { + de::MapVisitor::end(self) + } + + fn size_hint(&self) -> (usize, Option) { + de::MapVisitor::size_hint(self) + } +} + +// Used in the `impl SeqVisitor for MapDeserializer` to visit the map as a +// sequence of pairs. +struct PairDeserializer(Option<(A, B)>, PhantomData); + +impl de::Deserializer for PairDeserializer + where A: ValueDeserializer, + B: ValueDeserializer, + E: de::Error +{ + type Error = E; + + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option bytes map unit_struct newtype_struct tuple_struct struct + struct_field tuple enum ignored_any + } + + fn deserialize(&mut self, visitor: V) -> Result + where V: de::Visitor, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + match self.0.take() { + Some((k, v)) => { + visitor.visit_seq(PairVisitor(Some(k), Some(v), PhantomData)) + } + None => Err(de::Error::end_of_stream()), + } + } + + fn deserialize_seq_fixed_size(&mut self, len: usize, visitor: V) -> Result + where V: de::Visitor, + { + if len == 2 { + self.deserialize_seq(visitor) + } else { + Err(de::Error::invalid_length(len)) + } + } +} + +struct PairVisitor(Option, Option, PhantomData); + +impl de::SeqVisitor for PairVisitor + where A: ValueDeserializer, + B: ValueDeserializer, + E: de::Error, +{ + type Error = E; + + fn visit(&mut self) -> Result, Self::Error> + where T: de::Deserialize, + { + if let Some(k) = self.0.take() { + let mut de = k.into_deserializer(); + de::Deserialize::deserialize(&mut de).map(Some) + } else if let Some(v) = self.1.take() { + let mut de = v.into_deserializer(); + de::Deserialize::deserialize(&mut de).map(Some) + } else { + Ok(None) + } + } + + fn end(&mut self) -> Result<(), Self::Error> { + if self.1.is_none() { + Ok(()) + } else { + Err(de::Error::invalid_length(self.size_hint().0)) + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = if self.0.is_some() { + 2 + } else if self.1.is_some() { + 1 + } else { + 0 + }; + (len, Some(len)) + } +} + /////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "collections"))] @@ -925,21 +981,10 @@ impl de::Deserializer for MapVisitorDeserializer visitor.visit_map(&mut self.visitor) } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } } @@ -972,25 +1017,13 @@ impl<'a, E> de::Deserializer for BytesDeserializer<'a, E> } } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } } - /////////////////////////////////////////////////////////////////////////////// #[cfg(any(feature = "std", feature = "collections"))] @@ -1023,20 +1056,9 @@ impl de::Deserializer for ByteBufDeserializer } } - de_forward_to_deserialize!{ - deserialize_bool, - deserialize_f64, deserialize_f32, - deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_usize, - deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_isize, - deserialize_char, deserialize_str, deserialize_string, - deserialize_ignored_any, - deserialize_bytes, - deserialize_unit_struct, deserialize_unit, - deserialize_seq, deserialize_seq_fixed_size, - deserialize_map, deserialize_newtype_struct, deserialize_struct_field, - deserialize_tuple, - deserialize_enum, - deserialize_struct, deserialize_tuple_struct, - deserialize_option + forward_to_deserialize! { + bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string + unit option seq seq_fixed_size bytes map unit_struct newtype_struct + tuple_struct struct struct_field tuple enum ignored_any } } diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 54dcc120..78a0531e 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -45,6 +45,9 @@ macro_rules! format { ($s:expr, $($rest:tt)*) => ($s) } +#[macro_use] +mod macros; + pub mod bytes; pub mod de; #[cfg(feature = "std")] diff --git a/serde/src/macros.rs b/serde/src/macros.rs new file mode 100644 index 00000000..d8673ca4 --- /dev/null +++ b/serde/src/macros.rs @@ -0,0 +1,151 @@ +#[cfg(feature = "std")] +#[doc(hidden)] +#[macro_export] +macro_rules! forward_to_deserialize_method { + ($func:ident($($arg:ty),*)) => { + #[inline] + fn $func<__V>(&mut self, $(_: $arg,)* visitor: __V) -> ::std::result::Result<__V::Value, Self::Error> + where __V: $crate::de::Visitor + { + self.deserialize(visitor) + } + }; +} + +#[cfg(not(feature = "std"))] +#[doc(hidden)] +#[macro_export] +macro_rules! forward_to_deserialize_method { + ($func:ident($($arg:ty),*)) => { + #[inline] + fn $func<__V>(&mut self, $(_: $arg,)* visitor: __V) -> ::core::result::Result<__V::Value, Self::Error> + where __V: $crate::de::Visitor + { + self.deserialize(visitor) + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! forward_to_deserialize_helper { + (bool) => { + forward_to_deserialize_method!{deserialize_bool()} + }; + (usize) => { + forward_to_deserialize_method!{deserialize_usize()} + }; + (u8) => { + forward_to_deserialize_method!{deserialize_u8()} + }; + (u16) => { + forward_to_deserialize_method!{deserialize_u16()} + }; + (u32) => { + forward_to_deserialize_method!{deserialize_u32()} + }; + (u64) => { + forward_to_deserialize_method!{deserialize_u64()} + }; + (isize) => { + forward_to_deserialize_method!{deserialize_isize()} + }; + (i8) => { + forward_to_deserialize_method!{deserialize_i8()} + }; + (i16) => { + forward_to_deserialize_method!{deserialize_i16()} + }; + (i32) => { + forward_to_deserialize_method!{deserialize_i32()} + }; + (i64) => { + forward_to_deserialize_method!{deserialize_i64()} + }; + (f32) => { + forward_to_deserialize_method!{deserialize_f32()} + }; + (f64) => { + forward_to_deserialize_method!{deserialize_f64()} + }; + (char) => { + forward_to_deserialize_method!{deserialize_char()} + }; + (str) => { + forward_to_deserialize_method!{deserialize_str()} + }; + (string) => { + forward_to_deserialize_method!{deserialize_string()} + }; + (unit) => { + forward_to_deserialize_method!{deserialize_unit()} + }; + (option) => { + forward_to_deserialize_method!{deserialize_option()} + }; + (seq) => { + forward_to_deserialize_method!{deserialize_seq()} + }; + (seq_fixed_size) => { + forward_to_deserialize_method!{deserialize_seq_fixed_size(usize)} + }; + (bytes) => { + forward_to_deserialize_method!{deserialize_bytes()} + }; + (map) => { + forward_to_deserialize_method!{deserialize_map()} + }; + (unit_struct) => { + forward_to_deserialize_method!{deserialize_unit_struct(&'static str)} + }; + (newtype_struct) => { + forward_to_deserialize_method!{deserialize_newtype_struct(&'static str)} + }; + (tuple_struct) => { + forward_to_deserialize_method!{deserialize_tuple_struct(&'static str, usize)} + }; + (struct) => { + forward_to_deserialize_method!{deserialize_struct(&'static str, &'static [&'static str])} + }; + (struct_field) => { + forward_to_deserialize_method!{deserialize_struct_field()} + }; + (tuple) => { + forward_to_deserialize_method!{deserialize_tuple(usize)} + }; + (enum) => { + forward_to_deserialize_method!{deserialize_enum(&'static str, &'static [&'static str])} + }; + (ignored_any) => { + forward_to_deserialize_method!{deserialize_ignored_any()} + }; +} + +/// Helper to forward `Deserializer` methods to `Deserializer::deserialize`. +/// Every given method ignores all arguments and forwards to `deserialize`. +/// Note that `deserialize_enum` simply returns an `Error::invalid_type`; a +/// better approach is tracked in [serde-rs/serde#521][1]. +/// +/// ```rust,ignore +/// impl Deserializer for MyDeserializer { +/// fn deserialize(&mut self, visitor: V) -> Result +/// where V: Visitor +/// { +/// /* ... */ +/// } +/// +/// forward_to_deserialize! { +/// bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 char str string +/// unit option seq seq_fixed_size bytes map unit_struct newtype_struct +/// tuple_struct struct struct_field tuple enum ignored_any +/// } +/// } +/// ``` +/// +/// [1]: https://github.com/serde-rs/serde/issues/521 +#[macro_export] +macro_rules! forward_to_deserialize { + ($($func:ident)*) => { + $(forward_to_deserialize_helper!{$func})* + }; +} diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 348c8c77..5653a717 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -313,11 +313,6 @@ impl Serialize for () { /////////////////////////////////////////////////////////////////////////////// -// FIXME(rust #19630) Remove this work-around -macro_rules! e { - ($e:expr) => { $e } -} - macro_rules! tuple_impls { ($( $TupleVisitor:ident ($len:expr, $($T:ident),+) { @@ -334,7 +329,7 @@ macro_rules! tuple_impls { { let mut state = try!(serializer.serialize_tuple($len)); $( - try!(serializer.serialize_tuple_elt(&mut state, &e!(self.$idx))); + try!(serializer.serialize_tuple_elt(&mut state, &self.$idx)); )+ serializer.serialize_tuple_end(state) } @@ -640,15 +635,12 @@ impl Serialize for Duration { /////////////////////////////////////////////////////////////////////////////// -#[cfg(all(feature = "std", feature = "unstable"))] +#[cfg(feature = "std")] impl Serialize for net::IpAddr { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer, { - match *self { - net::IpAddr::V4(ref addr) => addr.serialize(serializer), - net::IpAddr::V6(ref addr) => addr.serialize(serializer), - } + self.to_string().serialize(serializer) } } diff --git a/serde_codegen/Cargo.toml b/serde_codegen/Cargo.toml index 36f705a5..39261519 100644 --- a/serde_codegen/Cargo.toml +++ b/serde_codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_codegen" -version = "0.8.4" +version = "0.8.21" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" @@ -8,31 +8,24 @@ homepage = "https://serde.rs" repository = "https://github.com/serde-rs/serde" documentation = "https://serde.rs/codegen.html" keywords = ["serde", "serialization"] -build = "build.rs" -include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/lib.rs.in"] +include = ["Cargo.toml", "src/**/*.rs"] + +publish = false # this branch contains breaking changes for 0.9 [features] default = ["with-syntex"] -unstable = ["quasi_macros"] +unstable = [] unstable-testing = ["clippy"] with-syntex = [ - "quasi/with-syntex", - "quasi_codegen", - "quasi_codegen/with-syntex", - "serde_codegen_internals/with-syntex", "syntex", "syntex_syntax", ] - -[build-dependencies] -quasi_codegen = { version = "^0.18.0", optional = true } -syntex = { version = "^0.42.2", optional = true } +with-syn = [] [dependencies] -aster = { version = "^0.25.0", default-features = false } clippy = { version = "^0.*", optional = true } -quasi = { version = "^0.18.0", default-features = false } -quasi_macros = { version = "^0.18.0", optional = true } -serde_codegen_internals = { version = "=0.7.0", default-features = false, path = "../serde_codegen_internals" } -syntex = { version = "^0.42.2", optional = true } -syntex_syntax = { version = "^0.42.0", optional = true } +quote = "0.3.8" +serde_codegen_internals = { version = "=0.11.3", default-features = false, path = "../serde_codegen_internals" } +syn = { version = "0.10", features = ["aster", "visit"] } +syntex = { version = "^0.54.0", optional = true } +syntex_syntax = { version = "^0.54.0", optional = true } diff --git a/serde_codegen/build.rs b/serde_codegen/build.rs deleted file mode 100644 index 9ff828f2..00000000 --- a/serde_codegen/build.rs +++ /dev/null @@ -1,28 +0,0 @@ -#[cfg(feature = "with-syntex")] -mod inner { - extern crate quasi_codegen; - - use std::env; - use std::path::Path; - use std::thread::spawn; - - pub fn main() { - // put everything into a thread, so users can use `RUST_MIN_STACK` to increase the amount of stack - spawn(|| { - let out_dir = env::var_os("OUT_DIR").unwrap(); - - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - quasi_codegen::expand(&src, &dst).unwrap(); - }).join().unwrap() - } -} - -#[cfg(not(feature = "with-syntex"))] -mod inner { - pub fn main() {} -} - -fn main() { - inner::main(); -} diff --git a/serde_codegen/src/bound.rs b/serde_codegen/src/bound.rs index 7bd5ddc6..fef77ba3 100644 --- a/serde_codegen/src/bound.rs +++ b/serde_codegen/src/bound.rs @@ -1,9 +1,6 @@ use std::collections::HashSet; -use aster::AstBuilder; - -use syntax::ast; -use syntax::visit; +use syn::{self, aster, visit}; use internals::ast::Item; use internals::attr; @@ -11,10 +8,10 @@ use internals::attr; // Remove the default from every type parameter because in the generated impls // they look like associated types: "error: associated type bindings are not // allowed here". -pub fn without_defaults(generics: &ast::Generics) -> ast::Generics { - ast::Generics { +pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { + syn::Generics { ty_params: generics.ty_params.iter().map(|ty_param| { - ast::TyParam { + syn::TyParam { default: None, .. ty_param.clone() }}).collect(), @@ -23,24 +20,22 @@ pub fn without_defaults(generics: &ast::Generics) -> ast::Generics { } pub fn with_where_predicates( - builder: &AstBuilder, - generics: &ast::Generics, - predicates: &[ast::WherePredicate], -) -> ast::Generics { - builder.from_generics(generics.clone()) + generics: &syn::Generics, + predicates: &[syn::WherePredicate], +) -> syn::Generics { + aster::from_generics(generics.clone()) .with_predicates(predicates.to_vec()) .build() } pub fn with_where_predicates_from_fields( - builder: &AstBuilder, item: &Item, - generics: &ast::Generics, + generics: &syn::Generics, from_field: F, -) -> ast::Generics - where F: Fn(&attr::Field) -> Option<&[ast::WherePredicate]>, +) -> syn::Generics + where F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>, { - builder.from_generics(generics.clone()) + aster::from_generics(generics.clone()) .with_predicates( item.body.all_fields() .flat_map(|field| from_field(&field.attrs)) @@ -60,34 +55,33 @@ pub fn with_where_predicates_from_fields( // c: C, // } pub fn with_bound( - builder: &AstBuilder, item: &Item, - generics: &ast::Generics, + generics: &syn::Generics, filter: F, - bound: &ast::Path, -) -> ast::Generics + bound: &syn::Path, +) -> syn::Generics where F: Fn(&attr::Field) -> bool, { struct FindTyParams { // Set of all generic type parameters on the current struct (A, B, C in // the example). Initialized up front. - all_ty_params: HashSet, + all_ty_params: HashSet, // Set of generic type parameters used in fields for which filter // returns true (A and B in the example). Filled in as the visitor sees // them. - relevant_ty_params: HashSet, + relevant_ty_params: HashSet, } impl visit::Visitor for FindTyParams { - fn visit_path(&mut self, path: &ast::Path, _id: ast::NodeId) { + fn visit_path(&mut self, path: &syn::Path) { if let Some(seg) = path.segments.last() { - if seg.identifier.name.as_str() == "PhantomData" { + if seg.ident == "PhantomData" { // Hardcoded exception, because PhantomData implements // Serialize and Deserialize whether or not T implements it. return; } } if !path.global && path.segments.len() == 1 { - let id = path.segments[0].identifier.name; + let id = path.segments[0].ident.clone(); if self.all_ty_params.contains(&id) { self.relevant_ty_params.insert(id); } @@ -97,7 +91,7 @@ pub fn with_bound( } let all_ty_params: HashSet<_> = generics.ty_params.iter() - .map(|ty_param| ty_param.ident.name) + .map(|ty_param| ty_param.ident.clone()) .collect(); let relevant_tys = item.body.all_fields() @@ -112,14 +106,14 @@ pub fn with_bound( visit::walk_ty(&mut visitor, ty); } - builder.from_generics(generics.clone()) + aster::from_generics(generics.clone()) .with_predicates( generics.ty_params.iter() - .map(|ty_param| ty_param.ident.name) + .map(|ty_param| ty_param.ident.clone()) .filter(|id| visitor.relevant_ty_params.contains(id)) - .map(|id| builder.where_predicate() + .map(|id| aster::where_predicate() // the type parameter that is being bounded e.g. T - .bound().build(builder.ty().id(id)) + .bound().build(aster::ty().id(id)) // the bound e.g. Serialize .bound().trait_(bound.clone()).build() .build())) diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 336d2f56..6088aa0d 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -1,113 +1,70 @@ -use aster; - -use syntax::ast::{self, Ident, MetaItem}; -use syntax::codemap::Span; -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::parse::token::InternedString; -use syntax::ptr::P; -use syntax::tokenstream::TokenTree; +use syn::{self, aster}; +use quote::{self, Tokens}; use bound; -use span; use internals::ast::{Body, Field, Item, Style, Variant}; -use internals::{attr, Error}; +use internals::{self, attr}; -pub fn expand_derive_deserialize( - cx: &mut ExtCtxt, - span: Span, - meta_item: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable) -) { - let item = match *annotatable { - Annotatable::Item(ref item) => item, - _ => { - cx.span_err( - meta_item.span, - "`#[derive(Deserialize)]` may only be applied to structs and enums"); - return; - } +use std::iter; + +pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Result { + let item = { + let ctxt = internals::Ctxt::new(); + let item = Item::from_ast(&ctxt, item); + check_no_str(&ctxt, &item); + try!(ctxt.check()); + item }; - let item = match Item::from_ast(cx, item) { - Ok(item) => item, - Err(Error::UnexpectedItemKind) => { - cx.span_err(item.span, - "`#[derive(Deserialize)]` may only be applied to structs and enums"); - return; - } - }; + let impl_generics = build_impl_generics(&item); - if check_no_str(cx, &item).is_err() { - return; - } - - let builder = aster::AstBuilder::new().span(span); - - let impl_item = deserialize_item(cx, &builder, &item); - push(span::record_expansion(cx, impl_item, "Deserialize")) -} - -fn deserialize_item( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - item: &Item, -) -> P { - let impl_generics = build_impl_generics(builder, &item); - - let ty = builder.ty().path() - .segment(item.ident).with_generics(impl_generics.clone()).build() + let ty = aster::ty().path() + .segment(item.ident.clone()).with_generics(impl_generics.clone()).build() .build(); - let body = deserialize_body(cx, - builder, - &item, + let body = deserialize_body(&item, &impl_generics, ty.clone()); let where_clause = &impl_generics.where_clause; - let dummy_const = builder.id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident)); + let dummy_const = aster::id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident)); - quote_item!(cx, + Ok(quote! { #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] - const $dummy_const: () = { + const #dummy_const: () = { extern crate serde as _serde; #[automatically_derived] - impl $impl_generics _serde::de::Deserialize for $ty $where_clause { - fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<$ty, __D::Error> + impl #impl_generics _serde::de::Deserialize for #ty #where_clause { + fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<#ty, __D::Error> where __D: _serde::de::Deserializer - $body + #body } }; - ).unwrap() + }) } // All the generics in the input, plus a bound `T: Deserialize` for each generic // field type that will be deserialized by us, plus a bound `T: Default` for // each generic field type that will be set to a default value. -fn build_impl_generics( - builder: &aster::AstBuilder, - item: &Item, -) -> ast::Generics { +fn build_impl_generics(item: &Item) -> syn::Generics { let generics = bound::without_defaults(item.generics); let generics = bound::with_where_predicates_from_fields( - builder, item, &generics, + item, &generics, |attrs| attrs.de_bound()); match item.attrs.de_bound() { Some(predicates) => { - bound::with_where_predicates(builder, &generics, predicates) + bound::with_where_predicates(&generics, predicates) } None => { - let generics = bound::with_bound(builder, item, &generics, + let generics = bound::with_bound(item, &generics, needs_deserialize_bound, - &builder.path().ids(&["_serde", "de", "Deserialize"]).build()); - let generics = bound::with_bound(builder, item, &generics, + &aster::path().ids(&["_serde", "de", "Deserialize"]).build()); + bound::with_bound(item, &generics, requires_default, - &builder.path().global().ids(&["std", "default", "Default"]).build()); - generics + &aster::path().global().ids(&["std", "default", "Default"]).build()) } } } @@ -129,18 +86,14 @@ fn requires_default(attrs: &attr::Field) -> bool { } fn deserialize_body( - cx: &ExtCtxt, - builder: &aster::AstBuilder, item: &Item, - impl_generics: &ast::Generics, - ty: P, -) -> P { + impl_generics: &syn::Generics, + ty: syn::Ty, +) -> Tokens { match item.body { Body::Enum(ref variants) => { deserialize_item_enum( - cx, - builder, - item.ident, + &item.ident, impl_generics, ty, variants, @@ -148,13 +101,11 @@ fn deserialize_body( } Body::Struct(Style::Struct, ref fields) => { if fields.iter().any(|field| field.ident.is_none()) { - cx.span_bug(item.span, "struct has unnamed fields") + panic!("struct has unnamed fields"); } deserialize_struct( - cx, - builder, - item.ident, + &item.ident, None, impl_generics, ty, @@ -164,13 +115,11 @@ fn deserialize_body( Body::Struct(Style::Tuple, ref fields) | Body::Struct(Style::Newtype, ref fields) => { if fields.iter().any(|field| field.ident.is_some()) { - cx.span_bug(item.span, "tuple struct has named fields") + panic!("tuple struct has named fields"); } deserialize_tuple( - cx, - builder, - item.ident, + &item.ident, None, impl_generics, ty, @@ -179,93 +128,99 @@ fn deserialize_body( } Body::Struct(Style::Unit, _) => { deserialize_unit_struct( - cx, - builder, - item.ident, + &item.ident, &item.attrs) } } } // Build `__Visitor(PhantomData, PhantomData, ...)` -fn deserialize_visitor( - builder: &aster::AstBuilder, - generics: &ast::Generics, -) -> (P, P, P) { +// +// Returns: +// +// 1. the struct declaration +// 2. the visitor type, including generics +// 3. the expression for instantiating the visitor +fn deserialize_visitor(generics: &syn::Generics) -> (Tokens, Tokens, Tokens) { if generics.lifetimes.is_empty() && generics.ty_params.is_empty() { ( - builder.item().unit_struct("__Visitor"), - builder.ty().id("__Visitor"), - builder.expr().id("__Visitor"), + quote! { + struct __Visitor; + }, + quote!(__Visitor), + quote!(__Visitor), ) } else { - let placeholders : Vec<_> = generics.ty_params.iter() - .map(|t| builder.ty().id(t.ident)) + let where_clause = &generics.where_clause; + + let num_phantoms = generics.lifetimes.len() + generics.ty_params.len(); + + let phantom_types = generics.lifetimes.iter() + .map(|lifetime_def| { + let lifetime = &lifetime_def.lifetime; + quote!(::std::marker::PhantomData<& #lifetime ()>) + }).chain(generics.ty_params.iter() + .map(|ty_param| { + let ident = &ty_param.ident; + quote!(::std::marker::PhantomData<#ident>) + })); + + let all_params = generics.lifetimes.iter() + .map(|lifetime_def| { + let lifetime = &lifetime_def.lifetime; + quote!(#lifetime) + }).chain(generics.ty_params.iter() + .map(|ty_param| { + let ident = &ty_param.ident; + quote!(#ident) + })); + + let ty_param_idents: Vec<_> = generics.ty_params.iter() + .map(|t| { + let ident = &t.ident; + quote!(#ident) + }) .collect(); + let ty_param_idents = if ty_param_idents.is_empty() { + None + } else { + Some(quote!(::<#(#ty_param_idents),*>)) + }; + + let phantom_exprs = iter::repeat(quote!(::std::marker::PhantomData)).take(num_phantoms); + ( - builder.item().tuple_struct("__Visitor") - .generics().with(generics.clone()).build() - .with_tys({ - let lifetimes = generics.lifetimes.iter() - .map(|lifetime_def| { - builder.ty() - .phantom_data() - .ref_().lifetime(lifetime_def.lifetime.name) - .ty() - .unit() - }); - - let ty_params = generics.ty_params.iter() - .map(|ty_param| { - builder.ty() - .phantom_data() - .id(ty_param.ident) - }); - - lifetimes.chain(ty_params) - }) - .build(), - builder.ty().path() - .segment("__Visitor").with_generics(generics.clone()).build() - .build(), - builder.expr().call() - .path().segment("__Visitor") - .with_tys(placeholders) - .build().build() - .with_args({ - let len = generics.lifetimes.len() + generics.ty_params.len(); - - (0 .. len).map(|_| builder.expr().phantom_data()) - }) - .build(), + quote! { + struct __Visitor #generics ( #(#phantom_types),* ) #where_clause; + }, + quote!(__Visitor <#(#all_params),*> ), + quote!(__Visitor #ty_param_idents ( #(#phantom_exprs),* )), ) } } fn deserialize_unit_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, + type_ident: &syn::Ident, item_attrs: &attr::Item, -) -> P { - let type_name = name_expr(builder, item_attrs.name()); +) -> Tokens { + let type_name = item_attrs.name().deserialize_name(); - quote_block!(cx, { + quote!({ struct __Visitor; impl _serde::de::Visitor for __Visitor { - type Value = $type_ident; + type Value = #type_ident; #[inline] - fn visit_unit<__E>(&mut self) -> ::std::result::Result<$type_ident, __E> + fn visit_unit<__E>(&mut self) -> ::std::result::Result<#type_ident, __E> where __E: _serde::de::Error, { - Ok($type_ident) + Ok(#type_ident) } #[inline] - fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$type_ident, __V::Error> + fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#type_ident, __V::Error> where __V: _serde::de::SeqVisitor, { try!(visitor.end()); @@ -273,39 +228,32 @@ fn deserialize_unit_struct( } } - deserializer.deserialize_unit_struct($type_name, __Visitor) - }).unwrap() + deserializer.deserialize_unit_struct(#type_name, __Visitor) + }) } fn deserialize_tuple( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - variant_ident: Option, - impl_generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + variant_ident: Option<&syn::Ident>, + impl_generics: &syn::Generics, + ty: syn::Ty, fields: &[Field], item_attrs: &attr::Item, -) -> P { +) -> Tokens { let where_clause = &impl_generics.where_clause; - let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( - builder, - impl_generics, - ); + let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(impl_generics); let is_enum = variant_ident.is_some(); let type_path = match variant_ident { - Some(variant_ident) => builder.path().id(type_ident).id(variant_ident).build(), - None => builder.path().id(type_ident).build(), + Some(variant_ident) => quote!(#type_ident::#variant_ident), + None => quote!(#type_ident), }; let nfields = fields.len(); let visit_newtype_struct = if !is_enum && nfields == 1 { Some(deserialize_newtype_struct( - cx, - builder, type_ident, &type_path, impl_generics, @@ -316,90 +264,85 @@ fn deserialize_tuple( }; let visit_seq = deserialize_seq( - cx, - builder, type_ident, - type_path, + &type_path, impl_generics, fields, false, ); let dispatch = if is_enum { - quote_expr!(cx, - visitor.visit_tuple($nfields, $visitor_expr)) + quote!(visitor.visit_tuple(#nfields, #visitor_expr)) } else if nfields == 1 { - let type_name = name_expr(builder, item_attrs.name()); - quote_expr!(cx, - deserializer.deserialize_newtype_struct($type_name, $visitor_expr)) + let type_name = item_attrs.name().deserialize_name(); + quote!(deserializer.deserialize_newtype_struct(#type_name, #visitor_expr)) } else { - let type_name = name_expr(builder, item_attrs.name()); - quote_expr!(cx, - deserializer.deserialize_tuple_struct($type_name, $nfields, $visitor_expr)) + let type_name = item_attrs.name().deserialize_name(); + quote!(deserializer.deserialize_tuple_struct(#type_name, #nfields, #visitor_expr)) }; - quote_block!(cx, { - $visitor_item + quote!({ + #visitor_item - impl $impl_generics _serde::de::Visitor for $visitor_ty $where_clause { - type Value = $ty; + impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { + type Value = #ty; - $visit_newtype_struct + #visit_newtype_struct #[inline] - fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> + fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error> where __V: _serde::de::SeqVisitor - $visit_seq + { + #visit_seq + } } - $dispatch - }).unwrap() + #dispatch + }) } fn deserialize_seq( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - type_path: ast::Path, - impl_generics: &ast::Generics, + type_ident: &syn::Ident, + type_path: &Tokens, + impl_generics: &syn::Generics, fields: &[Field], is_struct: bool, -) -> P { +) -> Tokens { let mut index_in_seq = 0usize; let let_values: Vec<_> = fields.iter() .enumerate() .map(|(i, field)| { - let name = builder.id(format!("__field{}", i)); + let name = aster::id(format!("__field{}", i)); if field.attrs.skip_deserializing() { - let default = expr_is_missing(cx, builder, &field.attrs); - quote_stmt!(cx, - let $name = $default; - ).unwrap() + let default = expr_is_missing(&field.attrs); + quote! { + let #name = #default; + } } else { let visit = match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; - quote_expr!(cx, try!(visitor.visit::<$field_ty>())) + quote!(try!(visitor.visit::<#field_ty>())) } Some(path) => { let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with( - cx, builder, type_ident, impl_generics, &field.ty, path); - quote_expr!(cx, { - $wrapper - $wrapper_impl - try!(visitor.visit::<$wrapper_ty>()).map(|wrap| wrap.value) + type_ident, impl_generics, field.ty, path); + quote!({ + #wrapper + #wrapper_impl + try!(visitor.visit::<#wrapper_ty>()).map(|wrap| wrap.value) }) } }; - let assign = quote_stmt!(cx, - let $name = match $visit { + let assign = quote! { + let #name = match #visit { Some(value) => { value }, None => { try!(visitor.end()); - return Err(_serde::de::Error::invalid_length($index_in_seq)); + return Err(_serde::de::Error::invalid_length(#index_in_seq)); } }; - ).unwrap(); + }; index_in_seq += 1; assign } @@ -407,110 +350,93 @@ fn deserialize_seq( .collect(); let result = if is_struct { - builder.expr().struct_path(type_path) - .with_id_exprs( - fields.iter() - .enumerate() - .map(|(i, field)| { - ( - match field.ident { - Some(name) => name.clone(), - None => { - cx.span_bug(field.span, "struct contains unnamed fields") - } - }, - builder.expr().id(format!("__field{}", i)), - ) - }) - ) - .build() + let args = fields.iter() + .enumerate() + .map(|(i, field)| { + let ident = field.ident.clone().expect("struct contains unnamed fields"); + let value = aster::id(format!("__field{}", i)); + quote!(#ident: #value) + }); + quote! { + #type_path { #(#args),* } + } } else { - builder.expr().call() - .build_path(type_path) - .with_args((0..fields.len()).map(|i| builder.expr().id(format!("__field{}", i)))) - .build() + let args = (0..fields.len()).map(|i| aster::id(format!("__field{}", i))); + quote! { + #type_path ( #(#args),* ) + } }; - quote_block!(cx, { - $let_values + quote! { + #(#let_values)* try!(visitor.end()); - Ok($result) - }).unwrap() + Ok(#result) + } } fn deserialize_newtype_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - type_path: &ast::Path, - impl_generics: &ast::Generics, + type_ident: &syn::Ident, + type_path: &Tokens, + impl_generics: &syn::Generics, field: &Field, -) -> Vec { +) -> Tokens { let value = match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; - quote_expr!(cx, - try!(<$field_ty as _serde::Deserialize>::deserialize(__e))) + quote! { + try!(<#field_ty as _serde::Deserialize>::deserialize(__e)) + } } Some(path) => { let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with( - cx, builder, type_ident, impl_generics, &field.ty, path); - quote_expr!(cx, { - $wrapper - $wrapper_impl - try!(<$wrapper_ty as _serde::Deserialize>::deserialize(__e)).value + type_ident, impl_generics, field.ty, path); + quote!({ + #wrapper + #wrapper_impl + try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value }) } }; - quote_tokens!(cx, + quote! { #[inline] fn visit_newtype_struct<__E>(&mut self, __e: &mut __E) -> ::std::result::Result where __E: _serde::de::Deserializer, { - Ok($type_path($value)) + Ok(#type_path(#value)) } - ) + } } fn deserialize_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - variant_ident: Option, - impl_generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + variant_ident: Option<&syn::Ident>, + impl_generics: &syn::Generics, + ty: syn::Ty, fields: &[Field], item_attrs: &attr::Item, -) -> P { +) -> Tokens { let where_clause = &impl_generics.where_clause; - let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( - builder, - impl_generics, - ); + let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(impl_generics); let type_path = match variant_ident { - Some(variant_ident) => builder.path().id(type_ident).id(variant_ident).build(), - None => builder.path().id(type_ident).build(), + Some(variant_ident) => quote!(#type_ident::#variant_ident), + None => quote!(#type_ident), }; let visit_seq = deserialize_seq( - cx, - builder, type_ident, - type_path.clone(), + &type_path, impl_generics, fields, true, ); let (field_visitor, fields_stmt, visit_map) = deserialize_struct_visitor( - cx, - builder, type_ident, - type_path.clone(), + type_path, impl_generics, fields, item_attrs, @@ -518,88 +444,86 @@ fn deserialize_struct( let is_enum = variant_ident.is_some(); let dispatch = if is_enum { - quote_expr!(cx, - visitor.visit_struct(FIELDS, $visitor_expr)) + quote! { + visitor.visit_struct(FIELDS, #visitor_expr) + } } else { - let type_name = name_expr(builder, item_attrs.name()); - quote_expr!(cx, - deserializer.deserialize_struct($type_name, FIELDS, $visitor_expr)) + let type_name = item_attrs.name().deserialize_name(); + quote! { + deserializer.deserialize_struct(#type_name, FIELDS, #visitor_expr) + } }; - quote_block!(cx, { - $field_visitor + quote!({ + #field_visitor - $visitor_item + #visitor_item - impl $impl_generics _serde::de::Visitor for $visitor_ty $where_clause { - type Value = $ty; + impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { + type Value = #ty; #[inline] - fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> + fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error> where __V: _serde::de::SeqVisitor - $visit_seq + { + #visit_seq + } #[inline] - fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> + fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error> where __V: _serde::de::MapVisitor - $visit_map + { + #visit_map + } } - $fields_stmt + #fields_stmt - $dispatch - }).unwrap() + #dispatch + }) } fn deserialize_item_enum( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - impl_generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + impl_generics: &syn::Generics, + ty: syn::Ty, variants: &[Variant], item_attrs: &attr::Item -) -> P { +) -> Tokens { let where_clause = &impl_generics.where_clause; - let type_name = name_expr(builder, item_attrs.name()); + let type_name = item_attrs.name().deserialize_name(); let variant_visitor = deserialize_field_visitor( - cx, - builder, variants.iter() + .filter(|variant| !variant.attrs.skip_deserializing()) .map(|variant| variant.attrs.name().deserialize_name()) .collect(), item_attrs, true, ); - let variants_expr = builder.expr().ref_().slice() - .with_exprs( - variants.iter().map(|variant| builder.expr().str(variant.ident)) - ) - .build(); + let variant_names = variants.iter().map(|variant| variant.ident.to_string()); - let variants_stmt = quote_stmt!(cx, - const VARIANTS: &'static [&'static str] = $variants_expr; - ).unwrap(); + let variants_stmt = quote! { + const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; + }; let ignored_arm = if item_attrs.deny_unknown_fields() { None } else { - Some(quote_arm!(cx, __Field::__ignore => { Err(_serde::de::Error::end_of_stream()) })) + Some(quote! { + __Field::__ignore => { Err(_serde::de::Error::end_of_stream()) } + }) }; // Match arms to extract a variant from a string let mut variant_arms = vec![]; - for (i, variant) in variants.iter().enumerate() { - let variant_name = builder.pat().path() - .id("__Field").id(format!("__field{}", i)) - .build(); + for (i, variant) in variants.iter().filter(|variant| !variant.attrs.skip_deserializing()).enumerate() { + let variant_name = aster::id(format!("__field{}", i)); + let variant_name = quote!(__Field::#variant_name); let block = deserialize_variant( - cx, - builder, type_ident, impl_generics, ty.clone(), @@ -607,61 +531,56 @@ fn deserialize_item_enum( item_attrs, ); - let arm = quote_arm!(cx, $variant_name => $block); + let arm = quote! { + #variant_name => #block + }; variant_arms.push(arm); } variant_arms.extend(ignored_arm.into_iter()); - let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( - builder, - impl_generics, - ); + let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(impl_generics); - quote_block!(cx, { - $variant_visitor + quote!({ + #variant_visitor - $visitor_item + #visitor_item - impl $impl_generics _serde::de::Visitor for $visitor_ty $where_clause { - type Value = $ty; + impl #impl_generics _serde::de::Visitor for #visitor_ty #where_clause { + type Value = #ty; - fn visit_enum<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> + fn visit_enum<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error> where __V: _serde::de::VariantVisitor, { match try!(visitor.visit_variant()) { - $variant_arms + #(#variant_arms)* } } } - $variants_stmt + #variants_stmt - deserializer.deserialize_enum($type_name, VARIANTS, $visitor_expr) - }).unwrap() + deserializer.deserialize_enum(#type_name, VARIANTS, #visitor_expr) + }) } fn deserialize_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + generics: &syn::Generics, + ty: syn::Ty, variant: &Variant, item_attrs: &attr::Item, -) -> P { - let variant_ident = variant.ident; +) -> Tokens { + let variant_ident = &variant.ident; match variant.style { Style::Unit => { - quote_block!(cx, { + quote!({ try!(visitor.visit_unit()); - Ok($type_ident::$variant_ident) - }).unwrap() + Ok(#type_ident::#variant_ident) + }) } Style::Newtype => { deserialize_newtype_variant( - cx, - builder, type_ident, variant_ident, generics, @@ -670,8 +589,6 @@ fn deserialize_variant( } Style::Tuple => { deserialize_tuple( - cx, - builder, type_ident, Some(variant_ident), generics, @@ -682,8 +599,6 @@ fn deserialize_variant( } Style::Struct => { deserialize_struct( - cx, - builder, type_ident, Some(variant_ident), generics, @@ -696,146 +611,140 @@ fn deserialize_variant( } fn deserialize_newtype_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - variant_ident: Ident, - impl_generics: &ast::Generics, + type_ident: &syn::Ident, + variant_ident: &syn::Ident, + impl_generics: &syn::Generics, field: &Field, -) -> P { +) -> Tokens { let visit = match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; - quote_expr!(cx, try!(visitor.visit_newtype::<$field_ty>())) + quote!(try!(visitor.visit_newtype::<#field_ty>())) } Some(path) => { let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with( - cx, builder, type_ident, impl_generics, &field.ty, path); - quote_expr!(cx, { - $wrapper - $wrapper_impl - try!(visitor.visit_newtype::<$wrapper_ty>()).value + type_ident, impl_generics, field.ty, path); + quote!({ + #wrapper + #wrapper_impl + try!(visitor.visit_newtype::<#wrapper_ty>()).value }) } }; - quote_block!(cx, { - Ok($type_ident::$variant_ident($visit)) - }).unwrap() + quote! { + Ok(#type_ident::#variant_ident(#visit)), + } } fn deserialize_field_visitor( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - field_names: Vec, + field_names: Vec, item_attrs: &attr::Item, is_variant: bool, -) -> Vec> { +) -> Tokens { // Create the field names for the fields. let field_idents: Vec<_> = (0 .. field_names.len()) - .map(|i| builder.id(format!("__field{}", i))) + .map(|i| aster::id(format!("__field{}", i))) .collect(); let ignore_variant = if item_attrs.deny_unknown_fields() { None } else { - let skip_ident = builder.id("__ignore"); - Some(builder.variant(skip_ident).unit()) + Some(quote!(__ignore,)) }; - let field_enum = builder.item() - .attr().allow(&["non_camel_case_types"]) - .enum_("__Field") - .with_variants( - field_idents.iter().map(|field_ident| { - builder.variant(field_ident).unit() - }) - ) - .with_variants(ignore_variant.into_iter()) - .build(); - let index_field_arms: Vec<_> = field_idents.iter() .enumerate() .map(|(field_index, field_ident)| { - quote_arm!(cx, $field_index => { Ok(__Field::$field_ident) }) + quote! { + #field_index => { Ok(__Field::#field_ident) } + } }) .collect(); let (index_error_msg, unknown_ident) = if is_variant { - (builder.expr().str("expected a variant"), builder.id("unknown_variant")) + ("expected a variant", aster::id("unknown_variant")) } else { - (builder.expr().str("expected a field"), builder.id("unknown_field")) + ("expected a field", aster::id("unknown_field")) }; let fallthrough_index_arm_expr = if !is_variant && !item_attrs.deny_unknown_fields() { - quote_expr!(cx, Ok(__Field::__ignore)) + quote! { + Ok(__Field::__ignore) + } } else { - quote_expr!(cx, Err(_serde::de::Error::invalid_value($index_error_msg))) + quote! { + Err(_serde::de::Error::invalid_value(#index_error_msg)) + } }; - let index_body = quote_block!(cx, { + let index_body = quote! { match value { - $index_field_arms - _ => $fallthrough_index_arm_expr + #(#index_field_arms)* + _ => #fallthrough_index_arm_expr } - }).unwrap(); - - // Convert the field names into byte strings. - let str_field_names: Vec<_> = field_names.iter() - .map(|name| builder.expr().lit().str(&name)) - .collect(); + }; // Match arms to extract a field from a string - let str_field_arms: Vec<_> = field_idents.iter().zip(str_field_names.iter()) + let str_field_arms: Vec<_> = field_idents.iter().zip(field_names.iter()) .map(|(field_ident, field_name)| { - quote_arm!(cx, $field_name => { Ok(__Field::$field_ident) }) + quote! { + #field_name => { Ok(__Field::#field_ident) } + } }) .collect(); let fallthrough_str_arm_expr = if !is_variant && !item_attrs.deny_unknown_fields() { - quote_expr!(cx, Ok(__Field::__ignore)) + quote! { + Ok(__Field::__ignore) + } } else { - quote_expr!(cx, Err(_serde::de::Error::$unknown_ident(value))) + quote! { + Err(_serde::de::Error::#unknown_ident(value)) + } }; - let str_body = quote_block!(cx, { + let str_body = quote! { match value { - $str_field_arms - _ => $fallthrough_str_arm_expr + #(#str_field_arms)* + _ => #fallthrough_str_arm_expr } - }).unwrap(); - - // Convert the field names into byte strings. - let bytes_field_names: Vec<_> = field_names.iter() - .map(|name| { - let name: &str = name; - builder.expr().lit().byte_str(name) - }) - .collect(); + }; // Match arms to extract a field from a string - let bytes_field_arms: Vec<_> = field_idents.iter().zip(bytes_field_names.iter()) + let bytes_field_arms: Vec<_> = field_idents.iter().zip(field_names.iter()) .map(|(field_ident, field_name)| { - quote_arm!(cx, $field_name => { Ok(__Field::$field_ident) }) + let bytes_field_name = quote::ByteStr(field_name); + quote! { + #bytes_field_name => { Ok(__Field::#field_ident) } + } }) .collect(); let fallthrough_bytes_arm_expr = if !is_variant && !item_attrs.deny_unknown_fields() { - quote_expr!(cx, Ok(__Field::__ignore)) + quote! { + Ok(__Field::__ignore) + } } else { - quote_expr!(cx, { + quote!({ let value = ::std::string::String::from_utf8_lossy(value); - Err(_serde::de::Error::$unknown_ident(&value)) + Err(_serde::de::Error::#unknown_ident(&value)) }) }; - let bytes_body = quote_block!(cx, { + let bytes_body = quote! { match value { - $bytes_field_arms - _ => $fallthrough_bytes_arm_expr + #(#bytes_field_arms)* + _ => #fallthrough_bytes_arm_expr + } + }; + + quote! { + #[allow(non_camel_case_types)] + enum __Field { + #(#field_idents,)* + #ignore_variant } - }).unwrap(); - let impl_item = quote_item!(cx, impl _serde::de::Deserialize for __Field { #[inline] fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<__Field, __D::Error> @@ -848,49 +757,47 @@ fn deserialize_field_visitor( fn visit_usize<__E>(&mut self, value: usize) -> ::std::result::Result<__Field, __E> where __E: _serde::de::Error - $index_body + { + #index_body + } fn visit_str<__E>(&mut self, value: &str) -> ::std::result::Result<__Field, __E> where __E: _serde::de::Error - $str_body + { + #str_body + } fn visit_bytes<__E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, __E> where __E: _serde::de::Error - $bytes_body + { + #bytes_body + } } deserializer.deserialize_struct_field(__FieldVisitor) } } - ).unwrap(); - - vec![field_enum, impl_item] + } } fn deserialize_struct_visitor( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - struct_path: ast::Path, - impl_generics: &ast::Generics, + type_ident: &syn::Ident, + struct_path: Tokens, + impl_generics: &syn::Generics, fields: &[Field], item_attrs: &attr::Item, -) -> (Vec>, ast::Stmt, P) { +) -> (Tokens, Tokens, Tokens) { let field_exprs = fields.iter() .map(|field| field.attrs.name().deserialize_name()) .collect(); let field_visitor = deserialize_field_visitor( - cx, - builder, field_exprs, item_attrs, false, ); let visit_map = deserialize_map( - cx, - builder, type_ident, struct_path, impl_generics, @@ -898,82 +805,73 @@ fn deserialize_struct_visitor( item_attrs, ); - let fields_expr = builder.expr().ref_().slice() - .with_exprs( - fields.iter() - .map(|field| { - match field.ident { - Some(name) => builder.expr().str(name), - None => { - cx.span_bug(field.span, "struct contains unnamed fields") - } - } - }) - ) - .build(); + let field_names = fields.iter().map(|field| { + field.ident.clone().expect("struct contains unnamed field").to_string() + }); - let fields_stmt = quote_stmt!(cx, - const FIELDS: &'static [&'static str] = $fields_expr; - ).unwrap(); + let fields_stmt = quote! { + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + }; (field_visitor, fields_stmt, visit_map) } fn deserialize_map( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - struct_path: ast::Path, - impl_generics: &ast::Generics, + type_ident: &syn::Ident, + struct_path: Tokens, + impl_generics: &syn::Generics, fields: &[Field], item_attrs: &attr::Item, -) -> P { +) -> Tokens { // Create the field names for the fields. let fields_names = fields.iter() .enumerate() .map(|(i, field)| - (field, builder.id(format!("__field{}", i)))) + (field, aster::id(format!("__field{}", i)))) .collect::>(); // Declare each field that will be deserialized. - let let_values: Vec = fields_names.iter() + let let_values: Vec<_> = fields_names.iter() .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|&(field, name)| { + .map(|&(field, ref name)| { let field_ty = &field.ty; - quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap() + quote! { + let mut #name: Option<#field_ty> = None; + } }) .collect(); // Match arms to extract a value for a field. let value_arms = fields_names.iter() .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|&(ref field, name)| { + .map(|&(field, ref name)| { let deser_name = field.attrs.name().deserialize_name(); - let name_str = builder.expr().lit().str(deser_name); let visit = match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; - quote_expr!(cx, try!(visitor.visit_value::<$field_ty>())) + quote! { + try!(visitor.visit_value::<#field_ty>()) + } } Some(path) => { let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with( - cx, builder, type_ident, impl_generics, &field.ty, path); - quote_expr!(cx, ({ - $wrapper - $wrapper_impl - try!(visitor.visit_value::<$wrapper_ty>()).value - })) + type_ident, impl_generics, field.ty, path); + quote!({ + #wrapper + #wrapper_impl + try!(visitor.visit_value::<#wrapper_ty>()).value + }) } }; - quote_arm!(cx, - __Field::$name => { - if $name.is_some() { - return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str)); + quote! { + __Field::#name => { + if #name.is_some() { + return Err(<__V::Error as _serde::de::Error>::duplicate_field(#deser_name)); } - $name = Some($visit); + #name = Some(#visit); } - ) + } }) .collect::>(); @@ -981,12 +879,12 @@ fn deserialize_map( // Ignored even if `deny_unknown_fields` is set. let skipped_arms = fields_names.iter() .filter(|&&(field, _)| field.attrs.skip_deserializing()) - .map(|&(_, name)| { - quote_arm!(cx, - __Field::$name => { - try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>()); + .map(|&(_, ref name)| { + quote! { + __Field::#name => { + let _ = try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>()); } - ) + } }) .collect::>(); @@ -994,78 +892,66 @@ fn deserialize_map( let ignored_arm = if item_attrs.deny_unknown_fields() { None } else { - Some(quote_arm!(cx, - _ => { try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>()); } - )) + Some(quote! { + _ => { let _ = try!(visitor.visit_value::<_serde::de::impls::IgnoredAny>()); } + }) }; let extract_values = fields_names.iter() .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|&(field, name)| { - let missing_expr = expr_is_missing(cx, builder, &field.attrs); + .map(|&(field, ref name)| { + let missing_expr = expr_is_missing(&field.attrs); - quote_stmt!(cx, - let $name = match $name { - Some($name) => $name, - None => $missing_expr + quote! { + let #name = match #name { + Some(#name) => #name, + None => #missing_expr }; - ).unwrap() + } }) .collect::>(); - let result = builder.expr().struct_path(struct_path) - .with_id_exprs( - fields_names.iter() - .map(|&(field, name)| { - ( - match field.ident { - Some(name) => name.clone(), - None => { - cx.span_bug(field.span, "struct contains unnamed fields") - } - }, - if field.attrs.skip_deserializing() { - expr_is_missing(cx, builder, &field.attrs) - } else { - builder.expr().id(name) - } - ) - }) - ) - .build(); + let result = fields_names.iter() + .map(|&(field, ref name)| { + let ident = field.ident.clone().expect("struct contains unnamed fields"); + let value = if field.attrs.skip_deserializing() { + expr_is_missing(&field.attrs) + } else { + quote!(#name) + }; + quote!(#ident: #value) + }); - quote_block!(cx, { - $let_values + quote! { + #(#let_values)* while let Some(key) = try!(visitor.visit_key::<__Field>()) { match key { - $value_arms - $skipped_arms - $ignored_arm + #(#value_arms)* + #(#skipped_arms)* + #ignored_arm } } try!(visitor.end()); - $extract_values + #(#extract_values)* - Ok($result) - }).unwrap() + Ok(#struct_path { #(#result),* }) + } } /// This function wraps the expression in `#[serde(deserialize_with="...")]` in /// a trait to prevent it from accessing the internal `Deserialize` state. fn wrap_deserialize_with( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - impl_generics: &ast::Generics, - field_ty: &P, - deserialize_with: &ast::Path, -) -> (ast::Stmt, ast::Stmt, ast::Path) { + type_ident: &syn::Ident, + impl_generics: &syn::Generics, + field_ty: &syn::Ty, + deserialize_with: &syn::Path, +) -> (Tokens, Tokens, syn::Path) { // Quasi-quoting doesn't do a great job of expanding generics into paths, // so manually build it. - let wrapper_ty = builder.path() + let wrapper_ty = aster::path() .segment("__SerdeDeserializeWithStruct") .with_generics(impl_generics.clone()) .build() @@ -1073,97 +959,82 @@ fn wrap_deserialize_with( let where_clause = &impl_generics.where_clause; - let phantom_ty = builder.path() + let phantom_ty = aster::path() .segment(type_ident) - .with_generics(builder.from_generics(impl_generics.clone()) + .with_generics(aster::from_generics(impl_generics.clone()) .strip_ty_params() .build()) .build() .build(); ( - quote_stmt!(cx, - struct __SerdeDeserializeWithStruct $impl_generics $where_clause { - value: $field_ty, - phantom: ::std::marker::PhantomData<$phantom_ty>, + quote! { + struct __SerdeDeserializeWithStruct #impl_generics #where_clause { + value: #field_ty, + phantom: ::std::marker::PhantomData<#phantom_ty>, } - ).unwrap(), - quote_stmt!(cx, - impl $impl_generics _serde::de::Deserialize for $wrapper_ty $where_clause { + }, + quote! { + impl #impl_generics _serde::de::Deserialize for #wrapper_ty #where_clause { fn deserialize<__D>(__d: &mut __D) -> ::std::result::Result where __D: _serde::de::Deserializer { - let value = try!($deserialize_with(__d)); + let value = try!(#deserialize_with(__d)); Ok(__SerdeDeserializeWithStruct { value: value, phantom: ::std::marker::PhantomData, }) } } - ).unwrap(), + }, wrapper_ty, ) } -fn expr_is_missing( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - attrs: &attr::Field, -) -> P { +fn expr_is_missing(attrs: &attr::Field) -> Tokens { match *attrs.default() { attr::FieldDefault::Default => { - return quote_expr!(cx, ::std::default::Default::default()); + return quote!(::std::default::Default::default()); } attr::FieldDefault::Path(ref path) => { - return quote_expr!(cx, $path()); + return quote!(#path()); } attr::FieldDefault::None => { /* below */ } } - let name = name_expr(builder, attrs.name()); + let name = attrs.name().deserialize_name(); match attrs.deserialize_with() { None => { - quote_expr!(cx, try!(visitor.missing_field($name))) + quote! { + try!(visitor.missing_field(#name)) + } } Some(_) => { - quote_expr!(cx, return Err( - <__V::Error as _serde::de::Error>::missing_field($name))) + quote! { + return Err(<__V::Error as _serde::de::Error>::missing_field(#name)) + } } } } -fn name_expr( - builder: &aster::AstBuilder, - name: &attr::Name, -) -> P { - builder.expr().str(name.deserialize_name()) -} - -fn check_no_str( - cx: &ExtCtxt, - item: &Item, -) -> Result<(), ()> { - let fail = |field: &Field| { - cx.span_err( - field.span, +fn check_no_str(cx: &internals::Ctxt, item: &Item) { + let fail = || { + cx.error( "Serde does not support deserializing fields of type &str; \ consider using String instead"); - Err(()) }; for field in item.body.all_fields() { if field.attrs.skip_deserializing() || field.attrs.deserialize_with().is_some() { continue } - if let ast::TyKind::Rptr(_, ref inner) = field.ty.node { - if let ast::TyKind::Path(_, ref path) = inner.ty.node { - if path.segments.len() == 1 - && path.segments[0].identifier.name.as_str() == "str" - { - return fail(field); + if let syn::Ty::Rptr(_, ref inner) = *field.ty { + if let syn::Ty::Path(_, ref path) = inner.ty { + if path.segments.len() == 1 && path.segments[0].ident == "str" { + fail(); + return; } } } } - Ok(()) } diff --git a/serde_codegen/src/lib.rs b/serde_codegen/src/lib.rs index fcdc6f4e..f920dda5 100644 --- a/serde_codegen/src/lib.rs +++ b/serde_codegen/src/lib.rs @@ -2,11 +2,10 @@ #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", allow(too_many_arguments))] #![cfg_attr(feature = "clippy", allow(used_underscore_binding))] -#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] -#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))] -extern crate aster; -extern crate quasi; +// The `quote!` macro requires deep recursion. +#![recursion_limit = "192"] + extern crate serde_codegen_internals as internals; #[cfg(feature = "with-syntex")] @@ -16,24 +15,68 @@ extern crate syntex; #[macro_use] extern crate syntex_syntax as syntax; -#[cfg(not(feature = "with-syntex"))] +extern crate syn; #[macro_use] -extern crate syntax; - -#[cfg(not(feature = "with-syntex"))] -extern crate rustc_plugin; +extern crate quote; #[cfg(feature = "with-syntex")] use std::path::Path; -#[cfg(not(feature = "with-syntex"))] -use syntax::feature_gate::AttributeType; +mod bound; +mod de; +mod ser; #[cfg(feature = "with-syntex")] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); +fn syntex_registry() -> syntex::Registry { + use syntax::{ast, fold}; -#[cfg(not(feature = "with-syntex"))] -include!("lib.rs.in"); + /// Strip the serde attributes from the crate. + #[cfg(feature = "with-syntex")] + fn strip_attributes(krate: ast::Crate) -> ast::Crate { + /// Helper folder that strips the serde attributes after the extensions have been expanded. + struct StripAttributeFolder; + + impl fold::Folder for StripAttributeFolder { + fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { + if attr.value.name == "serde" { + if let ast::MetaItemKind::List(..) = attr.value.node { + return None; + } + } + Some(attr) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + fold::Folder::fold_crate(&mut StripAttributeFolder, krate) + } + + let mut reg = syntex::Registry::new(); + + reg.add_attr("feature(custom_derive)"); + reg.add_attr("feature(custom_attribute)"); + + reg.add_decorator("derive_Serialize", shim::expand_derive_serialize); + reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize); + + reg.add_post_expansion_pass(strip_attributes); + + reg +} + +#[cfg(feature = "with-syntex")] +pub fn expand_str(src: &str) -> Result { + let src = src.to_owned(); + + let expand_thread = move || { + syntex_registry().expand_str("", "", &src) + }; + + syntex::with_extra_stack(expand_thread) +} #[cfg(feature = "with-syntex")] pub fn expand(src: S, dst: D) -> Result<(), syntex::Error> @@ -44,59 +87,86 @@ pub fn expand(src: S, dst: D) -> Result<(), syntex::Error> let dst = dst.as_ref().to_owned(); let expand_thread = move || { - use syntax::{ast, fold}; - - /// Strip the serde attributes from the crate. - #[cfg(feature = "with-syntex")] - fn strip_attributes(krate: ast::Crate) -> ast::Crate { - /// Helper folder that strips the serde attributes after the extensions have been expanded. - struct StripAttributeFolder; - - impl fold::Folder for StripAttributeFolder { - fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { - match attr.node.value.node { - ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; } - _ => {} - } - - Some(attr) - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } - } - - fold::Folder::fold_crate(&mut StripAttributeFolder, krate) - } - - let mut reg = syntex::Registry::new(); - - reg.add_attr("feature(custom_derive)"); - reg.add_attr("feature(custom_attribute)"); - - reg.add_decorator("derive_Serialize", ser::expand_derive_serialize); - reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize); - - reg.add_post_expansion_pass(strip_attributes); - - reg.expand("", src, dst) + syntex_registry().expand("", src, dst) }; syntex::with_extra_stack(expand_thread) } -#[cfg(not(feature = "with-syntex"))] -pub fn register(reg: &mut rustc_plugin::Registry) { - reg.register_syntax_extension( - syntax::parse::token::intern("derive_Serialize"), - syntax::ext::base::MultiDecorator( - Box::new(ser::expand_derive_serialize))); +macro_rules! shim { + ($name:ident $pkg:ident :: $func:ident) => { + pub fn $func( + cx: &mut ::syntax::ext::base::ExtCtxt, + span: ::syntax::codemap::Span, + meta_item: &::syntax::ast::MetaItem, + annotatable: &::syntax::ext::base::Annotatable, + push: &mut FnMut(::syntax::ext::base::Annotatable) + ) { + let item = match *annotatable { + ::syntax::ext::base::Annotatable::Item(ref item) => item, + _ => { + cx.span_err( + meta_item.span, + concat!("`#[derive(", + stringify!($name), + ")]` may only be applied to structs and enums")); + return; + } + }; - reg.register_syntax_extension( - syntax::parse::token::intern("derive_Deserialize"), - syntax::ext::base::MultiDecorator( - Box::new(de::expand_derive_deserialize))); + use syntax::{attr, ast, visit}; + struct MarkSerdeAttributesUsed; + impl<'a> visit::Visitor<'a> for MarkSerdeAttributesUsed { + fn visit_attribute(&mut self, attr: &ast::Attribute) { + if attr.value.name == "serde" { + if let ast::MetaItemKind::List(..) = attr.value.node { + attr::mark_used(attr); + } + } + } + } + visit::walk_item(&mut MarkSerdeAttributesUsed, item); - reg.register_attribute("serde".to_owned(), AttributeType::Normal); + use syntax::print::pprust; + let s = pprust::item_to_string(item); + + use {syn, $pkg}; + let syn_item = syn::parse_macro_input(&s).unwrap(); + let expanded = match $pkg::$func(&syn_item) { + Ok(expanded) => expanded.to_string(), + Err(msg) => { + cx.span_err(span, &msg); + return; + } + }; + + use syntax::parse; + let name = stringify!($name).to_string(); + let sess = cx.parse_sess; + let impl_item = parse::parse_item_from_source_str(name, expanded, sess); + push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap())); + } + }; +} + +#[cfg(feature = "with-syntex")] +mod shim { + shim!(Serialize ser::expand_derive_serialize); + shim!(Deserialize de::expand_derive_deserialize); +} + +#[cfg(feature = "with-syn")] +#[doc(hidden)] +/// Not public API. Use the serde_derive crate. +pub fn expand_derive_serialize(item: &str) -> Result { + let syn_item = syn::parse_macro_input(item).unwrap(); + ser::expand_derive_serialize(&syn_item) +} + +#[cfg(feature = "with-syn")] +#[doc(hidden)] +/// Not public API. Use the serde_derive crate. +pub fn expand_derive_deserialize(item: &str) -> Result { + let syn_item = syn::parse_macro_input(item).unwrap(); + de::expand_derive_deserialize(&syn_item) } diff --git a/serde_codegen/src/lib.rs.in b/serde_codegen/src/lib.rs.in deleted file mode 100644 index 08dd5d3c..00000000 --- a/serde_codegen/src/lib.rs.in +++ /dev/null @@ -1,4 +0,0 @@ -mod bound; -mod de; -mod ser; -mod span; diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 266dc482..65459abc 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -1,102 +1,62 @@ -use aster; - -use syntax::ast::{self, Ident, MetaItem}; -use syntax::codemap::Span; -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::ptr::P; +use syn::{self, aster}; +use quote::Tokens; use bound; -use span; use internals::ast::{Body, Field, Item, Style, Variant}; -use internals::{attr, Error}; +use internals::{self, attr}; -pub fn expand_derive_serialize( - cx: &mut ExtCtxt, - span: Span, - meta_item: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable) -) { - let item = match *annotatable { - Annotatable::Item(ref item) => item, - _ => { - cx.span_err( - meta_item.span, - "`#[derive(Serialize)]` may only be applied to structs and enums"); - return; - } - }; +pub fn expand_derive_serialize(item: &syn::MacroInput) -> Result { + let ctxt = internals::Ctxt::new(); + let item = Item::from_ast(&ctxt, item); + try!(ctxt.check()); - let item = match Item::from_ast(cx, item) { - Ok(item) => item, - Err(Error::UnexpectedItemKind) => { - cx.span_err(item.span, - "`#[derive(Serialize)]` may only be applied to structs and enums"); - return; - } - }; + let impl_generics = build_impl_generics(&item); - let builder = aster::AstBuilder::new().span(span); - - let impl_item = serialize_item(cx, &builder, &item); - push(span::record_expansion(cx, impl_item, "Serialize")) -} - -fn serialize_item( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - item: &Item, -) -> P { - let impl_generics = build_impl_generics(builder, &item); - - let ty = builder.ty().path() - .segment(item.ident).with_generics(impl_generics.clone()).build() + let ty = aster::ty().path() + .segment(item.ident.clone()).with_generics(impl_generics.clone()).build() .build(); - let body = serialize_body(cx, - builder, - &item, + let body = serialize_body(&item, &impl_generics, ty.clone()); let where_clause = &impl_generics.where_clause; - let dummy_const = builder.id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident)); + let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident)); - quote_item!(cx, + Ok(quote! { #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] - const $dummy_const: () = { + const #dummy_const: () = { extern crate serde as _serde; #[automatically_derived] - impl $impl_generics _serde::ser::Serialize for $ty $where_clause { + impl #impl_generics _serde::ser::Serialize for #ty #where_clause { fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error> where __S: _serde::ser::Serializer - $body + { + #body + } } }; - ).unwrap() + }) } // All the generics in the input, plus a bound `T: Serialize` for each generic // field type that will be serialized by us. -fn build_impl_generics( - builder: &aster::AstBuilder, - item: &Item, -) -> ast::Generics { +fn build_impl_generics(item: &Item) -> syn::Generics { let generics = bound::without_defaults(item.generics); let generics = bound::with_where_predicates_from_fields( - builder, item, &generics, + item, &generics, |attrs| attrs.ser_bound()); match item.attrs.ser_bound() { Some(predicates) => { - bound::with_where_predicates(builder, &generics, predicates) + bound::with_where_predicates(&generics, predicates) } None => { - bound::with_bound(builder, item, &generics, + bound::with_bound(item, &generics, needs_serialize_bound, - &builder.path().ids(&["_serde", "ser", "Serialize"]).build()) + &aster::path().ids(&["_serde", "ser", "Serialize"]).build()) } } } @@ -112,18 +72,14 @@ fn needs_serialize_bound(attrs: &attr::Field) -> bool { } fn serialize_body( - cx: &ExtCtxt, - builder: &aster::AstBuilder, item: &Item, - impl_generics: &ast::Generics, - ty: P, -) -> P { + impl_generics: &syn::Generics, + ty: syn::Ty, +) -> Tokens { match item.body { Body::Enum(ref variants) => { serialize_item_enum( - cx, - builder, - item.ident, + &item.ident, impl_generics, ty, variants, @@ -131,12 +87,10 @@ fn serialize_body( } Body::Struct(Style::Struct, ref fields) => { if fields.iter().any(|field| field.ident.is_none()) { - cx.span_bug(item.span, "struct has unnamed fields") + panic!("struct has unnamed fields"); } serialize_struct( - cx, - builder, impl_generics, ty, fields, @@ -144,12 +98,10 @@ fn serialize_body( } Body::Struct(Style::Tuple, ref fields) => { if fields.iter().any(|field| field.ident.is_some()) { - cx.span_bug(item.span, "tuple struct has named fields") + panic!("tuple struct has named fields"); } serialize_tuple_struct( - cx, - builder, impl_generics, ty, fields, @@ -157,8 +109,6 @@ fn serialize_body( } Body::Struct(Style::Newtype, ref fields) => { serialize_newtype_struct( - cx, - builder, impl_generics, ty, &fields[0], @@ -166,129 +116,116 @@ fn serialize_body( } Body::Struct(Style::Unit, _) => { serialize_unit_struct( - cx, - builder, &item.attrs) } } } -fn serialize_unit_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - item_attrs: &attr::Item, -) -> P { - let type_name = name_expr(builder, item_attrs.name()); +fn serialize_unit_struct(item_attrs: &attr::Item) -> Tokens { + let type_name = item_attrs.name().serialize_name(); - quote_block!(cx, { - _serializer.serialize_unit_struct($type_name) - }).unwrap() + quote! { + _serializer.serialize_unit_struct(#type_name) + } } fn serialize_newtype_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - impl_generics: &ast::Generics, - item_ty: P, + impl_generics: &syn::Generics, + item_ty: syn::Ty, field: &Field, item_attrs: &attr::Item, -) -> P { - let type_name = name_expr(builder, item_attrs.name()); +) -> Tokens { + let type_name = item_attrs.name().serialize_name(); - let mut field_expr = quote_expr!(cx, &self.0); + let mut field_expr = quote!(&self.0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(cx, builder, - &item_ty, impl_generics, &field.ty, path, field_expr); + field_expr = wrap_serialize_with( + &item_ty, impl_generics, field.ty, path, field_expr); } - quote_block!(cx, { - _serializer.serialize_newtype_struct($type_name, $field_expr) - }).unwrap() + quote! { + _serializer.serialize_newtype_struct(#type_name, #field_expr) + } } fn serialize_tuple_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - impl_generics: &ast::Generics, - ty: P, + impl_generics: &syn::Generics, + ty: syn::Ty, fields: &[Field], item_attrs: &attr::Item, -) -> P { +) -> Tokens { let serialize_stmts = serialize_tuple_struct_visitor( - cx, - builder, ty.clone(), fields, impl_generics, false, - cx.ident_of("serialize_tuple_struct_elt"), + aster::id("serialize_tuple_struct_elt"), ); - let type_name = name_expr(builder, item_attrs.name()); + let type_name = item_attrs.name().serialize_name(); let len = serialize_stmts.len(); + let let_mut = mut_if(len > 0); - quote_block!(cx, { - let mut state = try!(_serializer.serialize_tuple_struct($type_name, $len)); - $serialize_stmts - _serializer.serialize_tuple_struct_end(state) - }).unwrap() + quote! { + let #let_mut __serde_state = try!(_serializer.serialize_tuple_struct(#type_name, #len)); + #(#serialize_stmts)* + _serializer.serialize_tuple_struct_end(__serde_state) + } } fn serialize_struct( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - impl_generics: &ast::Generics, - ty: P, + impl_generics: &syn::Generics, + ty: syn::Ty, fields: &[Field], item_attrs: &attr::Item, -) -> P { +) -> Tokens { let serialize_fields = serialize_struct_visitor( - cx, - builder, ty.clone(), fields, impl_generics, false, - cx.ident_of("serialize_struct_elt"), + aster::id("serialize_struct_elt"), ); - let type_name = name_expr(builder, item_attrs.name()); - let len = fields.iter() + let type_name = item_attrs.name().serialize_name(); + + let mut serialized_fields = fields.iter() .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields .map(|field| { - let ident = field.ident.expect("struct has unnamed fields"); - let field_expr = quote_expr!(cx, &self.$ident); + let ident = field.ident.clone().expect("struct has unnamed fields"); + let field_expr = quote!(&self.#ident); match field.attrs.skip_serializing_if() { - Some(path) => quote_expr!(cx, if $path($field_expr) { 0 } else { 1 }), - None => quote_expr!(cx, 1), + Some(path) => quote!(if #path(#field_expr) { 0 } else { 1 }), + None => quote!(1), } }) - .fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr)); + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); - quote_block!(cx, { - let mut state = try!(_serializer.serialize_struct($type_name, $len)); - $serialize_fields - _serializer.serialize_struct_end(state) - }).unwrap() + quote! { + let #let_mut __serde_state = try!(_serializer.serialize_struct(#type_name, #len)); + #(#serialize_fields)* + _serializer.serialize_struct_end(__serde_state) + } } fn serialize_item_enum( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - impl_generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + impl_generics: &syn::Generics, + ty: syn::Ty, variants: &[Variant], item_attrs: &attr::Item, -) -> P { +) -> Tokens { let arms: Vec<_> = variants.iter() .enumerate() .map(|(variant_index, variant)| { serialize_variant( - cx, - builder, type_ident, impl_generics, ty.clone(), @@ -299,341 +236,335 @@ fn serialize_item_enum( }) .collect(); - quote_block!(cx, { + quote! { match *self { - $arms + #(#arms)* } - }).unwrap() + } } fn serialize_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_ident: Ident, - generics: &ast::Generics, - ty: P, + type_ident: &syn::Ident, + generics: &syn::Generics, + ty: syn::Ty, variant: &Variant, variant_index: usize, item_attrs: &attr::Item, -) -> ast::Arm { - let type_name = name_expr(builder, item_attrs.name()); +) -> Tokens { + let type_name = item_attrs.name().serialize_name(); - let variant_ident = variant.ident; - let variant_name = name_expr(builder, variant.attrs.name()); + let variant_ident = variant.ident.clone(); + let variant_name = variant.attrs.name().serialize_name(); - match variant.style { - Style::Unit => { - quote_arm!(cx, - $type_ident::$variant_ident => - _serde::ser::Serializer::serialize_unit_variant( - _serializer, - $type_name, - $variant_index, - $variant_name, - ), - ) - }, - Style::Newtype => { - let block = serialize_newtype_variant( - cx, - builder, - type_name, - variant_index, - variant_name, - ty, - generics, - &variant.fields[0], - ); - - quote_arm!(cx, - $type_ident::$variant_ident(ref __simple_value) => $block - ) - }, - Style::Tuple => { - let field_names: Vec = (0 .. variant.fields.len()) - .map(|i| builder.id(format!("__field{}", i))) - .collect(); - - let pat = builder.pat().enum_() - .id(type_ident).id(variant_ident).build() - .with_pats( - field_names.iter() - .map(|field| builder.pat().ref_id(field)) - ) - .build(); - - let block = serialize_tuple_variant( - cx, - builder, - type_name, - variant_index, - variant_name, - generics, - ty, - &variant.fields, - ); - - quote_arm!(cx, - $pat => $block - ) + if variant.attrs.skip_serializing() { + let skipped_msg = format!("The enum variant {}::{} cannot be serialized", + type_ident, variant_ident); + let skipped_err = quote! { + Err(_serde::ser::Error::invalid_value(#skipped_msg)) + }; + let fields_pat = match variant.style { + Style::Unit => quote!(), + Style::Newtype | Style::Tuple => quote!( (..) ), + Style::Struct => quote!( {..} ), + }; + quote! { + #type_ident::#variant_ident #fields_pat => #skipped_err, } - Style::Struct => { - let mut pat = builder.pat().struct_().id(type_ident).id(variant_ident).build(); - for field in &variant.fields { - let name = match field.ident { - Some(name) => name, - None => cx.span_bug(field.span, "struct variant has unnamed fields"), - }; - pat = pat.with_field_pat(ast::FieldPat { - ident: name, - pat: builder.pat().ref_id(name), - is_shorthand: true, - }); + } else { // variant wasn't skipped + match variant.style { + Style::Unit => { + quote! { + #type_ident::#variant_ident => + _serde::ser::Serializer::serialize_unit_variant( + _serializer, + #type_name, + #variant_index, + #variant_name, + ), + } + }, + Style::Newtype => { + let block = serialize_newtype_variant( + type_name, + variant_index, + variant_name, + ty, + generics, + &variant.fields[0], + ); + + quote! { + #type_ident::#variant_ident(ref __simple_value) => #block, + } + }, + Style::Tuple => { + let field_names = (0 .. variant.fields.len()) + .map(|i| aster::id(format!("__field{}", i))); + + let block = serialize_tuple_variant( + type_name, + variant_index, + variant_name, + generics, + ty, + &variant.fields, + ); + + quote! { + #type_ident::#variant_ident(#(ref #field_names),*) => { #block } + } } - let pat = pat.build(); + Style::Struct => { + let fields = variant.fields.iter() + .map(|f| f.ident.clone().expect("struct variant has unnamed fields")); - let block = serialize_struct_variant( - cx, - builder, - variant_index, - variant_name, - generics, - ty, - &variant.fields, - item_attrs, - ); + let block = serialize_struct_variant( + variant_index, + variant_name, + generics, + ty, + &variant.fields, + item_attrs, + ); - quote_arm!(cx, - $pat => $block - ) + quote! { + #type_ident::#variant_ident { #(ref #fields),* } => { #block } + } + } } } } fn serialize_newtype_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_name: P, + type_name: String, variant_index: usize, - variant_name: P, - item_ty: P, - generics: &ast::Generics, + variant_name: String, + item_ty: syn::Ty, + generics: &syn::Generics, field: &Field, -) -> P { - let mut field_expr = quote_expr!(cx, __simple_value); +) -> Tokens { + let mut field_expr = quote!(__simple_value); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(cx, builder, - &item_ty, generics, &field.ty, path, field_expr); + field_expr = wrap_serialize_with( + &item_ty, generics, field.ty, path, field_expr); } - quote_block!(cx, { + quote! { _serde::ser::Serializer::serialize_newtype_variant( _serializer, - $type_name, - $variant_index, - $variant_name, - $field_expr, + #type_name, + #variant_index, + #variant_name, + #field_expr, ) - }).unwrap() + } } fn serialize_tuple_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - type_name: P, + type_name: String, variant_index: usize, - variant_name: P, - generics: &ast::Generics, - structure_ty: P, + variant_name: String, + generics: &syn::Generics, + structure_ty: syn::Ty, fields: &[Field], -) -> P { +) -> Tokens { let serialize_stmts = serialize_tuple_struct_visitor( - cx, - builder, structure_ty, fields, generics, true, - cx.ident_of("serialize_tuple_variant_elt"), + aster::id("serialize_tuple_variant_elt"), ); let len = serialize_stmts.len(); + let let_mut = mut_if(len > 0); - quote_block!(cx, { - let mut state = try!(_serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, $len)); - $serialize_stmts - _serializer.serialize_tuple_variant_end(state) - }).unwrap() + quote! { + let #let_mut __serde_state = try!(_serializer.serialize_tuple_variant( + #type_name, + #variant_index, + #variant_name, + #len)); + #(#serialize_stmts)* + _serializer.serialize_tuple_variant_end(__serde_state) + } } fn serialize_struct_variant( - cx: &ExtCtxt, - builder: &aster::AstBuilder, variant_index: usize, - variant_name: P, - generics: &ast::Generics, - ty: P, + variant_name: String, + generics: &syn::Generics, + ty: syn::Ty, fields: &[Field], item_attrs: &attr::Item, -) -> P { - +) -> Tokens { let serialize_fields = serialize_struct_visitor( - cx, - builder, ty.clone(), fields, - &generics, + generics, true, - cx.ident_of("serialize_struct_variant_elt"), + aster::id("serialize_struct_variant_elt"), ); - let item_name = name_expr(builder, item_attrs.name()); - let len = fields.iter() + let item_name = item_attrs.name().serialize_name(); + + let mut serialized_fields = fields.iter() .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields .map(|field| { - let ident = field.ident.expect("struct has unnamed fields"); - let field_expr = quote_expr!(cx, $ident); + let ident = field.ident.clone().expect("struct has unnamed fields"); match field.attrs.skip_serializing_if() { - Some(path) => quote_expr!(cx, if $path($field_expr) { 0 } else { 1 }), - None => quote_expr!(cx, 1), + Some(path) => quote!(if #path(#ident) { 0 } else { 1 }), + None => quote!(1), } }) - .fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr)); + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); - quote_block!(cx, { - let mut state = try!(_serializer.serialize_struct_variant( - $item_name, - $variant_index, - $variant_name, - $len, + quote! { + let #let_mut __serde_state = try!(_serializer.serialize_struct_variant( + #item_name, + #variant_index, + #variant_name, + #len, )); - $serialize_fields - _serializer.serialize_struct_variant_end(state) - }).unwrap() + #(#serialize_fields)* + _serializer.serialize_struct_variant_end(__serde_state) + } } fn serialize_tuple_struct_visitor( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - structure_ty: P, + structure_ty: syn::Ty, fields: &[Field], - generics: &ast::Generics, + generics: &syn::Generics, is_enum: bool, - func: ast::Ident, -) -> Vec { + func: syn::Ident, +) -> Vec { fields.iter() .enumerate() .map(|(i, field)| { let mut field_expr = if is_enum { - builder.expr().path().id(format!("__field{}", i)).build() + let id = aster::id(format!("__field{}", i)); + quote!(#id) } else { - builder.expr().ref_().tup_field(i).self_() + let i = aster::id(i); + quote!(&self.#i) }; let skip = field.attrs.skip_serializing_if() - .map(|path| quote_expr!(cx, $path($field_expr))) - .unwrap_or(quote_expr!(cx, false)); + .map(|path| quote!(#path(#field_expr))); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(cx, builder, - &structure_ty, generics, &field.ty, path, field_expr); + field_expr = wrap_serialize_with( + &structure_ty, generics, field.ty, path, field_expr); } - quote_stmt!(cx, - if !$skip { - try!(_serializer.$func(&mut state, $field_expr)); - } - ).unwrap() + let ser = quote! { + try!(_serializer.#func(&mut __serde_state, #field_expr)); + }; + + match skip { + None => ser, + Some(skip) => quote!(if !#skip { #ser }), + } }) .collect() } fn serialize_struct_visitor( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - structure_ty: P, + structure_ty: syn::Ty, fields: &[Field], - generics: &ast::Generics, + generics: &syn::Generics, is_enum: bool, - func: ast::Ident, -) -> Vec { + func: syn::Ident, +) -> Vec { fields.iter() .filter(|&field| !field.attrs.skip_serializing()) .map(|field| { - let ident = field.ident.expect("struct has unnamed field"); + let ident = field.ident.clone().expect("struct has unnamed field"); let mut field_expr = if is_enum { - quote_expr!(cx, $ident) + quote!(#ident) } else { - quote_expr!(cx, &self.$ident) + quote!(&self.#ident) }; - let key_expr = name_expr(builder, field.attrs.name()); + let key_expr = field.attrs.name().serialize_name(); let skip = field.attrs.skip_serializing_if() - .map(|path| quote_expr!(cx, $path($field_expr))) - .unwrap_or(quote_expr!(cx, false)); + .map(|path| quote!(#path(#field_expr))); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(cx, builder, - &structure_ty, generics, &field.ty, path, field_expr) + field_expr = wrap_serialize_with( + &structure_ty, generics, field.ty, path, field_expr) } - quote_stmt!(cx, - if !$skip { - try!(_serializer.$func(&mut state, $key_expr, $field_expr)); - } - ).unwrap() + let ser = quote! { + try!(_serializer.#func(&mut __serde_state, #key_expr, #field_expr)); + }; + + match skip { + None => ser, + Some(skip) => quote!(if !#skip { #ser }), + } }) .collect() } fn wrap_serialize_with( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - item_ty: &P, - generics: &ast::Generics, - field_ty: &P, - path: &ast::Path, - value: P, -) -> P { + item_ty: &syn::Ty, + generics: &syn::Generics, + field_ty: &syn::Ty, + path: &syn::Path, + value: Tokens, +) -> Tokens { let where_clause = &generics.where_clause; - let wrapper_generics = builder.from_generics(generics.clone()) + let wrapper_generics = aster::from_generics(generics.clone()) .add_lifetime_bound("'__a") .lifetime_name("'__a") .build(); - let wrapper_ty = builder.path() + let wrapper_ty = aster::path() .segment("__SerializeWith") .with_generics(wrapper_generics.clone()) .build() .build(); - quote_expr!(cx, { - struct __SerializeWith $wrapper_generics $where_clause { - value: &'__a $field_ty, - phantom: ::std::marker::PhantomData<$item_ty>, + quote!({ + struct __SerializeWith #wrapper_generics #where_clause { + value: &'__a #field_ty, + phantom: ::std::marker::PhantomData<#item_ty>, } - impl $wrapper_generics _serde::ser::Serialize for $wrapper_ty $where_clause { - fn serialize<__S>(&self, __s: &mut __S) -> Result<(), __S::Error> + impl #wrapper_generics _serde::ser::Serialize for #wrapper_ty #where_clause { + fn serialize<__S>(&self, __s: &mut __S) -> ::std::result::Result<(), __S::Error> where __S: _serde::ser::Serializer { - $path(self.value, __s) + #path(self.value, __s) } } __SerializeWith { - value: $value, - phantom: ::std::marker::PhantomData::<$item_ty>, + value: #value, + phantom: ::std::marker::PhantomData::<#item_ty>, } }) } -fn name_expr( - builder: &aster::AstBuilder, - name: &attr::Name, -) -> P { - builder.expr().str(name.serialize_name()) +// Serialization of an empty struct results in code like: +// +// let mut __serde_state = try!(serializer.serialize_struct("S", 0)); +// serializer.serialize_struct_end(__serde_state) +// +// where we want to omit the `mut` to avoid a warning. +fn mut_if(is_mut: bool) -> Option { + if is_mut { + Some(quote!(mut)) + } else { + None + } } diff --git a/serde_codegen/src/span.rs b/serde_codegen/src/span.rs deleted file mode 100644 index 5421868d..00000000 --- a/serde_codegen/src/span.rs +++ /dev/null @@ -1,43 +0,0 @@ -use syntax::ast; -use syntax::codemap::{self, ExpnId, Span}; -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::fold::{self, Folder}; -use syntax::parse::token::intern; -use syntax::ptr::P; - -pub fn record_expansion( - cx: &ExtCtxt, - item: P, - derive: &str, -) -> Annotatable { - let info = codemap::ExpnInfo { - call_site: codemap::DUMMY_SP, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", derive))), - span: None, - allow_internal_unstable: false, - }, - }; - let expn_id = cx.codemap().record_expansion(info); - - let mut respanner = Respanner { expn_id: expn_id }; - let item = item.map(|item| respanner.fold_item_simple(item)); - Annotatable::Item(item) -} - -struct Respanner { - expn_id: ExpnId, -} - -impl Folder for Respanner { - fn new_span(&mut self, span: Span) -> Span { - Span { - expn_id: self.expn_id, - .. span - } - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } -} diff --git a/serde_codegen_internals/Cargo.toml b/serde_codegen_internals/Cargo.toml index 95750d3e..f98310f2 100644 --- a/serde_codegen_internals/Cargo.toml +++ b/serde_codegen_internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_codegen_internals" -version = "0.7.0" +version = "0.11.3" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "AST representation used by Serde codegen. Unstable." @@ -10,12 +10,11 @@ documentation = "https://docs.serde.rs/serde_codegen_internals/" keywords = ["serde", "serialization"] include = ["Cargo.toml", "src/**/*.rs"] +publish = false # this branch contains breaking changes for 0.9 + [features] -default = ["with-syntex"] unstable-testing = ["clippy"] -with-syntex = ["syntex_syntax", "syntex_errors"] [dependencies] clippy = { version = "^0.*", optional = true } -syntex_syntax = { version = "^0.42.0", optional = true } -syntex_errors = { version = "^0.42.0", optional = true } +syn = "0.10" diff --git a/serde_codegen_internals/src/ast.rs b/serde_codegen_internals/src/ast.rs index dd79944f..2941c164 100644 --- a/serde_codegen_internals/src/ast.rs +++ b/serde_codegen_internals/src/ast.rs @@ -1,17 +1,12 @@ -use syntax::ast; -use syntax::codemap; -use syntax::ext::base::ExtCtxt; -use syntax::ptr::P; - +use syn; use attr; -use Error; +use Ctxt; pub struct Item<'a> { - pub ident: ast::Ident, - pub span: codemap::Span, + pub ident: syn::Ident, pub attrs: attr::Item, pub body: Body<'a>, - pub generics: &'a ast::Generics, + pub generics: &'a syn::Generics, } pub enum Body<'a> { @@ -20,18 +15,16 @@ pub enum Body<'a> { } pub struct Variant<'a> { - pub ident: ast::Ident, - pub span: codemap::Span, + pub ident: syn::Ident, pub attrs: attr::Variant, pub style: Style, pub fields: Vec>, } pub struct Field<'a> { - pub ident: Option, - pub span: codemap::Span, + pub ident: Option, pub attrs: attr::Field, - pub ty: &'a P, + pub ty: &'a syn::Ty, } pub enum Style { @@ -42,33 +35,25 @@ pub enum Style { } impl<'a> Item<'a> { - pub fn from_ast( - cx: &ExtCtxt, - item: &'a ast::Item, - ) -> Result, Error> { + pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Item<'a> { let attrs = attr::Item::from_ast(cx, item); - let (body, generics) = match item.node { - ast::ItemKind::Enum(ref enum_def, ref generics) => { - let variants = enum_from_ast(cx, enum_def); - (Body::Enum(variants), generics) + let body = match item.body { + syn::Body::Enum(ref variants) => { + Body::Enum(enum_from_ast(cx, variants)) } - ast::ItemKind::Struct(ref variant_data, ref generics) => { + syn::Body::Struct(ref variant_data) => { let (style, fields) = struct_from_ast(cx, variant_data); - (Body::Struct(style, fields), generics) - } - _ => { - return Err(Error::UnexpectedItemKind); + Body::Struct(style, fields) } }; - Ok(Item { - ident: item.ident, - span: item.span, + Item { + ident: item.ident.clone(), attrs: attrs, body: body, - generics: generics, - }) + generics: &item.generics, + } } } @@ -86,16 +71,12 @@ impl<'a> Body<'a> { } } -fn enum_from_ast<'a>( - cx: &ExtCtxt, - enum_def: &'a ast::EnumDef, -) -> Vec> { - enum_def.variants.iter() +fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec> { + variants.iter() .map(|variant| { - let (style, fields) = struct_from_ast(cx, &variant.node.data); + let (style, fields) = struct_from_ast(cx, &variant.data); Variant { - ident: variant.node.name, - span: variant.span, + ident: variant.ident.clone(), attrs: attr::Variant::from_ast(cx, variant), style: style, fields: fields, @@ -104,36 +85,29 @@ fn enum_from_ast<'a>( .collect() } -fn struct_from_ast<'a>( - cx: &ExtCtxt, - variant_data: &'a ast::VariantData, -) -> (Style, Vec>) { - match *variant_data { - ast::VariantData::Struct(ref fields, _) => { +fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec>) { + match *data { + syn::VariantData::Struct(ref fields) => { (Style::Struct, fields_from_ast(cx, fields)) } - ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => { + syn::VariantData::Tuple(ref fields) if fields.len() == 1 => { (Style::Newtype, fields_from_ast(cx, fields)) } - ast::VariantData::Tuple(ref fields, _) => { + syn::VariantData::Tuple(ref fields) => { (Style::Tuple, fields_from_ast(cx, fields)) } - ast::VariantData::Unit(_) => { + syn::VariantData::Unit => { (Style::Unit, Vec::new()) } } } -fn fields_from_ast<'a>( - cx: &ExtCtxt, - fields: &'a [ast::StructField], -) -> Vec> { +fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec> { fields.iter() .enumerate() .map(|(i, field)| { Field { - ident: field.ident, - span: field.span, + ident: field.ident.clone(), attrs: attr::Field::from_ast(cx, i, field), ty: &field.ty, } diff --git a/serde_codegen_internals/src/attr.rs b/serde_codegen_internals/src/attr.rs index 8d8d595b..632dd508 100644 --- a/serde_codegen_internals/src/attr.rs +++ b/serde_codegen_internals/src/attr.rs @@ -1,16 +1,7 @@ -use std::rc::Rc; - -use syntax::ast; -use syntax::attr::{self, HasAttrs}; -use syntax::codemap::{Span, Spanned, respan}; -use syntax::ext::base::ExtCtxt; -use syntax::fold::Folder; -use syntax::parse::parser::{Parser, PathStyle}; -use syntax::parse::token::{self, InternedString}; -use syntax::parse; -use syntax::print::pprust::{lit_to_string, meta_item_to_string}; -use syntax::ptr::P; -use syntax::tokenstream::{self, TokenTree}; +use Ctxt; +use syn; +use syn::MetaItem::{List, NameValue, Word}; +use syn::NestedMetaItem::{Literal, MetaItem}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints // are `attr::Item::from_ast`, `attr::Variant::from_ast`, and @@ -20,13 +11,14 @@ use syntax::tokenstream::{self, TokenTree}; // user will see errors simultaneously for all bad attributes in the crate // rather than just the first. -struct Attr<'a, 'b: 'a, T> { - cx: &'a ExtCtxt<'b>, +struct Attr<'c, T> { + cx: &'c Ctxt, name: &'static str, - value: Option>, + value: Option, } -impl<'a, 'b, T> Attr<'a, 'b, T> { - fn none(cx: &'a ExtCtxt<'b>, name: &'static str) -> Self { + +impl<'c, T> Attr<'c, T> { + fn none(cx: &'c Ctxt, name: &'static str) -> Self { Attr { cx: cx, name: name, @@ -34,47 +26,40 @@ impl<'a, 'b, T> Attr<'a, 'b, T> { } } - fn set(&mut self, span: Span, t: T) { - if let Some(Spanned { span: prev_span, .. }) = self.value { - let mut err = self.cx.struct_span_err( - span, - &format!("duplicate serde attribute `{}`", self.name)); - err.span_help(prev_span, "previously set here"); - err.emit(); + fn set(&mut self, value: T) { + if self.value.is_some() { + self.cx.error(format!("duplicate serde attribute `{}`", self.name)); } else { - self.value = Some(respan(span, t)); + self.value = Some(value); } } - fn set_opt(&mut self, v: Option>) { - if let Some(v) = v { - self.set(v.span, v.node); + fn set_opt(&mut self, value: Option) { + if let Some(value) = value { + self.set(value); } } - fn set_if_none(&mut self, span: Span, t: T) { + fn set_if_none(&mut self, value: T) { if self.value.is_none() { - self.value = Some(respan(span, t)); + self.value = Some(value); } } fn get(self) -> Option { - self.value.map(|spanned| spanned.node) - } - - fn get_spanned(self) -> Option> { self.value } } -struct BoolAttr<'a, 'b: 'a>(Attr<'a, 'b, ()>); -impl<'a, 'b> BoolAttr<'a, 'b> { - fn none(cx: &'a ExtCtxt<'b>, name: &'static str) -> Self { +struct BoolAttr<'c>(Attr<'c, ()>); + +impl<'c> BoolAttr<'c> { + fn none(cx: &'c Ctxt, name: &'static str) -> Self { BoolAttr(Attr::none(cx, name)) } - fn set_true(&mut self, span: Span) { - self.0.set(span, ()); + fn set_true(&mut self) { + self.0.set(()); } fn get(&self) -> bool { @@ -84,18 +69,18 @@ impl<'a, 'b> BoolAttr<'a, 'b> { #[derive(Debug)] pub struct Name { - serialize: InternedString, - deserialize: InternedString, + serialize: String, + deserialize: String, } impl Name { /// Return the container name for the container when serializing. - pub fn serialize_name(&self) -> InternedString { + pub fn serialize_name(&self) -> String { self.serialize.clone() } /// Return the container name for the container when deserializing. - pub fn deserialize_name(&self) -> InternedString { + pub fn deserialize_name(&self) -> String { self.deserialize.clone() } } @@ -105,35 +90,32 @@ impl Name { pub struct Item { name: Name, deny_unknown_fields: bool, - ser_bound: Option>, - de_bound: Option>, + ser_bound: Option>, + de_bound: Option>, } impl Item { /// Extract out the `#[serde(...)]` attributes from an item. - pub fn from_ast(cx: &ExtCtxt, item: &ast::Item) -> Self { + pub fn from_ast(cx: &Ctxt, item: &syn::MacroInput) -> Self { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); let mut ser_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound"); - let ident = item.ident.name.as_str(); - - for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) { + for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { - let span = meta_item.span; - match meta_item.node { + match meta_item { // Parse `#[serde(rename="foo")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { - if let Ok(s) = get_str_from_lit(cx, name, lit) { - ser_name.set(span, s.clone()); - de_name.set(span, s); + MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { + if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + ser_name.set(s.clone()); + de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` - ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { + MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); @@ -141,31 +123,33 @@ impl Item { } // Parse `#[serde(deny_unknown_fields)]` - ast::MetaItemKind::Word(ref name) if name == &"deny_unknown_fields" => { - deny_unknown_fields.set_true(span); + MetaItem(Word(ref name)) if name == "deny_unknown_fields" => { + deny_unknown_fields.set_true(); } // Parse `#[serde(bound="D: Serialize")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => { - if let Ok(where_predicates) = parse_lit_into_where(cx, name, lit) { - ser_bound.set(span, where_predicates.clone()); - de_bound.set(span, where_predicates); + MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { + if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { + ser_bound.set(where_predicates.clone()); + de_bound.set(where_predicates); } } // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` - ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => { + MetaItem(List(ref name, ref meta_items)) if name == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } - _ => { - cx.span_err( - meta_item.span, - &format!("unknown serde container attribute `{}`", - meta_item_to_string(meta_item))); + MetaItem(ref meta_item) => { + cx.error(format!("unknown serde container attribute `{}`", + meta_item.name())); + } + + Literal(_) => { + cx.error(format!("unexpected literal in serde container attribute")); } } } @@ -173,8 +157,8 @@ impl Item { Item { name: Name { - serialize: ser_name.get().unwrap_or(ident.clone()), - deserialize: de_name.get().unwrap_or(ident), + serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()), + deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()), }, deny_unknown_fields: deny_unknown_fields.get(), ser_bound: ser_bound.get(), @@ -190,11 +174,11 @@ impl Item { self.deny_unknown_fields } - pub fn ser_bound(&self) -> Option<&[ast::WherePredicate]> { + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { self.ser_bound.as_ref().map(|vec| &vec[..]) } - pub fn de_bound(&self) -> Option<&[ast::WherePredicate]> { + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { self.de_bound.as_ref().map(|vec| &vec[..]) } } @@ -203,40 +187,51 @@ impl Item { #[derive(Debug)] pub struct Variant { name: Name, + skip_deserializing: bool, + skip_serializing: bool, } impl Variant { - pub fn from_ast(cx: &ExtCtxt, variant: &ast::Variant) -> Self { + pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename"); + let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); + let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); - let ident = variant.node.name.name.as_str(); - - for meta_items in variant.node.attrs.iter().filter_map(get_serde_meta_items) { + for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { - let span = meta_item.span; - match meta_item.node { + match meta_item { // Parse `#[serde(rename="foo")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { - if let Ok(s) = get_str_from_lit(cx, name, lit) { - ser_name.set(span, s.clone()); - de_name.set(span, s); + MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { + if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + ser_name.set(s.clone()); + de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` - ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { + MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); } } + // Parse `#[serde(skip_deserializing)]` + MetaItem(Word(ref name)) if name == "skip_deserializing" => { + skip_deserializing.set_true(); + } + // Parse `#[serde(skip_serializing)]` + MetaItem(Word(ref name)) if name == "skip_serializing" => { + skip_serializing.set_true(); + } - _ => { - cx.span_err( - meta_item.span, - &format!("unknown serde variant attribute `{}`", - meta_item_to_string(meta_item))); + MetaItem(ref meta_item) => { + cx.error(format!("unknown serde variant attribute `{}`", + meta_item.name())); + } + + Literal(_) => { + cx.error(format!("unexpected literal in serde variant attribute")); } } } @@ -244,15 +239,25 @@ impl Variant { Variant { name: Name { - serialize: ser_name.get().unwrap_or(ident.clone()), - deserialize: de_name.get().unwrap_or(ident), + serialize: ser_name.get().unwrap_or_else(|| variant.ident.to_string()), + deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()), }, + skip_deserializing: skip_deserializing.get(), + skip_serializing: skip_serializing.get(), } } pub fn name(&self) -> &Name { &self.name } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } } /// Represents field attribute information @@ -261,12 +266,12 @@ pub struct Field { name: Name, skip_serializing: bool, skip_deserializing: bool, - skip_serializing_if: Option, + skip_serializing_if: Option, default: FieldDefault, - serialize_with: Option, - deserialize_with: Option, - ser_bound: Option>, - de_bound: Option>, + serialize_with: Option, + deserialize_with: Option, + ser_bound: Option>, + de_bound: Option>, } /// Represents the default to use for a field when deserializing. @@ -277,14 +282,14 @@ pub enum FieldDefault { /// The default is given by `std::default::Default::default()`. Default, /// The default is given by this function. - Path(ast::Path), + Path(syn::Path), } impl Field { /// Extract out the `#[serde(...)]` attributes from a struct field. - pub fn from_ast(cx: &ExtCtxt, + pub fn from_ast(cx: &Ctxt, index: usize, - field: &ast::StructField) -> Self { + field: &syn::Field) -> Self { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); @@ -297,24 +302,23 @@ impl Field { let mut de_bound = Attr::none(cx, "bound"); let ident = match field.ident { - Some(ident) => ident.name.as_str(), - None => token::intern_and_get_ident(&index.to_string()), + Some(ref ident) => ident.to_string(), + None => index.to_string(), }; for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { - let span = meta_item.span; - match meta_item.node { + match meta_item { // Parse `#[serde(rename="foo")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { - if let Ok(s) = get_str_from_lit(cx, name, lit) { - ser_name.set(span, s.clone()); - de_name.set(span, s); + MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { + if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + ser_name.set(s.clone()); + de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` - ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { + MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); @@ -322,69 +326,71 @@ impl Field { } // Parse `#[serde(default)]` - ast::MetaItemKind::Word(ref name) if name == &"default" => { - default.set(span, FieldDefault::Default); + MetaItem(Word(ref name)) if name == "default" => { + default.set(FieldDefault::Default); } // Parse `#[serde(default="...")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => { - if let Ok(path) = parse_lit_into_path(cx, name, lit) { - default.set(span, FieldDefault::Path(path)); + MetaItem(NameValue(ref name, ref lit)) if name == "default" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + default.set(FieldDefault::Path(path)); } } // Parse `#[serde(skip_serializing)]` - ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => { - skip_serializing.set_true(span); + MetaItem(Word(ref name)) if name == "skip_serializing" => { + skip_serializing.set_true(); } // Parse `#[serde(skip_deserializing)]` - ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => { - skip_deserializing.set_true(span); + MetaItem(Word(ref name)) if name == "skip_deserializing" => { + skip_deserializing.set_true(); } // Parse `#[serde(skip_serializing_if="...")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => { - if let Ok(path) = parse_lit_into_path(cx, name, lit) { - skip_serializing_if.set(span, path); + MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + skip_serializing_if.set(path); } } // Parse `#[serde(serialize_with="...")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name, lit) { - serialize_with.set(span, path); + MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + serialize_with.set(path); } } // Parse `#[serde(deserialize_with="...")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name, lit) { - deserialize_with.set(span, path); + MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + deserialize_with.set(path); } } // Parse `#[serde(bound="D: Serialize")]` - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => { - if let Ok(where_predicates) = parse_lit_into_where(cx, name, lit) { - ser_bound.set(span, where_predicates.clone()); - de_bound.set(span, where_predicates); + MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { + if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { + ser_bound.set(where_predicates.clone()); + de_bound.set(where_predicates); } } // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` - ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => { + MetaItem(List(ref name, ref meta_items)) if name == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } - _ => { - cx.span_err( - meta_item.span, - &format!("unknown serde field attribute `{}`", - meta_item_to_string(meta_item))); + MetaItem(ref meta_item) => { + cx.error(format!("unknown serde field attribute `{}`", + meta_item.name())); + } + + Literal(_) => { + cx.error(format!("unexpected literal in serde field attribute")); } } } @@ -392,8 +398,8 @@ impl Field { // Is skip_deserializing, initialize the field to Default::default() // unless a different default is specified by `#[serde(default="...")]` - if let Some(Spanned { span, .. }) = skip_deserializing.0.value { - default.set_if_none(span, FieldDefault::Default); + if skip_deserializing.0.value.is_some() { + default.set_if_none(FieldDefault::Default); } Field { @@ -424,7 +430,7 @@ impl Field { self.skip_deserializing } - pub fn skip_serializing_if(&self) -> Option<&ast::Path> { + pub fn skip_serializing_if(&self) -> Option<&syn::Path> { self.skip_serializing_if.as_ref() } @@ -432,209 +438,106 @@ impl Field { &self.default } - pub fn serialize_with(&self) -> Option<&ast::Path> { + pub fn serialize_with(&self) -> Option<&syn::Path> { self.serialize_with.as_ref() } - pub fn deserialize_with(&self) -> Option<&ast::Path> { + pub fn deserialize_with(&self) -> Option<&syn::Path> { self.deserialize_with.as_ref() } - pub fn ser_bound(&self) -> Option<&[ast::WherePredicate]> { + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { self.ser_bound.as_ref().map(|vec| &vec[..]) } - pub fn de_bound(&self) -> Option<&[ast::WherePredicate]> { + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { self.de_bound.as_ref().map(|vec| &vec[..]) } } -type SerAndDe = (Option>, Option>); +type SerAndDe = (Option, Option); fn get_ser_and_de( - cx: &ExtCtxt, - attribute: &'static str, - items: &[P], + cx: &Ctxt, + attr_name: &'static str, + items: &[syn::NestedMetaItem], f: F ) -> Result, ()> - where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result, + where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result, { - let mut ser_item = Attr::none(cx, attribute); - let mut de_item = Attr::none(cx, attribute); + let mut ser_item = Attr::none(cx, attr_name); + let mut de_item = Attr::none(cx, attr_name); for item in items { - match item.node { - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => { - if let Ok(v) = f(cx, name, lit) { - ser_item.set(item.span, v); + match *item { + MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => { + if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { + ser_item.set(v); } } - ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => { - if let Ok(v) = f(cx, name, lit) { - de_item.set(item.span, v); + MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => { + if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { + de_item.set(v); } } _ => { - cx.span_err( - item.span, - &format!("unknown {} attribute `{}`", - attribute, - meta_item_to_string(item))); - + cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", + attr_name)); return Err(()); } } } - Ok((ser_item.get_spanned(), de_item.get_spanned())) + Ok((ser_item.get(), de_item.get())) } fn get_renames( - cx: &ExtCtxt, - items: &[P], -) -> Result, ()> { - get_ser_and_de(cx, "rename", items, get_str_from_lit) + cx: &Ctxt, + items: &[syn::NestedMetaItem], +) -> Result, ()> { + get_ser_and_de(cx, "rename", items, get_string_from_lit) } fn get_where_predicates( - cx: &ExtCtxt, - items: &[P], -) -> Result>, ()> { + cx: &Ctxt, + items: &[syn::NestedMetaItem], +) -> Result>, ()> { get_ser_and_de(cx, "bound", items, parse_lit_into_where) } -pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P]> { - match attr.node.value.node { - ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => { - attr::mark_used(attr); - Some(items) +pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option> { + match attr.value { + List(ref name, ref items) if name == "serde" => { + Some(items.iter().cloned().collect()) } _ => None } } -/// This syntax folder rewrites tokens to say their spans are coming from a macro context. -struct Respanner<'a, 'b: 'a> { - cx: &'a ExtCtxt<'b>, -} - -impl<'a, 'b> Folder for Respanner<'a, 'b> { - fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree { - match *tt { - TokenTree::Token(span, ref tok) => { - TokenTree::Token( - self.new_span(span), - self.fold_token(tok.clone()) - ) - } - TokenTree::Delimited(span, ref delimed) => { - TokenTree::Delimited( - self.new_span(span), - Rc::new(tokenstream::Delimited { - delim: delimed.delim, - open_span: delimed.open_span, - tts: self.fold_tts(&delimed.tts), - close_span: delimed.close_span, - }) - ) - } - TokenTree::Sequence(span, ref seq) => { - TokenTree::Sequence( - self.new_span(span), - Rc::new(tokenstream::SequenceRepetition { - tts: self.fold_tts(&seq.tts), - separator: seq.separator.clone().map(|tok| self.fold_token(tok)), - ..**seq - }) - ) - } - } - } - - fn new_span(&mut self, span: Span) -> Span { - Span { - lo: span.lo, - hi: span.hi, - expn_id: self.cx.backtrace(), - } +fn get_string_from_lit(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result { + if let syn::Lit::Str(ref s, _) = *lit { + Ok(s.clone()) + } else { + cx.error(format!("expected serde {} attribute to be a string: `{} = \"...\"`", + attr_name, meta_item_name)); + Err(()) } } -fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result { - match lit.node { - ast::LitKind::Str(ref s, _) => Ok(s.clone()), - _ => { - cx.span_err( - lit.span, - &format!("serde annotation `{}` must be a string, not `{}`", - name, - lit_to_string(lit))); - - Err(()) - } - } +fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result { + let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); + syn::parse_path(&string).map_err(|err| cx.error(err)) } -// If we just parse a string literal from an attibute, any syntax errors in the -// source will only have spans that point inside the string and not back to the -// attribute. So to have better error reporting, we'll first parse the string -// into a token tree. Then we'll update those spans to say they're coming from a -// macro context that originally came from the attribnute, and then finally -// parse them into an expression or where-clause. -fn parse_string_via_tts(cx: &ExtCtxt, name: &str, string: String, action: F) -> Result - where F: for<'a> Fn(&'a mut Parser) -> parse::PResult<'a, T>, -{ - let tts = panictry!(parse::parse_tts_from_source_str( - format!("", name), - string, - cx.cfg(), - cx.parse_sess())); - - // Respan the spans to say they are all coming from this macro. - let tts = Respanner { cx: cx }.fold_tts(&tts); - - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts); - - let path = match action(&mut parser) { - Ok(path) => path, - Err(mut e) => { - e.emit(); - return Err(()); - } - }; - - // Make sure to error out if there are trailing characters in the stream. - match parser.expect(&token::Eof) { - Ok(()) => { } - Err(mut e) => { - e.emit(); - return Err(()); - } - } - - Ok(path) -} - -fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result { - let string = try!(get_str_from_lit(cx, name, lit)).to_string(); - - parse_string_via_tts(cx, name, string, |parser| { - parser.parse_path(PathStyle::Type) - }) -} - -fn parse_lit_into_where(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result, ()> { - let string = try!(get_str_from_lit(cx, name, lit)); +fn parse_lit_into_where(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result, ()> { + let string = try!(get_string_from_lit(cx, attr_name, meta_item_name, lit)); if string.is_empty() { return Ok(Vec::new()); } let where_string = format!("where {}", string); - parse_string_via_tts(cx, name, where_string, |parser| { - let where_clause = try!(parser.parse_where_clause()); - Ok(where_clause.predicates) - }) + syn::parse_where_clause(&where_string).map(|wh| wh.predicates).map_err(|err| cx.error(err)) } diff --git a/serde_codegen_internals/src/ctxt.rs b/serde_codegen_internals/src/ctxt.rs new file mode 100644 index 00000000..a1455332 --- /dev/null +++ b/serde_codegen_internals/src/ctxt.rs @@ -0,0 +1,43 @@ +use std::fmt::Display; +use std::cell::RefCell; + +#[derive(Default)] +pub struct Ctxt { + errors: RefCell>>, +} + +impl Ctxt { + pub fn new() -> Self { + Ctxt { + errors: RefCell::new(Some(Vec::new())), + } + } + + pub fn error(&self, msg: T) { + self.errors.borrow_mut().as_mut().unwrap().push(msg.to_string()); + } + + pub fn check(self) -> Result<(), String> { + let mut errors = self.errors.borrow_mut().take().unwrap(); + match errors.len() { + 0 => Ok(()), + 1 => Err(errors.pop().unwrap()), + n => { + let mut msg = format!("{} errors:", n); + for err in errors { + msg.push_str("\n\t# "); + msg.push_str(&err); + } + Err(msg) + } + } + } +} + +impl Drop for Ctxt { + fn drop(&mut self) { + if self.errors.borrow().is_some() { + panic!("forgot to check for errors"); + } + } +} diff --git a/serde_codegen_internals/src/error.rs b/serde_codegen_internals/src/error.rs deleted file mode 100644 index 08337c0b..00000000 --- a/serde_codegen_internals/src/error.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::error; -use std::fmt; - -#[derive(Debug)] -pub enum Error { - UnexpectedItemKind, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "expected a struct or enum") - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - "expected a struct or enum" - } -} diff --git a/serde_codegen_internals/src/lib.rs b/serde_codegen_internals/src/lib.rs index 89f20aa6..0f37f5fa 100644 --- a/serde_codegen_internals/src/lib.rs +++ b/serde_codegen_internals/src/lib.rs @@ -1,21 +1,10 @@ #![cfg_attr(feature = "clippy", plugin(clippy))] #![cfg_attr(feature = "clippy", feature(plugin))] -#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] -#[cfg(feature = "with-syntex")] -#[macro_use] -extern crate syntex_syntax as syntax; -#[cfg(feature = "with-syntex")] -extern crate syntex_errors as errors; - -#[cfg(not(feature = "with-syntex"))] -#[macro_use] -extern crate syntax; -#[cfg(not(feature = "with-syntex"))] -extern crate rustc_errors as errors; +extern crate syn; pub mod ast; pub mod attr; -mod error; -pub use error::Error; +mod ctxt; +pub use ctxt::Ctxt; diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml new file mode 100644 index 00000000..2765340b --- /dev/null +++ b/serde_derive/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "serde_derive" +version = "0.8.21" +authors = ["Erick Tryzelaar "] +license = "MIT/Apache-2.0" +description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" +homepage = "https://serde.rs" +repository = "https://github.com/serde-rs/serde" +documentation = "https://serde.rs/codegen.html" +keywords = ["serde", "serialization"] +include = ["Cargo.toml", "src/**/*.rs"] + +publish = false # this branch contains breaking changes for 0.9 + +[lib] +name = "serde_derive" +proc-macro = true + +[dependencies.serde_codegen] +version = "=0.8.21" +path = "../serde_codegen" +default-features = false +features = ["with-syn"] + +[dev-dependencies] +compiletest_rs = "^0.2.0" +fnv = "1.0" +serde = { version = "0.8.21", path = "../serde" } +serde_test = { version = "0.8.21", path = "../serde_test" } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs new file mode 100644 index 00000000..38953f5b --- /dev/null +++ b/serde_derive/src/lib.rs @@ -0,0 +1,20 @@ +extern crate proc_macro; +extern crate serde_codegen; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + match serde_codegen::expand_derive_serialize(&input.to_string()) { + Ok(expanded) => expanded.parse().unwrap(), + Err(msg) => panic!(msg), + } +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + match serde_codegen::expand_derive_deserialize(&input.to_string()) { + Ok(expanded) => expanded.parse().unwrap(), + Err(msg) => panic!(msg), + } +} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/rename-and-ser.rs b/serde_derive/tests/compile-fail/duplicate-attribute/rename-and-ser.rs new file mode 100644 index 00000000..2f904a1f --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/rename-and-ser.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename="x", serialize="y")] //~^^ HELP: unknown serde field attribute `serialize` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/rename-rename-de.rs b/serde_derive/tests/compile-fail/duplicate-attribute/rename-rename-de.rs new file mode 100644 index 00000000..bd7be3ad --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/rename-rename-de.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename="x")] + #[serde(rename(deserialize="y"))] //~^^^ HELP: duplicate serde attribute `rename` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename-ser.rs b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename-ser.rs new file mode 100644 index 00000000..6ca7c8f8 --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename-ser.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename(serialize="x"), rename(serialize="y"))] //~^^ HELP: duplicate serde attribute `rename` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename.rs b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename.rs new file mode 100644 index 00000000..afe343b1 --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-rename.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename(serialize="x"))] + #[serde(rename="y")] //~^^^ HELP: duplicate serde attribute `rename` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-ser.rs b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-ser.rs new file mode 100644 index 00000000..8d50c256 --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/rename-ser-ser.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename(serialize="x", serialize="y"))] //~^^ HELP: duplicate serde attribute `rename` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/duplicate-attribute/two-rename-ser.rs b/serde_derive/tests/compile-fail/duplicate-attribute/two-rename-ser.rs new file mode 100644 index 00000000..94b67cff --- /dev/null +++ b/serde_derive/tests/compile-fail/duplicate-attribute/two-rename-ser.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct S { + #[serde(rename(serialize="x"))] + #[serde(rename(serialize="y"))] //~^^^ HELP: duplicate serde attribute `rename` + x: (), +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/str_ref_deser.rs b/serde_derive/tests/compile-fail/str_ref_deser.rs new file mode 100644 index 00000000..08c9b1f9 --- /dev/null +++ b/serde_derive/tests/compile-fail/str_ref_deser.rs @@ -0,0 +1,9 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize, Deserialize)] //~ ERROR: custom derive attribute panicked +struct Test<'a> { + s: &'a str, //~^^ HELP: Serde does not support deserializing fields of type &str +} + +fn main() {} diff --git a/serde_derive/tests/compile-fail/unknown-attribute/container.rs b/serde_derive/tests/compile-fail/unknown-attribute/container.rs new file mode 100644 index 00000000..59abfe1d --- /dev/null +++ b/serde_derive/tests/compile-fail/unknown-attribute/container.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +#[serde(abc="xyz")] //~^ HELP: unknown serde container attribute `abc` +struct A { + x: u32, +} + +fn main() { } diff --git a/serde_derive/tests/compile-fail/unknown-attribute/field.rs b/serde_derive/tests/compile-fail/unknown-attribute/field.rs new file mode 100644 index 00000000..66142ce3 --- /dev/null +++ b/serde_derive/tests/compile-fail/unknown-attribute/field.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +struct C { + #[serde(abc="xyz")] //~^^ HELP: unknown serde field attribute `abc` + x: u32, +} + +fn main() { } diff --git a/serde_derive/tests/compile-fail/unknown-attribute/variant.rs b/serde_derive/tests/compile-fail/unknown-attribute/variant.rs new file mode 100644 index 00000000..9b95ec0a --- /dev/null +++ b/serde_derive/tests/compile-fail/unknown-attribute/variant.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: custom derive attribute panicked +enum E { + #[serde(abc="xyz")] //~^^ HELP: unknown serde variant attribute `abc` + V, +} + +fn main() { } diff --git a/serde_macros/tests/compile_tests.rs b/serde_derive/tests/compile_tests.rs similarity index 100% rename from serde_macros/tests/compile_tests.rs rename to serde_derive/tests/compile_tests.rs diff --git a/serde_macros/tests/run-pass/identity-op.rs b/serde_derive/tests/run-pass/identity-op.rs similarity index 80% rename from serde_macros/tests/run-pass/identity-op.rs rename to serde_derive/tests/run-pass/identity-op.rs index dcf8117a..e1638025 100644 --- a/serde_macros/tests/run-pass/identity-op.rs +++ b/serde_derive/tests/run-pass/identity-op.rs @@ -1,8 +1,8 @@ -#![feature(custom_derive, plugin)] -#![plugin(serde_macros, clippy)] - #![deny(identity_op)] +#[macro_use] +extern crate serde_derive; + // The derived implementation uses 0+1 to add up the number of fields // serialized, which Clippy warns about. If the expansion info is registered // correctly, the Clippy lint is not triggered. diff --git a/serde_macros/tests/test.rs b/serde_derive/tests/test.rs similarity index 50% rename from serde_macros/tests/test.rs rename to serde_derive/tests/test.rs index e0462787..b1969a8f 100644 --- a/serde_macros/tests/test.rs +++ b/serde_derive/tests/test.rs @@ -1,5 +1,7 @@ -#![feature(test, custom_attribute, custom_derive, plugin)] -#![plugin(serde_macros)] +#![feature(test)] + +#[macro_use] +extern crate serde_derive; extern crate test; diff --git a/serde_macros/.cargo/config b/serde_macros/.cargo/config deleted file mode 100644 index 7f1ab8d3..00000000 --- a/serde_macros/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -# To prevent compiletest from seeing two versions of serde -paths = ["../serde"] diff --git a/serde_macros/.gitignore b/serde_macros/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/serde_macros/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/serde_macros/Cargo.toml b/serde_macros/Cargo.toml deleted file mode 100644 index f9c832d2..00000000 --- a/serde_macros/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "serde_macros" -version = "0.8.4" -authors = ["Erick Tryzelaar "] -license = "MIT/Apache-2.0" -description = "Macros to auto-generate implementations for the serde framework" -homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" -documentation = "https://serde.rs/codegen.html" -keywords = ["serde", "serialization"] -include = ["Cargo.toml", "src/**/*.rs"] - -[lib] -name = "serde_macros" -plugin = true - -[features] -unstable-testing = [ - "clippy", - "serde/unstable-testing", - "serde_codegen/unstable-testing" -] - -[dependencies] -clippy = { version = "^0.*", optional = true } -serde_codegen = { version = "=0.8.4", default-features = false, features = ["unstable"], path = "../serde_codegen" } - -[dev-dependencies] -compiletest_rs = "^0.2.0" -fnv = "1.0" -rustc-serialize = "^0.3.16" -serde = { version = "0.8.4", path = "../serde" } -serde_test = { version = "0.8.4", path = "../serde_test" } - -[[test]] -name = "test" -path = "tests/test.rs" - -[[bench]] -name = "bench" -path = "benches/bench.rs" diff --git a/serde_macros/benches/bench.rs b/serde_macros/benches/bench.rs deleted file mode 100644 index ec15c18c..00000000 --- a/serde_macros/benches/bench.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(custom_attribute, custom_derive, plugin, test)] -#![cfg_attr(feature = "clippy", plugin(clippy))] -#![plugin(serde_macros)] - -extern crate rustc_serialize; -extern crate serde; -extern crate test; - -include!("../../testing/benches/bench.rs.in"); diff --git a/serde_macros/src/lib.rs b/serde_macros/src/lib.rs deleted file mode 100644 index 077fdccf..00000000 --- a/serde_macros/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(plugin_registrar, rustc_private)] -#![cfg_attr(feature = "clippy", feature(plugin))] -#![cfg_attr(feature = "clippy", plugin(clippy))] - -extern crate serde_codegen; -extern crate rustc_plugin; - -#[plugin_registrar] -#[doc(hidden)] -pub fn plugin_registrar(reg: &mut rustc_plugin::Registry) { - serde_codegen::register(reg); -} diff --git a/serde_macros/tests/compile-fail/duplicate_attributes.rs b/serde_macros/tests/compile-fail/duplicate_attributes.rs deleted file mode 100644 index 4c1caab2..00000000 --- a/serde_macros/tests/compile-fail/duplicate_attributes.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![feature(custom_attribute, custom_derive, plugin)] -#![plugin(serde_macros)] - -#[derive(Serialize)] -struct S { - #[serde(rename(serialize="x"))] - #[serde(rename(serialize="y"))] //~ ERROR: duplicate serde attribute `rename` - a: (), - - #[serde(rename(serialize="x"))] - #[serde(rename="y")] //~ ERROR: duplicate serde attribute `rename` - b: (), - - #[serde(rename(serialize="x"))] - #[serde(rename(deserialize="y"))] // ok - c: (), - - #[serde(rename="x")] - #[serde(rename(deserialize="y"))] //~ ERROR: duplicate serde attribute `rename` - d: (), - - #[serde(rename(serialize="x", serialize="y"))] //~ ERROR: duplicate serde attribute `rename` - e: (), - - #[serde(rename="x", serialize="y")] //~ ERROR: unknown serde field attribute `serialize = "y"` - f: (), - - #[serde(rename(serialize="x"), rename(serialize="y"))] //~ ERROR: duplicate serde attribute `rename` - g: (), -} - -fn main() {} diff --git a/serde_macros/tests/compile-fail/reject-unknown-attributes.rs b/serde_macros/tests/compile-fail/reject-unknown-attributes.rs deleted file mode 100644 index 5a4d2776..00000000 --- a/serde_macros/tests/compile-fail/reject-unknown-attributes.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![feature(custom_attribute, custom_derive, plugin)] -#![plugin(serde_macros)] - -extern crate serde; - -#[derive(Serialize)] -#[serde(abc="xyz")] //~ unknown serde container attribute `abc = "xyz"` -struct Foo { - x: u32, -} - -#[derive(Deserialize)] -#[serde(abc="xyz")] //~ unknown serde container attribute `abc = "xyz"` -struct Foo { - x: u32, -} - -#[derive(Serialize)] -struct Foo { - #[serde(abc="xyz")] //~ unknown serde field attribute `abc = "xyz"` - x: u32, -} - -#[derive(Deserialize)] -struct Foo { - #[serde(abc="xyz")] //~ unknown serde field attribute `abc = "xyz"` - x: u32, -} - -fn main() { } diff --git a/serde_macros/tests/compile-fail/str_ref_deser.rs b/serde_macros/tests/compile-fail/str_ref_deser.rs deleted file mode 100644 index 827d08c9..00000000 --- a/serde_macros/tests/compile-fail/str_ref_deser.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(custom_attribute, custom_derive, plugin)] -#![plugin(serde_macros)] - -#[derive(Serialize, Deserialize)] -struct Test<'a> { - s: &'a str, //~ ERROR: Serde does not support deserializing fields of type &str -} - -fn main() {} diff --git a/serde_test/Cargo.toml b/serde_test/Cargo.toml index 878164e5..a17bf62d 100644 --- a/serde_test/Cargo.toml +++ b/serde_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_test" -version = "0.8.4" +version = "0.8.21" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Token De/Serializer for testing De/Serialize implementations" @@ -11,5 +11,7 @@ readme = "../README.md" keywords = ["serde", "serialization"] include = ["Cargo.toml", "src/**/*.rs"] +publish = false # this branch contains breaking changes for 0.9 + [dependencies] -serde = { version = "0.8.4", path = "../serde" } +serde = { version = "0.8.21", path = "../serde" } diff --git a/testing/Cargo.toml b/testing/Cargo.toml index 9f9fe69e..debc8aa8 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_testing" -version = "0.8.4" +version = "0.8.21" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" @@ -10,6 +10,7 @@ documentation = "https://docs.serde.rs/serde/" readme = "README.md" keywords = ["serialization"] build = "build.rs" +publish = false [features] unstable-testing = ["clippy", "serde/unstable-testing", "serde_codegen/unstable-testing"] @@ -29,7 +30,3 @@ clippy = { version = "^0.*", optional = true } [[test]] name = "test" path = "tests/test.rs" - -[[bench]] -name = "bench" -path = "benches/bench.rs" diff --git a/testing/benches/bench.rs b/testing/benches/bench.rs deleted file mode 100644 index e5b10c57..00000000 --- a/testing/benches/bench.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(test)] -#![cfg_attr(feature = "clippy", feature(plugin))] -#![cfg_attr(feature = "clippy", plugin(clippy))] - -extern crate rustc_serialize; -extern crate serde; -extern crate test; - -include!(concat!(env!("OUT_DIR"), "/bench.rs")); diff --git a/testing/benches/bench.rs.in b/testing/benches/bench.rs.in deleted file mode 100644 index d79b35f0..00000000 --- a/testing/benches/bench.rs.in +++ /dev/null @@ -1,4 +0,0 @@ -mod bench_enum; -mod bench_map; -mod bench_struct; -mod bench_vec; diff --git a/testing/benches/bench_enum.rs b/testing/benches/bench_enum.rs deleted file mode 100644 index 8badbb49..00000000 --- a/testing/benches/bench_enum.rs +++ /dev/null @@ -1,466 +0,0 @@ -use test::Bencher; -use std::error; -use std::fmt; -use rustc_serialize::Decodable; -use serde; -use serde::de::Deserialize; - -////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, PartialEq, Debug, RustcDecodable, Deserialize)] -pub enum Animal { - Dog, - Frog(String, isize) -} - -////////////////////////////////////////////////////////////////////////////// - -#[derive(Debug)] -pub enum Error { - EndOfStream, - Syntax, -} - -impl serde::de::Error for Error { - fn custom>(_: T) -> Error { Error::Syntax } - - fn end_of_stream() -> Error { Error::EndOfStream } - - fn unknown_field(_: &str) -> Error { Error::Syntax } - - fn missing_field(_: &'static str) -> Error { Error::Syntax } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.write_str(format!("{:?}", self).as_ref()) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - "Serde Deserialization Error" - } - - fn cause(&self) -> Option<&error::Error> { - None - } -} - -////////////////////////////////////////////////////////////////////////////// - -mod decoder { - use rustc_serialize::Decoder; - - use super::{Animal, Error}; - use super::Animal::{Dog, Frog}; - - enum State { - Animal(Animal), - Isize(isize), - String(String), - } - - pub struct AnimalDecoder { - stack: Vec, - - } - - impl AnimalDecoder { - #[inline] - pub fn new(animal: Animal) -> AnimalDecoder { - AnimalDecoder { - stack: vec!(State::Animal(animal)), - } - } - } - - impl Decoder for AnimalDecoder { - type Error = Error; - - fn error(&mut self, _: &str) -> Error { Error::Syntax } - - // Primitive types: - fn read_nil(&mut self) -> Result<(), Error> { Err(Error::Syntax) } - fn read_usize(&mut self) -> Result { Err(Error::Syntax) } - fn read_u64(&mut self) -> Result { Err(Error::Syntax) } - fn read_u32(&mut self) -> Result { Err(Error::Syntax) } - fn read_u16(&mut self) -> Result { Err(Error::Syntax) } - fn read_u8(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_isize(&mut self) -> Result { - match self.stack.pop() { - Some(State::Isize(x)) => Ok(x), - _ => Err(Error::Syntax), - } - } - fn read_i64(&mut self) -> Result { Err(Error::Syntax) } - fn read_i32(&mut self) -> Result { Err(Error::Syntax) } - fn read_i16(&mut self) -> Result { Err(Error::Syntax) } - fn read_i8(&mut self) -> Result { Err(Error::Syntax) } - fn read_bool(&mut self) -> Result { Err(Error::Syntax) } - fn read_f64(&mut self) -> Result { Err(Error::Syntax) } - fn read_f32(&mut self) -> Result { Err(Error::Syntax) } - fn read_char(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_str(&mut self) -> Result { - match self.stack.pop() { - Some(State::String(x)) => Ok(x), - _ => Err(Error::Syntax), - } - } - - // Compound types: - #[inline] - fn read_enum(&mut self, name: &str, f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - match self.stack.pop() { - Some(State::Animal(animal)) => { - self.stack.push(State::Animal(animal)); - if name == "Animal" { - f(self) - } else { - Err(Error::Syntax) - } - } - _ => Err(Error::Syntax) - } - } - - #[inline] - fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnOnce(&mut AnimalDecoder, usize) -> Result, - { - let name = match self.stack.pop() { - Some(State::Animal(Dog)) => "Dog", - Some(State::Animal(Frog(x0, x1))) => { - self.stack.push(State::Isize(x1)); - self.stack.push(State::String(x0)); - "Frog" - } - _ => { return Err(Error::Syntax); } - }; - - let idx = match names.iter().position(|n| *n == name) { - Some(idx) => idx, - None => { return Err(Error::Syntax); } - }; - - f(self, idx) - } - - #[inline] - fn read_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - f(self) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple(&mut self, _len: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - // Specialized types: - fn read_option(&mut self, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder, bool) -> Result, - { - Err(Error::Syntax) - } - - #[inline] - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut AnimalDecoder, usize) -> Result, - { - f(self, 3) - } - - #[inline] - fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - f(self) - } - - fn read_map(&mut self, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_key(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_val(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut AnimalDecoder) -> Result, - { - Err(Error::Syntax) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -mod deserializer { - use super::{Animal, Error}; - - use serde::de; - - #[derive(Debug)] - enum State { - Animal(Animal), - Isize(isize), - Str(&'static str), - String(String), - UnitState, - } - - pub struct AnimalDeserializer { - stack: Vec, - } - - impl AnimalDeserializer { - #[inline] - pub fn new(animal: Animal) -> AnimalDeserializer { - AnimalDeserializer { - stack: vec!(State::Animal(animal)), - } - } - } - - impl de::Deserializer for AnimalDeserializer { - type Error = Error; - - #[inline] - fn deserialize(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - match self.stack.pop() { - Some(State::Isize(value)) => { - visitor.visit_isize(value) - } - Some(State::String(value)) => { - visitor.visit_string(value) - } - Some(State::Str(value)) => { - visitor.visit_str(value) - } - Some(State::UnitState) => { - visitor.visit_unit() - } - Some(_) => { - Err(Error::Syntax) - } - None => { - Err(Error::EndOfStream) - } - } - } - - #[inline] - fn deserialize_enum(&mut self, - _name: &str, - _variants: &[&str], - mut visitor: V) -> Result - where V: de::EnumVisitor, - { - match self.stack.pop() { - Some(State::Animal(Animal::Dog)) => { - self.stack.push(State::UnitState); - self.stack.push(State::Str("Dog")); - visitor.visit(DogVisitor { - de: self, - }) - } - Some(State::Animal(Animal::Frog(x0, x1))) => { - self.stack.push(State::Isize(x1)); - self.stack.push(State::String(x0)); - self.stack.push(State::Str("Frog")); - visitor.visit(FrogVisitor { - de: self, - state: 0, - }) - } - Some(_) => { - Err(Error::Syntax) - } - None => { - Err(Error::EndOfStream) - } - } - } - } - - struct DogVisitor<'a> { - de: &'a mut AnimalDeserializer, - } - - impl<'a> de::VariantVisitor for DogVisitor<'a> { - type Error = Error; - - fn visit_variant(&mut self) -> Result - where V: de::Deserialize - { - de::Deserialize::deserialize(self.de) - } - - fn visit_unit(&mut self) -> Result<(), Error> { - de::Deserialize::deserialize(self.de) - } - } - - struct FrogVisitor<'a> { - de: &'a mut AnimalDeserializer, - state: usize, - } - - impl<'a> de::VariantVisitor for FrogVisitor<'a> { - type Error = Error; - - fn visit_variant(&mut self) -> Result - where V: de::Deserialize - { - de::Deserialize::deserialize(self.de) - } - - fn visit_tuple(&mut self, - _len: usize, - mut visitor: V) -> Result - where V: de::Visitor, - { - visitor.visit_seq(self) - } - } - - impl<'a> de::SeqVisitor for FrogVisitor<'a> { - type Error = Error; - - fn visit(&mut self) -> Result, Error> - where T: de::Deserialize, - { - match self.state { - 0 => { - self.state += 1; - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - 1 => { - self.state += 1; - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - _ => { - Ok(None) - } - } - } - - fn end(&mut self) -> Result<(), Error> { - if self.state == 2 { - Ok(()) - } else { - Err(Error::Syntax) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = 2 - self.state; - (len, Some(len)) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -#[bench] -fn bench_decoder_dog(b: &mut Bencher) { - b.iter(|| { - let animal = Animal::Dog; - - let mut d = decoder::AnimalDecoder::new(animal.clone()); - let value: Animal = Decodable::decode(&mut d).unwrap(); - - assert_eq!(value, animal); - }) -} - -#[bench] -fn bench_decoder_frog(b: &mut Bencher) { - b.iter(|| { - let animal = Animal::Frog("Henry".to_owned(), 349); - - let mut d = decoder::AnimalDecoder::new(animal.clone()); - let value: Animal = Decodable::decode(&mut d).unwrap(); - - assert_eq!(value, animal); - }) -} - -#[bench] -fn bench_deserializer_dog(b: &mut Bencher) { - b.iter(|| { - let animal = Animal::Dog; - - let mut d = deserializer::AnimalDeserializer::new(animal.clone()); - let value: Animal = Deserialize::deserialize(&mut d).unwrap(); - - assert_eq!(value, animal); - }) -} - -#[bench] -fn bench_deserializer_frog(b: &mut Bencher) { - b.iter(|| { - let animal = Animal::Frog("Henry".to_owned(), 349); - - let mut d = deserializer::AnimalDeserializer::new(animal.clone()); - let value: Animal = Deserialize::deserialize(&mut d).unwrap(); - - assert_eq!(value, animal); - }) -} diff --git a/testing/benches/bench_map.rs b/testing/benches/bench_map.rs deleted file mode 100644 index 32bc4415..00000000 --- a/testing/benches/bench_map.rs +++ /dev/null @@ -1,474 +0,0 @@ -use std::fmt::Debug; -use std::fmt; -use std::error; -use std::collections::HashMap; -use test::Bencher; - -use rustc_serialize::{Decoder, Decodable}; - -use serde; -use serde::de::{Deserializer, Deserialize}; - -////////////////////////////////////////////////////////////////////////////// - -#[derive(PartialEq, Debug)] -pub enum Error { - EndOfStream, - Syntax, - MissingField, -} - -impl serde::de::Error for Error { - fn custom>(_: T) -> Error { Error::Syntax } - - fn end_of_stream() -> Error { Error::EndOfStream } - - fn unknown_field(_: &str) -> Error { Error::Syntax } - - fn missing_field(_: &'static str) -> Error { - Error::MissingField - } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.write_str(format!("{:?}", self).as_ref()) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - "Serde Deserialization Error" - } - - fn cause(&self) -> Option<&error::Error> { - None - } -} -////////////////////////////////////////////////////////////////////////////// - -mod decoder { - use std::collections::HashMap; - use std::collections::hash_map::IntoIter; - use rustc_serialize; - - use super::Error; - - enum Value { - String(String), - Isize(isize), - } - - pub struct IsizeDecoder { - len: usize, - iter: IntoIter, - stack: Vec, - } - - impl IsizeDecoder { - #[inline] - pub fn new(values: HashMap) -> IsizeDecoder { - IsizeDecoder { - len: values.len(), - iter: values.into_iter(), - stack: vec!(), - } - } - } - - impl rustc_serialize::Decoder for IsizeDecoder { - type Error = Error; - - fn error(&mut self, _msg: &str) -> Error { - Error::Syntax - } - - // Primitive types: - fn read_nil(&mut self) -> Result<(), Error> { Err(Error::Syntax) } - fn read_usize(&mut self) -> Result { Err(Error::Syntax) } - fn read_u64(&mut self) -> Result { Err(Error::Syntax) } - fn read_u32(&mut self) -> Result { Err(Error::Syntax) } - fn read_u16(&mut self) -> Result { Err(Error::Syntax) } - fn read_u8(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_isize(&mut self) -> Result { - match self.stack.pop() { - Some(Value::Isize(x)) => Ok(x), - Some(_) => Err(Error::Syntax), - None => Err(Error::EndOfStream), - } - } - fn read_i64(&mut self) -> Result { Err(Error::Syntax) } - fn read_i32(&mut self) -> Result { Err(Error::Syntax) } - fn read_i16(&mut self) -> Result { Err(Error::Syntax) } - fn read_i8(&mut self) -> Result { Err(Error::Syntax) } - fn read_bool(&mut self) -> Result { Err(Error::Syntax) } - fn read_f64(&mut self) -> Result { Err(Error::Syntax) } - fn read_f32(&mut self) -> Result { Err(Error::Syntax) } - fn read_char(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_str(&mut self) -> Result { - match self.stack.pop() { - Some(Value::String(x)) => Ok(x), - Some(_) => Err(Error::Syntax), - None => Err(Error::EndOfStream), - } - } - - // Compound types: - fn read_enum(&mut self, _name: &str, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple(&mut self, _len: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - // Specialized types: - fn read_option(&mut self, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder, bool) -> Result, - { - Err(Error::Syntax) - } - - fn read_seq(&mut self, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_seq_elt(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - #[inline] - fn read_map(&mut self, f: F) -> Result where - F: FnOnce(&mut IsizeDecoder, usize) -> Result, - { - let len = self.len; - f(self, len) - } - #[inline] - fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - match self.iter.next() { - Some((key, value)) => { - self.stack.push(Value::Isize(value)); - self.stack.push(Value::String(key)); - f(self) - } - None => { - Err(Error::Syntax) - } - } - } - - #[inline] - fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut IsizeDecoder) -> Result, - { - f(self) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -mod deserializer { - use std::collections::HashMap; - use std::collections::hash_map; - - use super::Error; - - use serde::de; - - #[derive(PartialEq, Debug)] - enum State { - StartState, - Key(String), - Value(isize), - } - - pub struct IsizeDeserializer { - stack: Vec, - iter: hash_map::IntoIter, - } - - impl IsizeDeserializer { - #[inline] - pub fn new(values: HashMap) -> IsizeDeserializer { - IsizeDeserializer { - stack: vec!(State::StartState), - iter: values.into_iter(), - } - } - } - - impl de::Deserializer for IsizeDeserializer { - type Error = Error; - - fn deserialize(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - match self.stack.pop() { - Some(State::StartState) => { - visitor.visit_map(self) - } - Some(State::Key(key)) => { - visitor.visit_string(key) - } - Some(State::Value(value)) => { - visitor.visit_isize(value) - } - None => { - Err(Error::EndOfStream) - } - } - } - } - - impl de::MapVisitor for IsizeDeserializer { - type Error = Error; - - fn visit_key(&mut self) -> Result, Error> - where K: de::Deserialize, - { - match self.iter.next() { - Some((key, value)) => { - self.stack.push(State::Value(value)); - self.stack.push(State::Key(key)); - Ok(Some(try!(de::Deserialize::deserialize(self)))) - } - None => { - Ok(None) - } - } - } - - fn visit_value(&mut self) -> Result - where V: de::Deserialize, - { - de::Deserialize::deserialize(self) - } - - fn end(&mut self) -> Result<(), Error> { - match self.iter.next() { - Some(_) => Err(Error::Syntax), - None => Ok(()), - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - } - -/* - impl Iterator for IsizeDeserializer { - type Item = Result; - - #[inline] - fn next(&mut self) -> Option> { - match self.stack.pop() { - Some(State::StartState) => { - self.stack.push(KeyOrEndState); - Some(Ok(de::Token::MapStart(self.len))) - } - Some(State::KeyOrEndState) => { - match self.iter.next() { - Some((key, value)) => { - self.stack.push(Value(value)); - Some(Ok(de::Token::String(key))) - } - None => { - self.stack.push(EndState); - Some(Ok(de::Token::End)) - } - } - } - Some(State::Value(x)) => { - self.stack.push(KeyOrEndState); - Some(Ok(de::Token::Isize(x))) - } - Some(EndState) => { - None - } - None => { - None - } - } - } - } - - impl de::Deserializer for IsizeDeserializer { - #[inline] - fn end_of_stream(&mut self) -> Error { - EndOfStream - } - - #[inline] - fn syntax(&mut self, _token: de::Token, _expected: &[de::TokenKind]) -> Error { - Syntax - } - - #[inline] - fn unexpected_name(&mut self, _token: de::Token) -> Error { - Syntax - } - - #[inline] - fn conversion_error(&mut self, _token: de::Token) -> Error { - Syntax - } - - #[inline] - fn missing_field< - T: de::Deserialize - >(&mut self, _field: &'static str) -> Result { - Err(Error::Syntax) - } - } -*/ -} - -////////////////////////////////////////////////////////////////////////////// - -fn run_decoder< - D: Decoder, - T: Clone + PartialEq + Debug + Decodable ->(mut d: D, value: T) { - let v = Decodable::decode(&mut d); - - assert_eq!(Ok(value), v); -} - -#[bench] -fn bench_decoder_000(b: &mut Bencher) { - b.iter(|| { - let m: HashMap = HashMap::new(); - run_decoder(decoder::IsizeDecoder::new(m.clone()), m) - }) -} - -#[bench] -fn bench_decoder_003(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = HashMap::new(); - for i in 0 .. 3 { - m.insert(i.to_string(), i); - } - run_decoder(decoder::IsizeDecoder::new(m.clone()), m) - }) -} - -#[bench] -fn bench_decoder_100(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = HashMap::new(); - for i in 0 .. 100 { - m.insert(i.to_string(), i); - } - run_decoder(decoder::IsizeDecoder::new(m.clone()), m) - }) -} - -fn run_deserializer(mut d: D, value: T) - where D: Deserializer, - D::Error: Debug + PartialEq, - T: Clone + PartialEq + Debug + Deserialize -{ - let v = T::deserialize(&mut d); - - assert_eq!(Ok(value), v); -} - -#[bench] -fn bench_deserializer_000(b: &mut Bencher) { - b.iter(|| { - let m: HashMap = HashMap::new(); - run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m) - }) -} - -#[bench] -fn bench_deserializer_003(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = HashMap::new(); - for i in 0 .. 3 { - m.insert(i.to_string(), i); - } - run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m) - }) -} - -#[bench] -fn bench_deserializer_100(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = HashMap::new(); - for i in 0 .. 100 { - m.insert(i.to_string(), i); - } - run_deserializer(deserializer::IsizeDeserializer::new(m.clone()), m) - }) -} diff --git a/testing/benches/bench_struct.rs b/testing/benches/bench_struct.rs deleted file mode 100644 index 82b189e1..00000000 --- a/testing/benches/bench_struct.rs +++ /dev/null @@ -1,745 +0,0 @@ -use std::collections::HashMap; -use test::Bencher; -use std::fmt; -use std::error; - -use rustc_serialize::Decodable; - -use serde; -use serde::de::Deserialize; - -////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, PartialEq, Debug, RustcDecodable, Deserialize)] -pub struct Inner { - a: (), - b: usize, - c: HashMap>, -} - -////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, PartialEq, Debug, RustcDecodable, Deserialize)] -pub struct Outer { - inner: Vec, -} - -////////////////////////////////////////////////////////////////////////////// - -#[derive(Debug, PartialEq)] -pub enum Error { - EndOfStream, - Syntax, - MissingField, - OtherError, -} - -impl serde::de::Error for Error { - fn custom>(_: T) -> Error { Error::Syntax } - - fn end_of_stream() -> Error { Error::EndOfStream } - - fn unknown_field(_: &str) -> Error { Error::Syntax } - - fn missing_field(_: &'static str) -> Error { - Error::MissingField - } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.write_str(format!("{:?}", self).as_ref()) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - "Serde Deserialization Error" - } - - fn cause(&self) -> Option<&error::Error> { - None - } -} - -mod decoder { - use std::collections::HashMap; - use rustc_serialize::Decoder; - - use super::{Outer, Inner, Error}; - - #[derive(Debug)] - enum State { - Outer(Outer), - Inner(Inner), - Null, - Usize(usize), - Char(char), - String(String), - Field(&'static str), - Vec(Vec), - Map(HashMap>), - Option(bool), - } - - pub struct OuterDecoder { - stack: Vec, - - } - - impl OuterDecoder { - #[inline] - pub fn new(animal: Outer) -> OuterDecoder { - OuterDecoder { - stack: vec!(State::Outer(animal)), - } - } - } - - impl Decoder for OuterDecoder { - type Error = Error; - - fn error(&mut self, _msg: &str) -> Error { - Error::OtherError - } - - // Primitive types: - #[inline] - fn read_nil(&mut self) -> Result<(), Error> { - match self.stack.pop() { - Some(State::Null) => Ok(()), - _ => Err(Error::Syntax), - } - } - #[inline] - fn read_usize(&mut self) -> Result { - match self.stack.pop() { - Some(State::Usize(value)) => Ok(value), - _ => Err(Error::Syntax), - } - } - fn read_u64(&mut self) -> Result { Err(Error::Syntax) } - fn read_u32(&mut self) -> Result { Err(Error::Syntax) } - fn read_u16(&mut self) -> Result { Err(Error::Syntax) } - fn read_u8(&mut self) -> Result { Err(Error::Syntax) } - fn read_isize(&mut self) -> Result { Err(Error::Syntax) } - fn read_i64(&mut self) -> Result { Err(Error::Syntax) } - fn read_i32(&mut self) -> Result { Err(Error::Syntax) } - fn read_i16(&mut self) -> Result { Err(Error::Syntax) } - fn read_i8(&mut self) -> Result { Err(Error::Syntax) } - fn read_bool(&mut self) -> Result { Err(Error::Syntax) } - fn read_f64(&mut self) -> Result { Err(Error::Syntax) } - fn read_f32(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_char(&mut self) -> Result { - match self.stack.pop() { - Some(State::Char(c)) => Ok(c), - _ => Err(Error::Syntax), - } - } - #[inline] - fn read_str(&mut self) -> Result { - match self.stack.pop() { - Some(State::String(value)) => Ok(value), - _ => Err(Error::Syntax), - } - } - - // Compound types: - fn read_enum(&mut self, _name: &str, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut OuterDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut OuterDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - #[inline] - fn read_struct(&mut self, s_name: &str, _len: usize, f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - match self.stack.pop() { - Some(State::Outer(Outer { inner })) => { - if s_name == "Outer" { - self.stack.push(State::Vec(inner)); - self.stack.push(State::Field("inner")); - f(self) - } else { - Err(Error::Syntax) - } - } - Some(State::Inner(Inner { a: (), b, c })) => { - if s_name == "Inner" { - self.stack.push(State::Map(c)); - self.stack.push(State::Field("c")); - - self.stack.push(State::Usize(b)); - self.stack.push(State::Field("b")); - - self.stack.push(State::Null); - self.stack.push(State::Field("a")); - f(self) - } else { - Err(Error::Syntax) - } - } - _ => Err(Error::Syntax), - } - } - #[inline] - fn read_struct_field(&mut self, f_name: &str, _f_idx: usize, f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - match self.stack.pop() { - Some(State::Field(name)) => { - if f_name == name { - f(self) - } else { - Err(Error::Syntax) - } - } - _ => Err(Error::Syntax) - } - } - - fn read_tuple(&mut self, _len: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - Err(Error::Syntax) - } - - // Specialized types: - #[inline] - fn read_option(&mut self, f: F) -> Result where - F: FnOnce(&mut OuterDecoder, bool) -> Result, - { - match self.stack.pop() { - Some(State::Option(b)) => f(self, b), - _ => Err(Error::Syntax), - } - } - - #[inline] - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut OuterDecoder, usize) -> Result, - { - match self.stack.pop() { - Some(State::Vec(value)) => { - let len = value.len(); - for inner in value.into_iter().rev() { - self.stack.push(State::Inner(inner)); - } - f(self, len) - } - _ => Err(Error::Syntax) - } - } - #[inline] - fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - f(self) - } - - #[inline] - fn read_map(&mut self, f: F) -> Result where - F: FnOnce(&mut OuterDecoder, usize) -> Result, - { - match self.stack.pop() { - Some(State::Map(map)) => { - let len = map.len(); - for (key, value) in map { - match value { - Some(c) => { - self.stack.push(State::Char(c)); - self.stack.push(State::Option(true)); - } - None => { - self.stack.push(State::Option(false)); - } - } - self.stack.push(State::String(key)); - } - f(self, len) - } - _ => Err(Error::Syntax), - } - } - #[inline] - fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - f(self) - } - - #[inline] - fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut OuterDecoder) -> Result, - { - f(self) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -mod deserializer { - use std::collections::HashMap; - use std::collections::hash_map; - use std::vec; - use super::{Outer, Inner}; - use super::Error; - use serde::de; - - #[derive(Debug)] - enum State { - Outer(Outer), - Inner(Inner), - Str(&'static str), - Null, - Usize(usize), - Char(char), - String(String), - Option(bool), - Vec(Vec), - Map(HashMap>), - } - - pub struct OuterDeserializer { - stack: Vec, - } - - impl OuterDeserializer { - #[inline] - pub fn new(outer: Outer) -> OuterDeserializer { - OuterDeserializer { - stack: vec!(State::Outer(outer)), - } - } - } - - impl de::Deserializer for OuterDeserializer { - type Error = Error; - - fn deserialize(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - match self.stack.pop() { - Some(State::Vec(value)) => { - visitor.visit_seq(OuterSeqVisitor { - de: self, - iter: value.into_iter(), - }) - } - Some(State::Map(value)) => { - visitor.visit_map(MapVisitor { - de: self, - iter: value.into_iter(), - }) - } - Some(State::Null) => { - visitor.visit_unit() - } - Some(State::Usize(x)) => { - visitor.visit_usize(x) - } - Some(State::Char(x)) => { - visitor.visit_char(x) - } - Some(State::Str(x)) => { - visitor.visit_str(x) - } - Some(State::String(x)) => { - visitor.visit_string(x) - } - Some(State::Option(false)) => { - visitor.visit_none() - } - Some(State::Option(true)) => { - visitor.visit_some(self) - } - Some(_) => Err(Error::Syntax), - None => Err(Error::EndOfStream), - } - } - - fn deserialize_struct(&mut self, - name: &str, - _fields: &'static [&'static str], - mut visitor: V) -> Result - where V: de::Visitor, - { - match self.stack.pop() { - Some(State::Outer(Outer { inner })) => { - if name != "Outer" { - return Err(Error::Syntax); - } - - self.stack.push(State::Vec(inner)); - self.stack.push(State::Str("inner")); - - visitor.visit_map(OuterMapVisitor { - de: self, - state: 0, - }) - } - Some(State::Inner(Inner { a: (), b, c })) => { - if name != "Inner" { - return Err(Error::Syntax); - } - - self.stack.push(State::Map(c)); - self.stack.push(State::Str("c")); - - self.stack.push(State::Usize(b)); - self.stack.push(State::Str("b")); - - self.stack.push(State::Null); - self.stack.push(State::Str("a")); - - visitor.visit_map(InnerMapVisitor { - de: self, - state: 0, - }) - } - _ => { - Err(Error::Syntax) - } - } - } - } - - struct OuterMapVisitor<'a> { - de: &'a mut OuterDeserializer, - state: usize, - } - - impl<'a> de::MapVisitor for OuterMapVisitor<'a> { - type Error = Error; - - fn visit_key(&mut self) -> Result, Error> - where K: de::Deserialize, - { - match self.state { - 0 => { - self.state += 1; - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - _ => { - Ok(None) - } - } - } - - fn visit_value(&mut self) -> Result - where V: de::Deserialize, - { - de::Deserialize::deserialize(self.de) - } - - fn end(&mut self) -> Result<(), Error> { - if self.state == 1 { - Ok(()) - } else { - Err(Error::Syntax) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = 1 - self.state; - (len, Some(len)) - } - } - - struct OuterSeqVisitor<'a> { - de: &'a mut OuterDeserializer, - iter: vec::IntoIter, - } - - impl<'a> de::SeqVisitor for OuterSeqVisitor<'a> { - type Error = Error; - - fn visit(&mut self) -> Result, Error> - where T: de::Deserialize, - { - match self.iter.next() { - Some(value) => { - self.de.stack.push(State::Inner(value)); - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - None => { - Ok(None) - } - } - } - - fn end(&mut self) -> Result<(), Error> { - match self.iter.next() { - Some(_) => Err(Error::Syntax), - None => Ok(()), - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - } - - struct InnerMapVisitor<'a> { - de: &'a mut OuterDeserializer, - state: usize, - } - - impl<'a> de::MapVisitor for InnerMapVisitor<'a> { - type Error = Error; - - fn visit_key(&mut self) -> Result, Error> - where K: de::Deserialize, - { - match self.state { - 0 ... 2 => { - self.state += 1; - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - _ => { - Ok(None) - } - } - } - - fn visit_value(&mut self) -> Result - where V: de::Deserialize, - { - de::Deserialize::deserialize(self.de) - } - - fn end(&mut self) -> Result<(), Error> { - if self.state == 3 { - Ok(()) - } else { - Err(Error::Syntax) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = 1 - self.state; - (len, Some(len)) - } - } - - struct MapVisitor<'a> { - de: &'a mut OuterDeserializer, - iter: hash_map::IntoIter>, - } - - impl<'a> de::MapVisitor for MapVisitor<'a> { - type Error = Error; - - fn visit_key(&mut self) -> Result, Error> - where K: de::Deserialize, - { - match self.iter.next() { - Some((key, Some(value))) => { - self.de.stack.push(State::Char(value)); - self.de.stack.push(State::Option(true)); - self.de.stack.push(State::String(key)); - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - Some((key, None)) => { - self.de.stack.push(State::Option(false)); - self.de.stack.push(State::String(key)); - Ok(Some(try!(de::Deserialize::deserialize(self.de)))) - } - None => { - Ok(None) - } - } - } - - fn visit_value(&mut self) -> Result - where V: de::Deserialize, - { - de::Deserialize::deserialize(self.de) - } - - fn end(&mut self) -> Result<(), Error> { - match self.iter.next() { - Some(_) => Err(Error::Syntax), - None => Ok(()), - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - } -} - -#[bench] -fn bench_decoder_0_0(b: &mut Bencher) { - b.iter(|| { - let mut map = HashMap::new(); - map.insert("abc".to_owned(), Some('c')); - - let outer = Outer { - inner: vec!(), - }; - - let mut d = decoder::OuterDecoder::new(outer.clone()); - let value: Result = Decodable::decode(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} - -#[bench] -fn bench_decoder_1_0(b: &mut Bencher) { - b.iter(|| { - let map = HashMap::new(); - - let outer = Outer { - inner: vec!( - Inner { - a: (), - b: 5, - c: map, - }, - ) - }; - - let mut d = decoder::OuterDecoder::new(outer.clone()); - let value: Result = Decodable::decode(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} - -#[bench] -fn bench_decoder_1_5(b: &mut Bencher) { - b.iter(|| { - let mut map = HashMap::new(); - map.insert("1".to_owned(), Some('a')); - map.insert("2".to_owned(), None); - map.insert("3".to_owned(), Some('b')); - map.insert("4".to_owned(), None); - map.insert("5".to_owned(), Some('c')); - - let outer = Outer { - inner: vec!( - Inner { - a: (), - b: 5, - c: map, - }, - ) - }; - - let mut d = decoder::OuterDecoder::new(outer.clone()); - let value: Result = Decodable::decode(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} - -#[bench] -fn bench_deserializer_0_0(b: &mut Bencher) { - b.iter(|| { - let outer = Outer { - inner: vec!(), - }; - - let mut d = deserializer::OuterDeserializer::new(outer.clone()); - let value: Result = Deserialize::deserialize(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} - -#[bench] -fn bench_deserializer_1_0(b: &mut Bencher) { - b.iter(|| { - let map = HashMap::new(); - - let outer = Outer { - inner: vec!( - Inner { - a: (), - b: 5, - c: map, - }, - ) - }; - - let mut d = deserializer::OuterDeserializer::new(outer.clone()); - let value: Result = Deserialize::deserialize(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} - -#[bench] -fn bench_deserializer_1_5(b: &mut Bencher) { - b.iter(|| { - let mut map = HashMap::new(); - map.insert("1".to_owned(), Some('a')); - map.insert("2".to_owned(), None); - map.insert("3".to_owned(), Some('b')); - map.insert("4".to_owned(), None); - map.insert("5".to_owned(), Some('c')); - - let outer = Outer { - inner: vec!( - Inner { - a: (), - b: 5, - c: map, - }, - ) - }; - - let mut d = deserializer::OuterDeserializer::new(outer.clone()); - let value: Result = Deserialize::deserialize(&mut d); - - assert_eq!(value, Ok(outer)); - }) -} diff --git a/testing/benches/bench_vec.rs b/testing/benches/bench_vec.rs deleted file mode 100644 index 96a4e637..00000000 --- a/testing/benches/bench_vec.rs +++ /dev/null @@ -1,628 +0,0 @@ -use std::fmt::Debug; -use std::fmt; -use std::error; -use test::Bencher; - -use rustc_serialize::{Decoder, Decodable}; - -use serde; -use serde::de::{Deserializer, Deserialize}; - -////////////////////////////////////////////////////////////////////////////// - -#[derive(PartialEq, Debug)] -pub enum Error { - EndOfStream, - Syntax, -} - -impl serde::de::Error for Error { - fn custom>(_: T) -> Error { Error::Syntax } - - fn end_of_stream() -> Error { Error::EndOfStream } - - fn unknown_field(_: &str) -> Error { Error::Syntax } - - fn missing_field(_: &'static str) -> Error { Error::Syntax } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.write_str(format!("{:?}", self).as_ref()) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - "Serde Deserialization Error" - } - - fn cause(&self) -> Option<&error::Error> { - None - } -} -////////////////////////////////////////////////////////////////////////////// - -mod decoder { - use std::vec; - use rustc_serialize; - - use super::Error; - - pub struct UsizeDecoder { - len: usize, - iter: vec::IntoIter, - } - - impl UsizeDecoder { - #[inline] - pub fn new(values: Vec) -> UsizeDecoder { - UsizeDecoder { - len: values.len(), - iter: values.into_iter(), - } - } - } - - impl rustc_serialize::Decoder for UsizeDecoder { - type Error = Error; - - fn error(&mut self, _: &str) -> Error { Error::Syntax } - - // Primitive types: - fn read_nil(&mut self) -> Result<(), Error> { Err(Error::Syntax) } - #[inline] - fn read_usize(&mut self) -> Result { - match self.iter.next() { - Some(value) => Ok(value), - None => Err(Error::EndOfStream), - } - } - fn read_u64(&mut self) -> Result { Err(Error::Syntax) } - fn read_u32(&mut self) -> Result { Err(Error::Syntax) } - fn read_u16(&mut self) -> Result { Err(Error::Syntax) } - fn read_u8(&mut self) -> Result { Err(Error::Syntax) } - fn read_isize(&mut self) -> Result { Err(Error::Syntax) } - fn read_i64(&mut self) -> Result { Err(Error::Syntax) } - fn read_i32(&mut self) -> Result { Err(Error::Syntax) } - fn read_i16(&mut self) -> Result { Err(Error::Syntax) } - fn read_i8(&mut self) -> Result { Err(Error::Syntax) } - fn read_bool(&mut self) -> Result { Err(Error::Syntax) } - fn read_f64(&mut self) -> Result { Err(Error::Syntax) } - fn read_f32(&mut self) -> Result { Err(Error::Syntax) } - fn read_char(&mut self) -> Result { Err(Error::Syntax) } - fn read_str(&mut self) -> Result { Err(Error::Syntax) } - - // Compound types: - fn read_enum(&mut self, _name: &str, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple(&mut self, _len: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - // Specialized types: - fn read_option(&mut self, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder, bool) -> Result, - { - Err(Error::Syntax) - } - - #[inline] - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut UsizeDecoder, usize) -> Result, - { - let len = self.len; - f(self, len) - } - #[inline] - fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - f(self) - } - - fn read_map(&mut self, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_key(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_val(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut UsizeDecoder) -> Result, - { - Err(Error::Syntax) - } - } - - - pub struct U8Decoder { - len: usize, - iter: vec::IntoIter, - } - - impl U8Decoder { - #[inline] - pub fn new(values: Vec) -> U8Decoder { - U8Decoder { - len: values.len(), - iter: values.into_iter(), - } - } - } - - impl rustc_serialize::Decoder for U8Decoder { - type Error = Error; - - fn error(&mut self, _: &str) -> Error { Error::Syntax } - - // Primitive types: - fn read_nil(&mut self) -> Result<(), Error> { Err(Error::Syntax) } - fn read_usize(&mut self) -> Result { Err(Error::Syntax) } - fn read_u64(&mut self) -> Result { Err(Error::Syntax) } - fn read_u32(&mut self) -> Result { Err(Error::Syntax) } - fn read_u16(&mut self) -> Result { Err(Error::Syntax) } - #[inline] - fn read_u8(&mut self) -> Result { - match self.iter.next() { - Some(value) => Ok(value), - None => Err(Error::EndOfStream), - } - } - #[inline] - fn read_isize(&mut self) -> Result { Err(Error::Syntax) } - fn read_i64(&mut self) -> Result { Err(Error::Syntax) } - fn read_i32(&mut self) -> Result { Err(Error::Syntax) } - fn read_i16(&mut self) -> Result { Err(Error::Syntax) } - fn read_i8(&mut self) -> Result { Err(Error::Syntax) } - fn read_bool(&mut self) -> Result { Err(Error::Syntax) } - fn read_f64(&mut self) -> Result { Err(Error::Syntax) } - fn read_f32(&mut self) -> Result { Err(Error::Syntax) } - fn read_char(&mut self) -> Result { Err(Error::Syntax) } - fn read_str(&mut self) -> Result { Err(Error::Syntax) } - - // Compound types: - fn read_enum(&mut self, _name: &str, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut U8Decoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_variant_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) -> Result where - F: FnOnce(&mut U8Decoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_struct_field(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple(&mut self, _len: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - // Specialized types: - fn read_option(&mut self, _f: F) -> Result where - F: FnOnce(&mut U8Decoder, bool) -> Result, - { - Err(Error::Syntax) - } - - #[inline] - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut U8Decoder, usize) -> Result, - { - let len = self.len; - f(self, len) - } - #[inline] - fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - f(self) - } - - fn read_map(&mut self, _f: F) -> Result where - F: FnOnce(&mut U8Decoder, usize) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_key(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - - fn read_map_elt_val(&mut self, _idx: usize, _f: F) -> Result where - F: FnOnce(&mut U8Decoder) -> Result, - { - Err(Error::Syntax) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -mod deserializer { - //use std::num; - use std::vec; - - use super::Error; - - use serde::de; - - #[derive(PartialEq, Debug)] - enum State { - Start, - SepOrEnd, - End, - } - - pub struct Deserializer { - state: State, - iter: vec::IntoIter, - len: usize, - value: Option, - } - - impl Deserializer { - #[inline] - pub fn new(values: Vec) -> Deserializer { - let len = values.len(); - Deserializer { - state: State::Start, - iter: values.into_iter(), - len: len, - value: None, - } - } - } - - impl de::Deserializer for Deserializer { - type Error = Error; - - #[inline] - fn deserialize(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - match self.state { - State::Start => { - self.state = State::SepOrEnd; - visitor.visit_seq(self) - } - State::SepOrEnd => { - visitor.visit_usize(self.value.take().unwrap()) - } - State::End => { - Err(Error::EndOfStream) - } - } - } - } - - impl de::SeqVisitor for Deserializer { - type Error = Error; - - #[inline] - fn visit(&mut self) -> Result, Error> - where T: de::Deserialize, - { - match self.iter.next() { - Some(value) => { - self.len -= 1; - self.value = Some(value); - Ok(Some(try!(de::Deserialize::deserialize(self)))) - } - None => { - self.state = State::End; - Ok(None) - } - } - } - - #[inline] - fn end(&mut self) -> Result<(), Error> { - match self.iter.next() { - Some(_) => Err(Error::Syntax), - None => { - self.state = State::End; - Ok(()) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } - } - - impl de::Deserializer for Deserializer { - type Error = Error; - - #[inline] - fn deserialize(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - match self.state { - State::Start => { - self.state = State::SepOrEnd; - visitor.visit_seq(self) - } - State::SepOrEnd => { - visitor.visit_u8(self.value.take().unwrap()) - } - State::End => { - Err(Error::EndOfStream) - } - } - } - } - - impl de::SeqVisitor for Deserializer { - type Error = Error; - - #[inline] - fn visit(&mut self) -> Result, Error> - where T: de::Deserialize, - { - match self.iter.next() { - Some(value) => { - self.len -= 1; - self.value = Some(value); - Ok(Some(try!(de::Deserialize::deserialize(self)))) - } - None => { - self.state = State::End; - Ok(None) - } - } - } - - #[inline] - fn end(&mut self) -> Result<(), Error> { - match self.iter.next() { - Some(_) => Err(Error::Syntax), - None => { - self.state = State::End; - Ok(()) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -fn run_decoder< - D: Decoder, - T: Clone + PartialEq + Debug + Decodable ->(mut d: D, value: T) { - let v = Decodable::decode(&mut d); - - assert_eq!(Ok(value), v); -} - -fn run_deserializer(mut d: D, value: T) - where D: Deserializer, - D::Error: Debug + PartialEq, - T: Clone + PartialEq + Debug + Deserialize -{ - let v = T::deserialize(&mut d); - - assert_eq!(Ok(value), v); -} - -#[bench] -fn bench_decoder_usize_000(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(); - run_decoder(decoder::UsizeDecoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_decoder_usize_003(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(1, 2, 3); - run_decoder(decoder::UsizeDecoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_decoder_usize_100(b: &mut Bencher) { - b.iter(|| { - let v: Vec = (0 .. 100).collect(); - run_decoder(decoder::UsizeDecoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_decoder_u8_000(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(); - run_decoder(decoder::U8Decoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_decoder_u8_003(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(1, 2, 3); - run_decoder(decoder::U8Decoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_decoder_u8_100(b: &mut Bencher) { - b.iter(|| { - let v: Vec = (0 .. 100).collect(); - run_decoder(decoder::U8Decoder::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_usize_000(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_usize_003(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(1, 2, 3); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_usize_100(b: &mut Bencher) { - b.iter(|| { - let v: Vec = (0 .. 100).collect(); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_u8_000(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_u8_003(b: &mut Bencher) { - b.iter(|| { - let v: Vec = vec!(1, 2, 3); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} - -#[bench] -fn bench_deserializer_u8_100(b: &mut Bencher) { - b.iter(|| { - let v: Vec = (0 .. 100).collect(); - run_deserializer(deserializer::Deserializer::new(v.clone()), v) - }) -} diff --git a/testing/build.rs b/testing/build.rs index ad175e85..bf4a763b 100644 --- a/testing/build.rs +++ b/testing/build.rs @@ -5,13 +5,7 @@ use std::path::Path; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); - - for &(src, dst) in &[ - ("tests/test.rs.in", "test.rs"), - ("benches/bench.rs.in", "bench.rs"), - ] { - let src = Path::new(src); - let dst = Path::new(&out_dir).join(dst); - serde_codegen::expand(&src, &dst).unwrap(); - } + let src = Path::new("tests/test.rs.in"); + let dst = Path::new(&out_dir).join("test.rs"); + serde_codegen::expand(&src, &dst).unwrap(); } diff --git a/testing/tests/test.rs.in b/testing/tests/test.rs.in index fca1ff46..04c69bdb 100644 --- a/testing/tests/test.rs.in +++ b/testing/tests/test.rs.in @@ -1,4 +1,5 @@ extern crate serde; +extern crate serde_test; #[macro_use] mod macros; diff --git a/testing/tests/test_bytes.rs b/testing/tests/test_bytes.rs index 000aa091..a0e5fbcc 100644 --- a/testing/tests/test_bytes.rs +++ b/testing/tests/test_bytes.rs @@ -1,11 +1,13 @@ use std::fmt; use std::error; -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde::{Serialize, Serializer}; use serde::bytes::{ByteBuf, Bytes}; use serde::ser; use serde::de; +use serde_test::{assert_de_tokens, Token}; + /////////////////////////////////////////////////////////////////////////////// #[derive(Debug, PartialEq)] @@ -286,153 +288,6 @@ impl Serializer for BytesSerializer { /////////////////////////////////////////////////////////////////////////////// -struct BytesDeserializer { - bytes: Option>, -} - -impl BytesDeserializer { - fn new(bytes: Vec) -> Self { - BytesDeserializer { - bytes: Some(bytes), - } - } -} - -impl Deserializer for BytesDeserializer { - type Error = Error; - - fn deserialize(&mut self, _visitor: V) -> Result - where V: de::Visitor, - { - Err(Error) - } - - fn deserialize_bytes(&mut self, mut visitor: V) -> Result - where V: de::Visitor, - { - visitor.visit_byte_buf(self.bytes.take().unwrap()) - } - - fn deserialize_seq<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_struct_field<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_map<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_unit<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_ignored_any<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_string<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_str<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_char<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_i64<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_i32<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_i16<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_i8<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_u64<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_u32<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_u16<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_u8<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_f32<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_f64<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_bool<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_usize<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_isize<__V>(&mut self, visitor: __V) -> Result<__V::Value, Self::Error> - where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_option<__V>(&mut self, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_seq_fixed_size<__V>(&mut self, _: usize, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_unit_struct<__V>(&mut self, _: &str, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_newtype_struct<__V>(&mut self, _: &str, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_tuple_struct<__V>(&mut self, _: &str, _: usize, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_struct<__V>(&mut self, _: &str, _: &[&str], visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_tuple<__V>(&mut self, _: usize, visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - self.deserialize(visitor) - } - fn deserialize_enum<__V>(&mut self, _: &str, _: &[&str], _visitor: __V) - -> Result<__V::Value, Self::Error> where __V: de::Visitor { - Err(Error) - } -} - -/////////////////////////////////////////////////////////////////////////////// - #[test] fn test_bytes_ser_bytes() { let buf = vec![]; @@ -449,12 +304,42 @@ fn test_bytes_ser_bytes() { /////////////////////////////////////////////////////////////////////////////// #[test] -fn test_byte_buf_de_bytes() { - let mut de = BytesDeserializer::new(vec![]); - let bytes = Deserialize::deserialize(&mut de); - assert_eq!(bytes, Ok(ByteBuf::new())); +fn test_byte_buf_de() { + let empty = ByteBuf::new(); + assert_de_tokens(&empty, &[Token::Bytes(b""),]); + assert_de_tokens(&empty, &[Token::Str("")]); + assert_de_tokens(&empty, &[Token::String(String::new())]); + assert_de_tokens(&empty, &[ + Token::SeqStart(None), + Token::SeqEnd, + ]); + assert_de_tokens(&empty, &[ + Token::SeqStart(Some(0)), + Token::SeqEnd, + ]); - let mut de = BytesDeserializer::new(vec![1, 2, 3]); - let bytes = Deserialize::deserialize(&mut de); - assert_eq!(bytes, Ok(ByteBuf::from(vec![1, 2, 3]))); + let buf = ByteBuf::from(vec![65, 66, 67]); + assert_de_tokens(&buf, &[Token::Bytes(b"ABC")]); + assert_de_tokens(&buf, &[Token::Str("ABC")]); + assert_de_tokens(&buf, &[Token::String("ABC".to_owned())]); + assert_de_tokens(&buf, &[ + Token::SeqStart(None), + Token::SeqSep, + Token::U8(65), + Token::SeqSep, + Token::U8(66), + Token::SeqSep, + Token::U8(67), + Token::SeqEnd, + ]); + assert_de_tokens(&buf, &[ + Token::SeqStart(Some(3)), + Token::SeqSep, + Token::U8(65), + Token::SeqSep, + Token::U8(66), + Token::SeqSep, + Token::U8(67), + Token::SeqEnd, + ]); } diff --git a/testing/tests/test_de.rs b/testing/tests/test_de.rs index 162bf016..280d427f 100644 --- a/testing/tests/test_de.rs +++ b/testing/tests/test_de.rs @@ -37,7 +37,10 @@ enum Enum { Unit, Simple(i32), Seq(i32, i32, i32), - Map { a: i32, b: i32, c: i32 } + Map { a: i32, b: i32, c: i32 }, + #[allow(dead_code)] + #[serde(skip_deserializing)] + Skipped, } ////////////////////////////////////////////////////////////////////////// @@ -215,6 +218,9 @@ declare_tests! { Token::SeqEnd, ], } + test_unit_string { + String::new() => &[Token::Unit], + } test_tuple_struct { TupleStruct(1, 2, 3) => &[ Token::SeqStart(Some(3)), @@ -802,6 +808,12 @@ declare_error_tests! { ], Error::UnknownVariant("Foo".to_owned()), } + test_enum_skipped_variant { + &[ + Token::EnumUnit("Enum", "Skipped"), + ], + Error::UnknownVariant("Skipped".to_owned()), + } test_struct_seq_too_long { &[ Token::SeqStart(Some(4)), diff --git a/testing/tests/test_gen.rs b/testing/tests/test_gen.rs index 7d648f57..c52ebcad 100644 --- a/testing/tests/test_gen.rs +++ b/testing/tests/test_gen.rs @@ -9,6 +9,11 @@ use self::serde::de::{Deserialize, Deserializer}; use std::borrow::Cow; use std::marker::PhantomData; +// Try to trip up the generated code if it fails to use fully qualified paths. +#[allow(dead_code)] +struct Result; +use std::result::Result as StdResult; + ////////////////////////////////////////////////////////////////////////// #[test] @@ -187,6 +192,16 @@ fn test_gen() { #[serde(bound(deserialize = "T::Owned: Deserialize"))] struct CowT<'a, T: ?Sized + 'a + ToOwned>(Cow<'a, T>); assert::>(); + + #[derive(Serialize, Deserialize)] + struct EmptyStruct {} + assert::(); + + #[derive(Serialize, Deserialize)] + enum EmptyEnumVariant { + EmptyStruct {}, + } + assert::(); } ////////////////////////////////////////////////////////////////////////// @@ -195,32 +210,32 @@ fn assert() {} fn assert_ser() {} trait SerializeWith { - fn serialize_with(_: &Self, _: &mut S) -> Result<(), S::Error>; + fn serialize_with(_: &Self, _: &mut S) -> StdResult<(), S::Error>; } trait DeserializeWith: Sized { - fn deserialize_with(_: &mut D) -> Result; + fn deserialize_with(_: &mut D) -> StdResult; } // Implements neither Serialize nor Deserialize struct X; -fn ser_x(_: &X, _: &mut S) -> Result<(), S::Error> { +fn ser_x(_: &X, _: &mut S) -> StdResult<(), S::Error> { unimplemented!() } -fn de_x(_: &mut D) -> Result { +fn de_x(_: &mut D) -> StdResult { unimplemented!() } impl SerializeWith for X { - fn serialize_with(_: &Self, _: &mut S) -> Result<(), S::Error> { + fn serialize_with(_: &Self, _: &mut S) -> StdResult<(), S::Error> { unimplemented!() } } impl DeserializeWith for X { - fn deserialize_with(_: &mut D) -> Result { + fn deserialize_with(_: &mut D) -> StdResult { unimplemented!() } } diff --git a/testing/tests/test_macros.rs b/testing/tests/test_macros.rs index a6b1d167..6e5e1d82 100644 --- a/testing/tests/test_macros.rs +++ b/testing/tests/test_macros.rs @@ -600,3 +600,28 @@ fn test_default_ty_param() { ] ); } + +#[test] +fn test_enum_state_field() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + enum SomeEnum { + Key { key: char, state: bool }, + } + + assert_tokens( + &SomeEnum::Key { key: 'a', state: true }, + &[ + Token::EnumMapStart("SomeEnum", "Key", 2), + + Token::EnumMapSep, + Token::Str("key"), + Token::Char('a'), + + Token::EnumMapSep, + Token::Str("state"), + Token::Bool(true), + + Token::EnumMapEnd, + ] + ); +} diff --git a/testing/tests/test_ser.rs b/testing/tests/test_ser.rs index 52573533..3a5a5748 100644 --- a/testing/tests/test_ser.rs +++ b/testing/tests/test_ser.rs @@ -30,12 +30,20 @@ struct Struct { c: i32, } -#[derive(Serialize)] +#[derive(Serialize, PartialEq, Debug)] enum Enum { Unit, One(i32), Seq(i32, i32), Map { a: i32, b: i32 }, + #[serde(skip_serializing)] + SkippedUnit, + #[serde(skip_serializing)] + SkippedOne(i32), + #[serde(skip_serializing)] + SkippedSeq(i32, i32), + #[serde(skip_serializing)] + SkippedMap { _a: i32, _b: i32 }, } ////////////////////////////////////////////////////////////////////////// @@ -388,3 +396,23 @@ fn test_cannot_serialize_paths() { &[], Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned())); } + +#[test] +fn test_enum_skipped() { + assert_ser_tokens_error( + &Enum::SkippedUnit, + &[], + Error::InvalidValue("The enum variant Enum::SkippedUnit cannot be serialized".to_owned())); + assert_ser_tokens_error( + &Enum::SkippedOne(42), + &[], + Error::InvalidValue("The enum variant Enum::SkippedOne cannot be serialized".to_owned())); + assert_ser_tokens_error( + &Enum::SkippedSeq(1, 2), + &[], + Error::InvalidValue("The enum variant Enum::SkippedSeq cannot be serialized".to_owned())); + assert_ser_tokens_error( + &Enum::SkippedMap { _a: 1, _b: 2 }, + &[], + Error::InvalidValue("The enum variant Enum::SkippedMap cannot be serialized".to_owned())); +}