Compare commits

...

57 Commits

Author SHA1 Message Date
Erick Tryzelaar 37c0ad19bb Version bump 2015-06-25 16:10:52 -07:00
Erick Tryzelaar ed5b4d7319 Fix serializing generic enums
This fixes generic enums with variants that don't use all lifetime
and typarams. Closes #88.
2015-06-18 08:45:03 -07:00
Erick Tryzelaar b09c0fc653 Fix an indent typo 2015-06-18 07:49:13 -07:00
Erick Tryzelaar ab3e40ca45 Version bump 2015-06-08 07:12:27 -07:00
Erick Tryzelaar 8f67e9c048 Switch exponent bounds checking back to using powi 2015-06-08 07:07:09 -07:00
Erick Tryzelaar 7dc1a64f03 Merge pull request #80 from ProtectedMode/master
Fix #77, integer overflow when parsing JSON scientific notation number.
2015-06-08 06:57:33 -07:00
Erick Tryzelaar ac3a3e922f Fix compilation with rust nightly (613e57b44) and syntex 0.7.0 2015-06-08 06:55:36 -07:00
Erick Tryzelaar 4e50c56542 Merge pull request #87 from Manishearth/patch-1
Use correct attribute syntax
2015-06-07 20:46:44 -07:00
Manish Goregaokar 26b1ed79c0 !!!!!! 2015-06-06 18:08:33 +05:30
ProtectedMode 2e8ef0f768 Add test for #77, integer overflow when parsing JSON scientific notation number. 2015-05-21 09:59:14 +02:00
Erick Tryzelaar c993414b92 serde_tests tests doesn't need the test crate 2015-05-20 22:57:19 -07:00
Erick Tryzelaar ed6ef4e149 Travis work 2015-05-20 22:44:50 -07:00
Erick Tryzelaar 859cdcc815 Remove unnecessary lifetime 2015-05-20 09:02:38 -07:00
ProtectedMode 745a95b607 Fix #77, integer overflow when parsing JSON scientific notation number. 2015-05-20 16:32:10 +02:00
Erick Tryzelaar 81d617bd93 The README is in a different location 2015-05-18 23:36:46 -07:00
Erick Tryzelaar 3396388222 Remove redundant import 2015-05-18 23:34:17 -07:00
Erick Tryzelaar ff8c3b3d51 Initial support for syntex 2015-05-18 23:34:17 -07:00
Erick Tryzelaar 3d0efd123f Minor cleanup 2015-05-18 22:49:50 -07:00
Erick Tryzelaar 8ca1b9ac3c default_value doesn't need to be public 2015-05-18 22:49:49 -07:00
Erick Tryzelaar 2c24be90d2 Switch to using MultiDecorator 2015-05-18 22:49:49 -07:00
Erick Tryzelaar 482f92af61 Add a single driver for tests and benchmarks 2015-05-18 22:47:36 -07:00
Erick Tryzelaar 24ac61f9f2 Pull codegen into it's own crate 2015-05-18 22:47:35 -07:00
Erick Tryzelaar 426394cd7b Version bump 2015-05-18 22:47:35 -07:00
Erick Tryzelaar 7c3e95a7c7 Ignore all target and Cargo.lock files 2015-05-18 22:47:35 -07:00
Erick Tryzelaar 9dd5f9dc7a Restructure directories to prep for syntex 2015-05-18 22:47:35 -07:00
Erick Tryzelaar e6776ffc37 Protect against json integer overflow
Closes #75
2015-05-18 22:40:29 -07:00
Erick Tryzelaar adae2bd3c5 Merge pull request #72 from borman/bytestrings
Improved support for byte strings
2015-05-18 22:28:37 -07:00
Erick Tryzelaar 14ca260c26 Merge pull request #70 from oli-obk/xml_requirements
changes needed for xml parsing
2015-05-18 22:25:15 -07:00
Erick Tryzelaar 64588f0cb6 Merge pull request #74 from tomprogrammer/array
Add serialization/deserialization for fixed size arrays
2015-05-18 22:21:59 -07:00
Erick Tryzelaar 50cac7f985 Rewrite Value::lookup to not require an allocation 2015-05-18 22:19:30 -07:00
Erick Tryzelaar 5fe85128c2 Merge pull request #76 from blaenk/json-lookup
implement lookup method for json::Value
2015-05-18 21:50:55 -07:00
Jorge Israel Peña bc236bde34 implement lookup method for json::Value 2015-05-17 21:24:00 -07:00
Thomas Bahn 15794a5ed6 Improve build time 2015-05-16 14:36:28 +02:00
Thomas Bahn 62058962de Add deserialiation implementations for fixed size arrays 2015-05-16 14:19:22 +02:00
Thomas Bahn 7d52366403 Add serialization implementations for fixed size arrays 2015-05-16 14:18:32 +02:00
Erick Tryzelaar ee45eb8340 Merge pull request #69 from hugoduncan/feature/format-specific-field-names
Adds serializer format specific field names
2015-05-14 21:59:05 -07:00
Hugo Duncan 801f37b305 Fix visitors for generic structs 2015-05-14 17:35:21 -04:00
Hugo Duncan bdec0b3e63 Update commas and blocks in match arms 2015-05-14 17:35:16 -04:00
Mikhail Borisov 5c631f3e58 WIP 2015-05-12 15:16:06 +03:00
Mikhail Borisov 5fd9daa865 WIP 2015-05-12 15:03:26 +03:00
Oliver Schneider 0485702a68 update benchmarks 2015-05-11 10:34:58 +02:00
Mikhail Borisov 875610044f Improved support for byte strings 2015-05-09 03:18:13 +03:00
Hugo Duncan ec483fc07d Add doc string for format method 2015-05-08 12:43:12 -04:00
Hugo Duncan 53e6e29571 Fix whitespace 2015-05-08 12:43:12 -04:00
Hugo Duncan c5eed99c6a Make forwarded trait name global 2015-05-08 12:43:12 -04:00
Hugo Duncan fe5176113b Add missing attr.rs file 2015-05-08 12:43:12 -04:00
Hugo Duncan 0f7c67efa7 Factor default attribute lookup into FieldAttrs 2015-05-08 12:43:12 -04:00
Hugo Duncan cd0ee64892 Add constructor functions for FieldAttrs 2015-05-08 12:43:12 -04:00
Hugo Duncan ec3af2cb6a Factor out attr module
Factors out field attribute code into the attr module.
2015-05-08 12:43:12 -04:00
Hugo Duncan 960b68937d Remove commented code and extra newline 2015-05-08 12:43:12 -04:00
Hugo Duncan a1e101b513 Make Value use the 'json' format string 2015-05-08 12:43:11 -04:00
Hugo Duncan c30311153c Rename fmt to format 2015-05-08 12:43:11 -04:00
Hugo Duncan a935ebe8b9 Adds serializer format specific field names
Allows different field names to be used for different external formats.

Field names are specified using the `rename` field attribute, e.g:

    #[serde(rename(xml= "a4", json="a5"))]

Reverts #62

Addresses #61
2015-05-08 12:43:11 -04:00
Oliver Schneider 83ee86122b address comments by erickt 2015-05-08 16:32:46 +02:00
Erick Tryzelaar af752ddcb5 Merge pull request #71 from lifthrasiir/json-split-branch
Replace a redundant `escape` variable with nested matches.
2015-05-07 10:51:57 -07:00
Kang Seonghoon 9550063275 Replace a redundant escape variable with nested matches.
This has a non-trivial performance effect due to the branch prediction,
but is expected to be no slower than the older code and, at least in
some cases, is slightly faster for a string-heavy JSON.
2015-05-08 01:53:24 +09:00
Oliver Schneider c117a680cf changes needed for xml parsing 2015-05-04 16:07:19 +02:00
51 changed files with 1596 additions and 437 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
/target/ target
/Cargo.lock Cargo.lock
+25 -7
View File
@@ -1,16 +1,34 @@
language: rust language: rust
rust:
- stable
- beta
- nightly
env:
global:
secure: HO41LMpMXkF2In9+1sxWVu7fgolL+y9+4Q5PI6wZX2L5pDwpPJCjxaQarQXCEnoIxED1PlP03JuF7ULNz0zw1ylYhAOfOSdkxFZRnE2wMZqq6qvXBHwyMiDrAociIzoPKSGv7JVrKPsjsnd+96K6xxueIodQZrmAdyq7N/M82Mc=
matrix:
- CRATE=serde_tests TARGET=test
matrix:
include:
- rust: nightly
env: CRATE=serde_macros TARGET=test
- rust: nightly
env: CRATE=serde_macros TARGET=bench
- rust: nightly
env: CRATE=serde_tests TARGET=bench
script: script:
- cargo test - (cd $CRATE && cargo $TARGET)
- cargo bench
- cargo doc
after_success: | after_success: |
[ $TRAVIS_BRANCH = "master" ] && [ $TRAVIS_BRANCH = "master" ] &&
[ $TRAVIS_PULL_REQUEST = false ] && [ $TRAVIS_PULL_REQUEST = false ] &&
cargo doc && mkdir -p target/doc &&
(cd serde && cargo doc --no-deps) &&
(cd serde_codegen && cargo doc --no-deps) &&
(cd serde_macros && cargo doc --no-deps) &&
cp -r serde/target/doc target/doc/serde &&
cp -r serde_codegen/target/doc target/doc/serde_codegen &&
cp -r serde_macros/target/doc target/doc/serde_macros &&
echo "<meta http-equiv=refresh content=0;url=`echo $TRAVIS_REPO_SLUG | cut -d '/' -f 2`/index.html>" > target/doc/index.html && echo "<meta http-equiv=refresh content=0;url=`echo $TRAVIS_REPO_SLUG | cut -d '/' -f 2`/index.html>" > target/doc/index.html &&
sudo pip install ghp-import && sudo pip install ghp-import &&
ghp-import -n target/doc && ghp-import -n target/doc &&
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
env:
global:
secure: HO41LMpMXkF2In9+1sxWVu7fgolL+y9+4Q5PI6wZX2L5pDwpPJCjxaQarQXCEnoIxED1PlP03JuF7ULNz0zw1ylYhAOfOSdkxFZRnE2wMZqq6qvXBHwyMiDrAociIzoPKSGv7JVrKPsjsnd+96K6xxueIodQZrmAdyq7N/M82Mc=
+2 -2
View File
@@ -24,8 +24,8 @@ and
for the annotated type: for the annotated type:
```rust ```rust
#[feature(custom_derive, plugin)] #![feature(custom_derive, plugin)]
#[plugin(serde_macros)] #![plugin(serde_macros)]
extern crate serde; extern crate serde;
+2 -6
View File
@@ -1,17 +1,13 @@
[package] [package]
name = "serde" name = "serde"
version = "0.3.3" version = "0.4.2"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
repository = "https://github.com/serde-rs/serde" repository = "https://github.com/serde-rs/serde"
documentation = "http://serde-rs.github.io/serde/serde" documentation = "http://serde-rs.github.io/serde/serde"
readme = "README.md" readme = "../README.md"
keywords = ["serialization"] keywords = ["serialization"]
[dependencies] [dependencies]
num = "*" num = "*"
[dev-dependencies]
rustc-serialize = "*"
serde_macros = { version = "*", path = "serde_macros" }
+94
View File
@@ -0,0 +1,94 @@
use std::cmp;
use std::io;
use std::slice;
trait IntoBufRead {
type IntoBuf: io::BufRead + BufReadExt;
fn into_buf_read(self) -> Self::IntoBuf;
}
trait BufReadExt {
fn get_buf(&self) -> &[u8];
fn read_u8(&mut self) -> io::Result<Option<u8>>;
}
struct SliceReader<'a> {
buf: &'a [u8],
}
impl<'a> io::Read for SliceReader<'a> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.buf.len());
let (a, b) = self.buf.split_at(amt);
slice::bytes::copy_memory(buf, a);
*self.buf = b;
Ok(amt)
}
}
impl<'a> io::BufRead for SliceReader<'a> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
fn consume(&mut self, amt: usize) { *self.buf = &self.buf[amt..]; }
}
impl<'a> BufReadExt for SliceReader<'a> {
fn get_buf(&self) -> &[u8] { self.buf }
fn read_u8(&mut self) -> io::Result<Option<u8>> {
let byte = self.buf.get(0);
*self.buf = &self.buf[1..];
byte
}
}
struct BufReader<R> {
inner: R,
buf: io::Cursor<Vec<u8>>,
}
impl<R> BufReader<R> where R: io::Read {
fn new(inner: R) -> Self {
BufferedReader::with_capacity(io::DEFAULT_BUF_SIZE, inner)
}
fn new(cap: usize, inner: R) -> Self {
BufferedReader {
inner: inner,
buf: io::Cursor::new(Vec::with_capacity(cap)),
}
}
fn into_inner(self) -> R {
self.inner
}
}
impl<R> Read for BufReader<R> where R: io::Read {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
if self.buf.get_ref().len() == self.buf.position() as usize &&
buf.len() >= self.buf.get_ref().capacity() {
return self.inner.read(buf);
}
try!(self.fill_buf());
self.buf.read(buf)
}
}
impl<R> BufReadExt for BufReader<R> {
fn get_buf(&self) -> &[u8] {
self.buf.get_ref()
}
fn read_u8(&mut self) -> io::Result<Option<u8>> {
if self.buf.get_ref().len() == self.buf.position() as usize {
}
let byte = self.buf.get(0);
*self.buf = &self.buf[1..];
byte
}
}
+43 -4
View File
@@ -1,6 +1,8 @@
//! Helper module to enable serializing bytes more efficiently //! Helper module to enable serializing bytes more efficiently
use std::ops; use std::ops;
use std::fmt;
use std::ascii;
use ser; use ser;
use de; use de;
@@ -8,10 +10,17 @@ use de;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// `Bytes` wraps a `&[u8]` in order to serialize into a byte array. /// `Bytes` wraps a `&[u8]` in order to serialize into a byte array.
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Bytes<'a> { pub struct Bytes<'a> {
bytes: &'a [u8], bytes: &'a [u8],
} }
impl<'a> fmt::Debug for Bytes<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "b\"{}\"", escape_bytestring(self.bytes))
}
}
impl<'a> From<&'a [u8]> for Bytes<'a> { impl<'a> From<&'a [u8]> for Bytes<'a> {
fn from(bytes: &'a [u8]) -> Self { fn from(bytes: &'a [u8]) -> Self {
Bytes { Bytes {
@@ -28,6 +37,12 @@ impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
} }
} }
impl<'a> Into<&'a [u8]> for Bytes<'a> {
fn into(self) -> &'a [u8] {
self.bytes
}
}
impl<'a> ops::Deref for Bytes<'a> { impl<'a> ops::Deref for Bytes<'a> {
type Target = [u8]; type Target = [u8];
@@ -46,7 +61,7 @@ impl<'a> ser::Serialize for Bytes<'a> {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// `ByteBuf` wraps a `Vec<u8>` in order to hook into serialize and from deserialize a byte array. /// `ByteBuf` wraps a `Vec<u8>` in order to hook into serialize and from deserialize a byte array.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf { pub struct ByteBuf {
bytes: Vec<u8>, bytes: Vec<u8>,
} }
@@ -65,10 +80,22 @@ impl ByteBuf {
} }
} }
impl<T> From<T> for ByteBuf where T: Into<Vec<u8>> { impl fmt::Debug for ByteBuf {
fn from(bytes: T) -> Self { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "b\"{}\"", escape_bytestring(self.bytes.as_ref()))
}
}
impl Into<Vec<u8>> for ByteBuf {
fn into(self) -> Vec<u8> {
self.bytes
}
}
impl From<Vec<u8>> for ByteBuf {
fn from(bytes: Vec<u8>) -> Self {
ByteBuf { ByteBuf {
bytes: bytes.into(), bytes: bytes,
} }
} }
} }
@@ -172,3 +199,15 @@ impl de::Deserialize for ByteBuf {
deserializer.visit_bytes(ByteBufVisitor) deserializer.visit_bytes(ByteBufVisitor)
} }
} }
///////////////////////////////////////////////////////////////////////////////
fn escape_bytestring(bytes: &[u8]) -> String {
let mut result = String::new();
for &b in bytes {
for esc in ascii::escape_default(b) {
result.push(esc as char);
}
}
result
}
+173 -3
View File
@@ -3,6 +3,7 @@ use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::path; use std::path;
use std::rc::Rc; use std::rc::Rc;
use std::str;
use std::sync::Arc; use std::sync::Arc;
use num::FromPrimitive; use num::FromPrimitive;
@@ -56,6 +57,16 @@ impl Visitor for BoolVisitor {
{ {
Ok(v) Ok(v)
} }
fn visit_str<E>(&mut self, s: &str) -> Result<bool, E>
where E: Error,
{
match s.trim() {
"true" => Ok(true),
"false" => Ok(false),
_ => Err(Error::syntax_error()),
}
}
} }
impl Deserialize for bool { impl Deserialize for bool {
@@ -96,7 +107,7 @@ impl<T> PrimitiveVisitor<T> {
} }
impl< impl<
T: Deserialize + FromPrimitive T: Deserialize + FromPrimitive + str::FromStr
> Visitor for PrimitiveVisitor<T> { > Visitor for PrimitiveVisitor<T> {
type Value = T; type Value = T;
@@ -112,6 +123,13 @@ impl<
impl_deserialize_num_method!(u64, visit_u64, from_u64); impl_deserialize_num_method!(u64, visit_u64, from_u64);
impl_deserialize_num_method!(f32, visit_f32, from_f32); impl_deserialize_num_method!(f32, visit_f32, from_f32);
impl_deserialize_num_method!(f64, visit_f64, from_f64); impl_deserialize_num_method!(f64, visit_f64, from_f64);
#[inline]
fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
where E: Error,
{
str::FromStr::from_str(v.trim()).or(Err(Error::syntax_error()))
}
} }
macro_rules! impl_deserialize_num { macro_rules! impl_deserialize_num {
@@ -198,6 +216,24 @@ impl Visitor for StringVisitor {
{ {
Ok(v) Ok(v)
} }
fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<String, E>
where E: Error,
{
match str::from_utf8(v) {
Ok(s) => Ok(s.to_string()),
Err(_) => Err(Error::syntax_error()),
}
}
fn visit_byte_buf<'a, E>(&mut self, v: Vec<u8>) -> Result<String, E>
where E: Error,
{
match String::from_utf8(v) {
Ok(s) => Ok(s),
Err(_) => Err(Error::syntax_error()),
}
}
} }
impl Deserialize for String { impl Deserialize for String {
@@ -394,12 +430,146 @@ impl<T> Deserialize for Vec<T>
fn deserialize<D>(deserializer: &mut D) -> Result<Vec<T>, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Vec<T>, D::Error>
where D: Deserializer, where D: Deserializer,
{ {
deserializer.visit(VecVisitor::new()) deserializer.visit_seq(VecVisitor::new())
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
struct ArrayVisitor0<T> {
marker: PhantomData<T>,
}
impl<T> ArrayVisitor0<T> {
pub fn new() -> Self {
ArrayVisitor0 {
marker: PhantomData,
}
}
}
impl<T> Visitor for ArrayVisitor0<T> where T: Deserialize + Default {
type Value = [T; 0];
#[inline]
fn visit_unit<E>(&mut self) -> Result<[T; 0], E>
where E: Error,
{
Ok([T::default(); 0])
}
#[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<[T; 0], V::Error>
where V: SeqVisitor,
{
try!(visitor.end());
Ok([T::default(); 0])
}
}
impl<T> Deserialize for [T; 0]
where T: Deserialize + Default
{
fn deserialize<D>(deserializer: &mut D) -> Result<[T; 0], D::Error>
where D: Deserializer,
{
deserializer.visit(ArrayVisitor0::new())
}
}
macro_rules! array_impls {
($($visitor:ident, $len:expr => ($($name:ident),+),)+) => {
$(
struct $visitor<T> {
marker: PhantomData<T>,
}
impl<T> $visitor<T> {
pub fn new() -> Self {
$visitor {
marker: PhantomData
}
}
}
impl<T> Visitor for $visitor<T> where T: Deserialize {
type Value = [T; $len];
#[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<[T; $len], V::Error>
where V: SeqVisitor,
{
$(
let $name = match try!(visitor.visit()) {
Some(val) => val,
None => { return Err(Error::end_of_stream_error()); }
};
)+;
try!(visitor.end());
Ok([$($name,)+])
}
}
impl<T> Deserialize for [T; $len]
where T: Deserialize,
{
fn deserialize<D>(deserializer: &mut D) -> Result<[T; $len], D::Error>
where D: Deserializer,
{
deserializer.visit($visitor::new())
}
}
)+
}
}
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),
}
///////////////////////////////////////////////////////////////////////////////
macro_rules! tuple_impls { macro_rules! tuple_impls {
() => {}; () => {};
($($visitor:ident => ($($name:ident),+),)+) => { ($($visitor:ident => ($($name:ident),+),)+) => {
@@ -438,7 +608,7 @@ macro_rules! tuple_impls {
fn deserialize<D>(deserializer: &mut D) -> Result<($($name,)+), D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<($($name,)+), D::Error>
where D: Deserializer, where D: Deserializer,
{ {
deserializer.visit($visitor { marker: PhantomData }) deserializer.visit_seq($visitor { marker: PhantomData })
} }
} }
)+ )+
+12 -3
View File
@@ -113,12 +113,21 @@ pub trait Deserializer {
{ {
self.visit(visitor) self.visit(visitor)
} }
/// Specify a format string for the deserializer.
///
/// The deserializer format is used to determine which format
/// specific field attributes should be used with the
/// deserializer.
fn format() -> &'static str {
""
}
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
pub trait Visitor { pub trait Visitor {
type Value; type Value: Deserialize;
fn visit_bool<E>(&mut self, _v: bool) -> Result<Self::Value, E> fn visit_bool<E>(&mut self, _v: bool) -> Result<Self::Value, E>
where E: Error, where E: Error,
@@ -263,10 +272,10 @@ pub trait Visitor {
Err(Error::syntax_error()) Err(Error::syntax_error())
} }
fn visit_byte_buf<E>(&mut self, _v: Vec<u8>) -> Result<Self::Value, E> fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::syntax_error()) self.visit_bytes(&v)
} }
} }
+54
View File
@@ -12,6 +12,7 @@ use std::hash::Hash;
use std::vec; use std::vec;
use de; use de;
use bytes;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -409,3 +410,56 @@ impl<K, V> ValueDeserializer for HashMap<K, V>
MapDeserializer::new(self.into_iter(), len) MapDeserializer::new(self.into_iter(), len)
} }
} }
///////////////////////////////////////////////////////////////////////////////
impl<'a> ValueDeserializer for bytes::Bytes<'a>
{
type Deserializer = BytesDeserializer<'a>;
fn into_deserializer(self) -> BytesDeserializer<'a> {
BytesDeserializer(Some(self.into()))
}
}
pub struct BytesDeserializer<'a> (Option<&'a [u8]>);
impl<'a> de::Deserializer for BytesDeserializer<'a> {
type Error = Error;
fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
where V: de::Visitor,
{
match self.0.take() {
Some(bytes) => visitor.visit_bytes(bytes),
None => Err(de::Error::end_of_stream_error()),
}
}
}
///////////////////////////////////////////////////////////////////////////////
impl ValueDeserializer for bytes::ByteBuf
{
type Deserializer = ByteBufDeserializer;
fn into_deserializer(self) -> Self::Deserializer {
ByteBufDeserializer(Some(self.into()))
}
}
pub struct ByteBufDeserializer(Option<Vec<u8>>);
impl de::Deserializer for ByteBufDeserializer {
type Error = Error;
fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
where V: de::Visitor,
{
match self.0.take() {
Some(bytes) => visitor.visit_byte_buf(bytes),
None => Err(de::Error::end_of_stream_error()),
}
}
}
+7 -1
View File
@@ -1,4 +1,5 @@
use std::io; use std::io;
use std::iter::Peekable;
pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> { pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
iter: Iter, iter: Iter,
@@ -25,12 +26,17 @@ impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
pub fn get_ref(&self) -> &Iter { &self.iter } pub fn get_ref(&self) -> &Iter { &self.iter }
/// Gets a mutable reference to the underlying iterator. /// Gets a mutable reference to the underlying iterator.
pub fn get_mut(&self) -> &Iter { &self.iter } pub fn get_mut(&mut self) -> &mut Iter { &mut self.iter }
/// Unwraps this `LineColIterator`, returning the underlying iterator. /// Unwraps this `LineColIterator`, returning the underlying iterator.
pub fn into_inner(self) -> Iter { self.iter } pub fn into_inner(self) -> Iter { self.iter }
} }
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Peekable<Iter>> {
/// peeks at the next value
pub fn peek(&mut self) -> Option<&io::Result<u8>> { self.iter.peek() }
}
impl<Iter: Iterator<Item=io::Result<u8>>> Iterator for LineColIterator<Iter> { impl<Iter: Iterator<Item=io::Result<u8>>> Iterator for LineColIterator<Iter> {
type Item = io::Result<u8>; type Item = io::Result<u8>;
fn next(&mut self) -> Option<io::Result<u8>> { fn next(&mut self) -> Option<io::Result<u8>> {
+40 -21
View File
@@ -1,4 +1,5 @@
use std::char; use std::char;
use std::i32;
use std::io; use std::io;
use std::str; use std::str;
@@ -13,6 +14,15 @@ pub struct Deserializer<Iter: Iterator<Item=io::Result<u8>>> {
str_buf: Vec<u8>, str_buf: Vec<u8>,
} }
macro_rules! try_or_invalid {
($self_:expr, $e:expr) => {
match $e {
Some(v) => v,
None => { return Err($self_.error(ErrorCode::InvalidNumber)); }
}
}
}
impl<Iter> Deserializer<Iter> impl<Iter> Deserializer<Iter>
where Iter: Iterator<Item=io::Result<u8>>, where Iter: Iterator<Item=io::Result<u8>>,
{ {
@@ -180,7 +190,7 @@ impl<Iter> Deserializer<Iter>
} }
fn parse_integer(&mut self) -> Result<u64, Error> { fn parse_integer(&mut self) -> Result<u64, Error> {
let mut res = 0; let mut accum: u64 = 0;
match self.ch_or_null() { match self.ch_or_null() {
b'0' => { b'0' => {
@@ -198,8 +208,9 @@ impl<Iter> Deserializer<Iter>
while !self.eof() { while !self.eof() {
match self.ch_or_null() { match self.ch_or_null() {
c @ b'0' ... b'9' => { c @ b'0' ... b'9' => {
res *= 10; accum = try_or_invalid!(self, accum.checked_mul(10));
res += (c as u64) - (b'0' as u64); accum = try_or_invalid!(self, accum.checked_add((c as u64) - ('0' as u64)));
try!(self.bump()); try!(self.bump());
} }
_ => break, _ => break,
@@ -209,7 +220,7 @@ impl<Iter> Deserializer<Iter>
_ => { return Err(self.error(ErrorCode::InvalidNumber)); } _ => { return Err(self.error(ErrorCode::InvalidNumber)); }
} }
Ok(res) Ok(accum)
} }
fn parse_decimal(&mut self, res: f64) -> Result<f64, Error> { fn parse_decimal(&mut self, res: f64) -> Result<f64, Error> {
@@ -240,7 +251,7 @@ impl<Iter> Deserializer<Iter>
fn parse_exponent(&mut self, mut res: f64) -> Result<f64, Error> { fn parse_exponent(&mut self, mut res: f64) -> Result<f64, Error> {
try!(self.bump()); try!(self.bump());
let mut exp = 0; let mut exp: u64 = 0;
let mut neg_exp = false; let mut neg_exp = false;
if self.ch_is(b'+') { if self.ch_is(b'+') {
@@ -258,8 +269,8 @@ impl<Iter> Deserializer<Iter>
while !self.eof() { while !self.eof() {
match self.ch_or_null() { match self.ch_or_null() {
c @ b'0' ... b'9' => { c @ b'0' ... b'9' => {
exp *= 10; exp = try_or_invalid!(self, exp.checked_mul(10));
exp += (c as i32) - (b'0' as i32); exp = try_or_invalid!(self, exp.checked_add((c as u64) - (b'0' as u64)));
try!(self.bump()); try!(self.bump());
} }
@@ -267,7 +278,12 @@ impl<Iter> Deserializer<Iter>
} }
} }
let exp: f64 = 10_f64.powi(exp); let exp = if exp <= i32::MAX as u64 {
10_f64.powi(exp as i32)
} else {
return Err(self.error(ErrorCode::InvalidNumber));
};
if neg_exp { if neg_exp {
res /= exp; res /= exp;
} else { } else {
@@ -307,15 +323,23 @@ impl<Iter> Deserializer<Iter>
fn parse_string(&mut self) -> Result<(), Error> { fn parse_string(&mut self) -> Result<(), Error> {
self.str_buf.clear(); self.str_buf.clear();
let mut escape = false;
loop { loop {
let ch = match try!(self.next_char()) { let ch = match try!(self.next_char()) {
Some(ch) => ch, Some(ch) => ch,
None => { return Err(self.error(ErrorCode::EOFWhileParsingString)); } None => { return Err(self.error(ErrorCode::EOFWhileParsingString)); }
}; };
if escape { match ch {
b'"' => {
try!(self.bump());
return Ok(());
}
b'\\' => {
let ch = match try!(self.next_char()) {
Some(ch) => ch,
None => { return Err(self.error(ErrorCode::EOFWhileParsingString)); }
};
match ch { match ch {
b'"' => self.str_buf.push(b'"'), b'"' => self.str_buf.push(b'"'),
b'\\' => self.str_buf.push(b'\\'), b'\\' => self.str_buf.push(b'\\'),
@@ -377,15 +401,6 @@ impl<Iter> Deserializer<Iter>
return Err(self.error(ErrorCode::InvalidEscape)); return Err(self.error(ErrorCode::InvalidEscape));
} }
} }
escape = false;
} else {
match ch {
b'"' => {
try!(self.bump());
return Ok(());
}
b'\\' => {
escape = true;
} }
ch => { ch => {
self.str_buf.push(ch); self.str_buf.push(ch);
@@ -393,7 +408,6 @@ impl<Iter> Deserializer<Iter>
} }
} }
} }
}
fn parse_object_colon(&mut self) -> Result<(), Error> { fn parse_object_colon(&mut self) -> Result<(), Error> {
try!(self.parse_whitespace()); try!(self.parse_whitespace());
@@ -465,6 +479,11 @@ impl<Iter> de::Deserializer for Deserializer<Iter>
Err(self.error(ErrorCode::ExpectedSomeValue)) Err(self.error(ErrorCode::ExpectedSomeValue))
} }
} }
#[inline]
fn format() -> &'static str {
"json"
}
} }
struct SeqVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> { struct SeqVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> {
@@ -256,6 +256,11 @@ impl<W, F> ser::Serializer for Serializer<W, F>
try!(self.formatter.colon(&mut self.writer)); try!(self.formatter.colon(&mut self.writer));
value.serialize(self) value.serialize(self)
} }
#[inline]
fn format() -> &'static str {
"json"
}
} }
pub trait Formatter { pub trait Formatter {
+34 -2
View File
@@ -37,8 +37,30 @@ impl Value {
/// Otherwise, it will return the `Value` associated with the final key. /// Otherwise, it will return the `Value` associated with the final key.
pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Value>{ pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Value>{
let mut target = self; let mut target = self;
for key in keys.iter() { for key in keys {
match target.find(*key) { match target.find(key) {
Some(t) => { target = t; },
None => return None
}
}
Some(target)
}
/// Looks up a value by path.
///
/// This is a convenience method that splits the path by `'.'`
/// and then feeds the sequence of keys into the `find_path`
/// method.
///
/// ``` ignore
/// let obj: Value = json::from_str(r#"{"x": {"a": 1}}"#).unwrap();
///
/// assert!(obj.lookup("x.a").unwrap() == &Value::U64(1));
/// ```
pub fn lookup<'a>(&'a self, path: &str) -> Option<&'a Value> {
let mut target = self;
for key in path.split('.') {
match target.find(key) {
Some(t) => { target = t; }, Some(t) => { target = t; },
None => return None None => return None
} }
@@ -571,6 +593,11 @@ impl ser::Serializer for Serializer {
Ok(()) Ok(())
} }
#[inline]
fn format() -> &'static str {
"json"
}
} }
pub struct Deserializer { pub struct Deserializer {
@@ -677,6 +704,11 @@ impl de::Deserializer for Deserializer {
None => Ok(value) None => Ok(value)
} }
} }
#[inline]
fn format() -> &'static str {
"json"
}
} }
struct SeqDeserializer<'a> { struct SeqDeserializer<'a> {
View File
@@ -130,6 +130,53 @@ impl<'a, T> Serialize for &'a [T]
} }
} }
macro_rules! array_impls {
($len:expr) => {
impl<T> Serialize for [T; $len] where T: Serialize {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
{
serializer.visit_seq(SeqIteratorVisitor::new(self.iter(), Some($len)))
}
}
}
}
array_impls!(0);
array_impls!(1);
array_impls!(2);
array_impls!(3);
array_impls!(4);
array_impls!(5);
array_impls!(6);
array_impls!(7);
array_impls!(8);
array_impls!(9);
array_impls!(10);
array_impls!(11);
array_impls!(12);
array_impls!(13);
array_impls!(14);
array_impls!(15);
array_impls!(16);
array_impls!(17);
array_impls!(18);
array_impls!(19);
array_impls!(20);
array_impls!(21);
array_impls!(22);
array_impls!(23);
array_impls!(24);
array_impls!(25);
array_impls!(26);
array_impls!(27);
array_impls!(28);
array_impls!(29);
array_impls!(30);
array_impls!(31);
array_impls!(32);
impl<T> Serialize for Vec<T> where T: Serialize { impl<T> Serialize for Vec<T> where T: Serialize {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+8
View File
@@ -179,6 +179,14 @@ pub trait Serializer {
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
where K: Serialize, where K: Serialize,
V: Serialize; V: Serialize;
/// Specify a format string for the serializer.
///
/// The serializer format is used to determine which format
/// specific field attributes should be used with the serializer.
fn format() -> &'static str {
""
}
} }
pub trait SeqVisitor { pub trait SeqVisitor {
+24
View File
@@ -0,0 +1,24 @@
[package]
name = "serde_codegen"
version = "0.4.2"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework"
repository = "https://github.com/erickt/rust-serde"
build = "build.rs"
[features]
default = ["with-syntex"]
nightly = ["quasi_macros"]
with-syntex = ["quasi/with-syntex", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
[build-dependencies]
quasi_codegen = { verision = "*", optional = true }
syntex = { version = "*", optional = true }
[dependencies]
aster = { version = "*", default-features = false }
quasi = { verision = "*", default-features = false }
quasi_macros = { version = "*", optional = true }
syntex = { version = "*", optional = true }
syntex_syntax = { version = "*", optional = true }
+28
View File
@@ -0,0 +1,28 @@
#[cfg(feature = "with-syntex")]
mod inner {
extern crate syntex;
extern crate quasi_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let mut registry = syntex::Registry::new();
quasi_codegen::register(&mut registry);
let src = Path::new("src/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
registry.expand("", &src, &dst).unwrap();
}
}
#[cfg(not(feature = "with-syntex"))]
mod inner {
pub fn main() {}
}
fn main() {
inner::main();
}
+108
View File
@@ -0,0 +1,108 @@
use std::collections::HashMap;
use std::collections::HashSet;
use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;
/// Represents field name information
pub enum FieldNames {
Global(P<ast::Expr>),
Format{
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
default: P<ast::Expr>,
}
}
/// Represents field attribute information
pub struct FieldAttrs {
names: FieldNames,
use_default: bool,
}
impl FieldAttrs {
/// Create a FieldAttr with a single default field name
pub fn new(default_value: bool, name: P<ast::Expr>) -> FieldAttrs {
FieldAttrs {
names: FieldNames::Global(name),
use_default: default_value,
}
}
/// Create a FieldAttr with format specific field names
pub fn new_with_formats(
default_value: bool,
default_name: P<ast::Expr>,
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
) -> FieldAttrs {
FieldAttrs {
names: FieldNames::Format {
formats: formats,
default: default_name,
},
use_default: default_value,
}
}
/// Return a set of formats that the field has attributes for.
pub fn formats(&self) -> HashSet<P<ast::Expr>> {
match self.names {
FieldNames::Format{ref formats, default: _} => {
let mut set = HashSet::new();
for (fmt, _) in formats.iter() {
set.insert(fmt.clone());
};
set
},
_ => HashSet::new()
}
}
/// Return an expression for the field key name for serialisation.
///
/// The resulting expression assumes that `S` refers to a type
/// that implements `Serializer`.
pub fn serializer_key_expr(self, cx: &ExtCtxt) -> P<ast::Expr> {
match self.names {
FieldNames::Global(x) => x,
FieldNames::Format{formats, default} => {
let arms = formats.iter()
.map(|(fmt, lit)| {
quote_arm!(cx, $fmt => { $lit })
})
.collect::<Vec<_>>();
quote_expr!(cx,
{
match S::format() {
$arms
_ => { $default }
}
})
},
}
}
/// Return the default field name for the field.
pub fn default_key_expr(&self) -> &P<ast::Expr> {
match self.names {
FieldNames::Global(ref expr) => expr,
FieldNames::Format{formats: _, ref default} => default
}
}
/// Return the field name for the field in the specified format.
pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
match self.names {
FieldNames::Global(ref expr) =>
expr,
FieldNames::Format{ref formats, ref default} =>
formats.get(format).unwrap_or(default)
}
}
/// Predicate for using a field's default value
pub fn use_default(&self) -> bool {
self.use_default
}
}
@@ -1,4 +1,9 @@
use std::collections::HashSet;
use aster;
use syntax::ast::{ use syntax::ast::{
self,
Ident, Ident,
MetaItem, MetaItem,
Item, Item,
@@ -6,23 +11,32 @@ use syntax::ast::{
StructDef, StructDef,
EnumDef, EnumDef,
}; };
use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::owned_slice::OwnedSlice;
use syntax::ptr::P; use syntax::ptr::P;
use aster; use attr;
use field; use field;
pub fn expand_derive_deserialize( pub fn expand_derive_deserialize(
cx: &mut ExtCtxt, cx: &mut ExtCtxt,
span: Span, span: Span,
_mitem: &MetaItem, meta_item: &MetaItem,
item: &Item, annotatable: &Annotatable,
push: &mut FnMut(P<ast::Item>) push: &mut FnMut(Annotatable)
) { ) {
let item = match *annotatable {
Annotatable::Item(ref item) => item,
_ => {
cx.span_err(
meta_item.span,
"`derive` may only be applied to structs and enums");
return;
}
};
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let generics = match item.node { let generics = match item.node {
@@ -44,7 +58,7 @@ pub fn expand_derive_deserialize(
let body = deserialize_body( let body = deserialize_body(
cx, cx,
&builder, &builder,
item, &item,
&impl_generics, &impl_generics,
ty.clone(), ty.clone(),
); );
@@ -62,7 +76,7 @@ pub fn expand_derive_deserialize(
} }
).unwrap(); ).unwrap();
push(impl_item) push(Annotatable::Item(impl_item))
} }
fn deserialize_body( fn deserialize_body(
@@ -154,14 +168,25 @@ fn deserialize_item_struct(
fn deserialize_visitor( fn deserialize_visitor(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
trait_generics: &ast::Generics, trait_generics: &ast::Generics,
) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>) { forward_ty_params: Vec<ast::TyParam>,
if trait_generics.ty_params.is_empty() { forward_tys: Vec<P<ast::Ty>>
) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>, ast::Generics) {
if trait_generics.ty_params.is_empty() && forward_tys.is_empty() {
( (
builder.item().tuple_struct("__Visitor").build(), builder.item().tuple_struct("__Visitor").build(),
builder.ty().id("__Visitor"), builder.ty().id("__Visitor"),
builder.expr().id("__Visitor"), builder.expr().id("__Visitor"),
trait_generics.clone(),
) )
} else { } else {
let placeholders : Vec<_> = trait_generics.ty_params.iter()
.map(|t| builder.ty().id(t.ident))
.collect();
let mut trait_generics = trait_generics.clone();
let mut ty_params = forward_ty_params.clone();
ty_params.extend(trait_generics.ty_params.into_vec());
trait_generics.ty_params = OwnedSlice::from_vec(ty_params);
( (
builder.item().tuple_struct("__Visitor") builder.item().tuple_struct("__Visitor")
.generics().with(trait_generics.clone()).build() .generics().with(trait_generics.clone()).build()
@@ -174,17 +199,38 @@ fn deserialize_visitor(
builder.ty().path() builder.ty().path()
.segment("__Visitor").with_generics(trait_generics.clone()).build() .segment("__Visitor").with_generics(trait_generics.clone()).build()
.build(), .build(),
builder.expr().call().id("__Visitor") builder.expr().call()
.path().segment("__Visitor")
.with_tys(forward_tys)
.with_tys(placeholders)
.build().build()
.with_args( .with_args(
trait_generics.ty_params.iter().map(|_| { trait_generics.ty_params.iter().map(|_| {
builder.expr().phantom_data() builder.expr().phantom_data()
}) })
) )
.build(), .build(),
trait_generics,
) )
} }
} }
fn deserializer_ty_param(builder: &aster::AstBuilder) -> ast::TyParam {
builder.ty_param("__D")
.trait_bound(builder.path()
.global()
.segment("serde").build()
.segment("de").build()
.id("Deserializer")
.build())
.build()
.build()
}
fn deserializer_ty_arg(builder: &aster::AstBuilder) -> P<ast::Ty>{
builder.ty().id("__D")
}
fn deserialize_unit_struct( fn deserialize_unit_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
@@ -228,9 +274,12 @@ fn deserialize_tuple_struct(
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
impl_generics, impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
); );
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
@@ -245,7 +294,7 @@ fn deserialize_tuple_struct(
quote_expr!(cx, { quote_expr!(cx, {
$visitor_item $visitor_item
impl $impl_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
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>
@@ -270,7 +319,7 @@ fn deserialize_seq(
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
quote_stmt!(cx, quote_stmt!(cx,
let $name = match try!(visitor.visit()) { let $name = match try!(visitor.visit()) {
Some(value) => value, Some(value) => { value },
None => { None => {
return Err(::serde::de::Error::end_of_stream_error()); return Err(::serde::de::Error::end_of_stream_error());
} }
@@ -303,9 +352,12 @@ fn deserialize_struct(
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
impl_generics, &impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
); );
let (field_visitor, visit_map_expr) = deserialize_struct_visitor( let (field_visitor, visit_map_expr) = deserialize_struct_visitor(
@@ -322,7 +374,7 @@ fn deserialize_struct(
$visitor_item $visitor_item
impl $impl_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
#[inline] #[inline]
@@ -353,7 +405,10 @@ fn deserialize_item_enum(
cx, cx,
builder, builder,
enum_def.variants.iter() enum_def.variants.iter()
.map(|variant| builder.expr().str(variant.node.name)) .map(|variant|
attr::FieldAttrs::new(
true,
builder.expr().str(variant.node.name)))
.collect() .collect()
); );
@@ -378,9 +433,12 @@ fn deserialize_item_enum(
}) })
.collect(); .collect();
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
impl_generics, impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
); );
quote_expr!(cx, { quote_expr!(cx, {
@@ -388,7 +446,7 @@ fn deserialize_item_enum(
$visitor_item $visitor_item
impl $impl_generics ::serde::de::EnumVisitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::EnumVisitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
fn visit<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error> fn visit<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
@@ -457,9 +515,12 @@ fn deserialize_tuple_variant(
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &generics.where_clause; let where_clause = &generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
generics, generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
); );
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
@@ -472,7 +533,7 @@ fn deserialize_tuple_variant(
quote_expr!(cx, { quote_expr!(cx, {
$visitor_item $visitor_item
impl $generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
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>
@@ -504,9 +565,12 @@ fn deserialize_struct_variant(
builder.path().id(type_ident).id(variant_ident).build(), builder.path().id(type_ident).id(variant_ident).build(),
); );
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
deserialize_visitor(
builder, builder,
generics, generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
); );
quote_expr!(cx, { quote_expr!(cx, {
@@ -514,7 +578,7 @@ fn deserialize_struct_variant(
$visitor_item $visitor_item
impl $generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty; type Value = $ty;
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>
@@ -531,10 +595,10 @@ fn deserialize_struct_variant(
fn deserialize_field_visitor( fn deserialize_field_visitor(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
field_exprs: Vec<P<ast::Expr>>, field_attrs: Vec<attr::FieldAttrs>,
) -> Vec<P<ast::Item>> { ) -> Vec<P<ast::Item>> {
// Create the field names for the fields. // Create the field names for the fields.
let field_idents: Vec<ast::Ident> = (0 .. field_exprs.len()) let field_idents: Vec<ast::Ident> = (0 .. field_attrs.len())
.map(|i| builder.id(format!("__field{}", i))) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
@@ -548,43 +612,106 @@ fn deserialize_field_visitor(
) )
.build(); .build();
// A set of all the formats that have specialized field attributes
let formats = field_attrs.iter()
.fold(HashSet::new(), |mut set, field_expr| {
set.extend(field_expr.formats());
set
});
// Match arms to extract a field from a string // Match arms to extract a field from a string
let field_arms: Vec<_> = field_idents.iter() let default_field_arms: Vec<_> = field_idents.iter()
.zip(field_exprs.into_iter()) .zip(field_attrs.iter())
.map(|(field_ident, field_expr)| { .map(|(field_ident, field_expr)| {
quote_arm!(cx, $field_expr => { Ok(__Field::$field_ident) }) let expr = field_expr.default_key_expr();
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
}) })
.collect(); .collect();
vec![ let body = if formats.is_empty() {
field_enum, // No formats specific attributes, so no match on format required
quote_expr!(cx,
match value {
$default_field_arms
_ => { Err(::serde::de::Error::unknown_field_error(value)) }
})
} else {
let field_arms : Vec<_> = formats.iter()
.map(|fmt| {
field_idents.iter()
.zip(field_attrs.iter())
.map(|(field_ident, field_expr)| {
let expr = field_expr.key_expr(fmt);
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
})
.collect::<Vec<_>>()
})
.collect();
quote_item!(cx, let fmt_matches : Vec<_> = formats.iter()
.zip(field_arms.iter())
.map(|(ref fmt, ref arms)| {
quote_arm!(cx, $fmt => {
match value {
$arms
_ => {
Err(::serde::de::Error::unknown_field_error(value))
}
}})
})
.collect();
quote_expr!(cx,
match __D::format() {
$fmt_matches
_ => match value {
$default_field_arms
_ => { Err(::serde::de::Error::unknown_field_error(value)) }
}
})
};
let impl_item = quote_item!(cx,
impl ::serde::de::Deserialize for __Field { impl ::serde::de::Deserialize for __Field {
#[inline] #[inline]
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error> fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error>
where D: ::serde::de::Deserializer, where D: ::serde::de::Deserializer,
{ {
struct __FieldVisitor; use std::marker::PhantomData;
impl ::serde::de::Visitor for __FieldVisitor { struct __FieldVisitor<D> {
phantom: PhantomData<D>
}
impl<__D> ::serde::de::Visitor for __FieldVisitor<__D>
where __D: ::serde::de::Deserializer
{
type Value = __Field; type Value = __Field;
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E> fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E>
where E: ::serde::de::Error, where E: ::serde::de::Error,
{ {
match value { $body
$field_arms }
_ => Err(::serde::de::Error::unknown_field_error(value)),
fn visit_bytes<E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, E>
where E: ::serde::de::Error,
{
// TODO: would be better to generate a byte string literal match
match ::std::str::from_utf8(value) {
Ok(s) => self.visit_str(s),
_ => Err(::serde::de::Error::syntax_error()),
} }
} }
} }
deserializer.visit(__FieldVisitor) deserializer.visit(
__FieldVisitor::<D>{ phantom: PhantomData })
} }
} }
).unwrap(), ).unwrap();
]
vec![field_enum, impl_item]
} }
fn deserialize_struct_visitor( fn deserialize_struct_visitor(
@@ -596,7 +723,7 @@ fn deserialize_struct_visitor(
let field_visitor = deserialize_field_visitor( let field_visitor = deserialize_field_visitor(
cx, cx,
builder, builder,
field::struct_field_strs(cx, builder, struct_def, field::Direction::Deserialize), field::struct_field_attrs(cx, builder, struct_def),
); );
let visit_map_expr = deserialize_map( let visit_map_expr = deserialize_map(
@@ -637,25 +764,36 @@ fn deserialize_map(
.collect(); .collect();
let extract_values: Vec<P<ast::Stmt>> = field_names.iter() let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
.zip(struct_def.fields.iter()) .zip(field::struct_field_attrs(cx, builder, struct_def).iter())
.map(|(field_name, field)| { .map(|(field_name, field_attr)| {
let rename = field::field_rename(field, &field::Direction::Deserialize); let missing_expr = if field_attr.use_default() {
let name_str = match (rename, field.node.kind) {
(Some(rename), _) => builder.expr().build_lit(P(rename.clone())),
(None, ast::NamedField(name, _)) => builder.expr().str(name),
(None, ast::UnnamedField(_)) => panic!("struct contains unnamed fields"),
};
let missing_expr = if field::default_value(field) {
quote_expr!(cx, ::std::default::Default::default()) quote_expr!(cx, ::std::default::Default::default())
} else { } else {
quote_expr!(cx, try!(visitor.missing_field($name_str))) let formats = field_attr.formats();
let arms : Vec<_> = formats.iter()
.map(|format| {
let key_expr = field_attr.key_expr(format);
quote_arm!(cx, $format => { $key_expr })
})
.collect();
let default = field_attr.default_key_expr();
if arms.is_empty() {
quote_expr!(cx, try!(visitor.missing_field($default)))
} else {
quote_expr!(
cx,
try!(visitor.missing_field(
match __D::format() {
$arms
_ => { $default }
})))
}
}; };
quote_stmt!(cx, quote_stmt!(cx,
let $field_name = match $field_name { let $field_name = match $field_name {
Some($field_name) => $field_name, Some($field_name) => $field_name,
None => $missing_expr, None => $missing_expr
}; };
).unwrap() ).unwrap()
}) })
+133
View File
@@ -0,0 +1,133 @@
use std::collections::HashMap;
use aster;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;
use attr::FieldAttrs;
enum Rename<'a> {
None,
Global(&'a ast::Lit),
Format(HashMap<P<ast::Expr>, &'a ast::Lit>)
}
fn rename<'a>(
builder: &aster::AstBuilder,
mi: &'a ast::MetaItem,
) -> Option<Rename<'a>>
{
match mi.node {
ast::MetaNameValue(ref n, ref lit) => {
if n == &"rename" {
Some(Rename::Global(lit))
} else {
None
}
},
ast::MetaList(ref n, ref items) => {
if n == &"rename" {
let mut m = HashMap::new();
m.extend(
items.iter()
.filter_map(
|item|
match item.node {
ast::MetaNameValue(ref n, ref lit) =>
Some((builder.expr().str(n),
lit)),
_ => None
}));
Some(Rename::Format(m))
} else {
None
}
},
_ => None
}
}
fn default_value(mi: &ast::MetaItem) -> bool {
if let ast::MetaItem_::MetaWord(ref n) = mi.node {
n == &"default"
} else {
false
}
}
fn field_attrs<'a>(
builder: &aster::AstBuilder,
field: &'a ast::StructField,
) -> (Rename<'a>, bool) {
field.node.attrs.iter()
.find(|sa| {
if let ast::MetaList(ref n, _) = sa.node.value.node {
n == &"serde"
} else {
false
}
})
.and_then(|sa| {
if let ast::MetaList(_, ref vals) = sa.node.value.node {
attr::mark_used(&sa);
Some((vals.iter()
.fold(None, |v, mi| v.or(rename(builder, mi)))
.unwrap_or(Rename::None),
vals.iter().any(|mi| default_value(mi))))
} else {
Some((Rename::None, false))
}
})
.unwrap_or((Rename::None, false))
}
pub fn struct_field_attrs(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
struct_def: &ast::StructDef,
) -> Vec<FieldAttrs> {
struct_def.fields.iter()
.map(|field| {
match field_attrs(builder, field) {
(Rename::Global(rename), default_value) =>
FieldAttrs::new(
default_value,
builder.expr().build_lit(P(rename.clone()))),
(Rename::Format(renames), default_value) => {
let mut res = HashMap::new();
res.extend(
renames.into_iter()
.map(|(k,v)|
(k, builder.expr().build_lit(P(v.clone())))));
FieldAttrs::new_with_formats(
default_value,
default_field_name(cx, builder, field.node.kind),
res)
},
(Rename::None, default_value) => {
FieldAttrs::new(
default_value,
default_field_name(cx, builder, field.node.kind))
}
}
})
.collect()
}
fn default_field_name(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
kind: ast::StructFieldKind,
) -> P<ast::Expr> {
match kind {
ast::NamedField(name, _) => {
builder.expr().str(name)
}
ast::UnnamedField(_) => {
cx.bug("struct has named and unnamed fields")
}
}
}
+73
View File
@@ -0,0 +1,73 @@
#![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;
#[cfg(feature = "with-syntex")]
extern crate syntex;
#[cfg(feature = "with-syntex")]
extern crate syntex_syntax as syntax;
#[cfg(not(feature = "with-syntex"))]
extern crate syntax;
#[cfg(not(feature = "with-syntex"))]
extern crate rustc;
#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");
#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
use syntax::{ast, fold};
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);
/// 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<ast::Attribute> {
match attr.node.value.node {
ast::MetaList(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)
}
}
#[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)));
reg.register_syntax_extension(
syntax::parse::token::intern("derive_Deserialize"),
syntax::ext::base::MultiDecorator(
Box::new(de::expand_derive_deserialize)));
}
+4
View File
@@ -0,0 +1,4 @@
mod attr;
mod de;
mod field;
mod ser;
@@ -1,3 +1,5 @@
use aster;
use syntax::ast::{ use syntax::ast::{
Ident, Ident,
MetaItem, MetaItem,
@@ -7,21 +9,29 @@ use syntax::ast::{
}; };
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::ptr::P; use syntax::ptr::P;
use aster; use field::struct_field_attrs;
use field::{Direction, struct_field_strs};
pub fn expand_derive_serialize( pub fn expand_derive_serialize(
cx: &mut ExtCtxt, cx: &mut ExtCtxt,
span: Span, span: Span,
_mitem: &MetaItem, meta_item: &MetaItem,
item: &Item, annotatable: &Annotatable,
push: &mut FnMut(P<ast::Item>) push: &mut FnMut(Annotatable)
) { ) {
let item = match *annotatable {
Annotatable::Item(ref item) => item,
_ => {
cx.span_err(
meta_item.span,
"`derive` may only be applied to structs and enums");
return;
}
};
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let generics = match item.node { let generics = match item.node {
@@ -43,9 +53,12 @@ pub fn expand_derive_serialize(
let body = serialize_body( let body = serialize_body(
cx, cx,
&builder, &builder,
item, &item,
&impl_generics, &impl_generics,
ty.clone(), builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty.clone()),
); );
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@@ -61,7 +74,7 @@ pub fn expand_derive_serialize(
} }
).unwrap(); ).unwrap();
push(impl_item) push(Annotatable::Item(impl_item))
} }
fn serialize_body( fn serialize_body(
@@ -88,6 +101,7 @@ fn serialize_body(
builder, builder,
item.ident, item.ident,
impl_generics, impl_generics,
ty,
enum_def, enum_def,
) )
} }
@@ -166,15 +180,11 @@ fn serialize_tuple_struct(
ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty);
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor( let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx, cx,
builder, builder,
value_ty, ty.clone(),
ty,
fields, fields,
impl_generics, impl_generics,
); );
@@ -187,6 +197,7 @@ fn serialize_tuple_struct(
serializer.visit_named_seq($type_name, Visitor { serializer.visit_named_seq($type_name, Visitor {
value: self, value: self,
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData,
}) })
}) })
} }
@@ -200,15 +211,11 @@ fn serialize_struct(
struct_def: &StructDef, struct_def: &StructDef,
fields: Vec<Ident>, fields: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty.clone());
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let (visitor_struct, visitor_impl) = serialize_struct_visitor(
cx, cx,
builder, builder,
value_ty, ty.clone(),
ty,
struct_def, struct_def,
impl_generics, impl_generics,
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)), fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
@@ -222,6 +229,7 @@ fn serialize_struct(
serializer.visit_named_map($type_name, Visitor { serializer.visit_named_map($type_name, Visitor {
value: self, value: self,
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData,
}) })
}) })
} }
@@ -231,6 +239,7 @@ fn serialize_item_enum(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>,
enum_def: &ast::EnumDef, enum_def: &ast::EnumDef,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let arms: Vec<ast::Arm> = enum_def.variants.iter() let arms: Vec<ast::Arm> = enum_def.variants.iter()
@@ -240,6 +249,7 @@ fn serialize_item_enum(
builder, builder,
type_ident, type_ident,
impl_generics, impl_generics,
ty.clone(),
variant, variant,
) )
}) })
@@ -257,6 +267,7 @@ fn serialize_variant(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
generics: &ast::Generics, generics: &ast::Generics,
ty: P<ast::Ty>,
variant: &ast::Variant, variant: &ast::Variant,
) -> ast::Arm { ) -> ast::Arm {
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
@@ -276,7 +287,7 @@ fn serialize_variant(
$type_name, $type_name,
$variant_name, $variant_name,
) )
}, }
) )
} }
ast::TupleVariantKind(ref args) => { ast::TupleVariantKind(ref args) => {
@@ -295,6 +306,7 @@ fn serialize_variant(
type_name, type_name,
variant_name, variant_name,
generics, generics,
ty,
args, args,
fields, fields,
); );
@@ -330,6 +342,7 @@ fn serialize_variant(
type_name, type_name,
variant_name, variant_name,
generics, generics,
ty,
struct_def, struct_def,
fields, fields,
); );
@@ -345,10 +358,11 @@ fn serialize_tuple_variant(
type_name: P<ast::Expr>, type_name: P<ast::Expr>,
variant_name: P<ast::Expr>, variant_name: P<ast::Expr>,
generics: &ast::Generics, generics: &ast::Generics,
structure_ty: P<ast::Ty>,
args: &[ast::VariantArg], args: &[ast::VariantArg],
fields: Vec<Ident>, fields: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty().tuple() let variant_ty = builder.ty().tuple()
.with_tys( .with_tys(
args.iter().map(|arg| { args.iter().map(|arg| {
builder.ty() builder.ty()
@@ -359,6 +373,15 @@ fn serialize_tuple_variant(
) )
.build(); .build();
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx,
builder,
structure_ty,
variant_ty,
args.len(),
generics,
);
let value_expr = builder.expr().tuple() let value_expr = builder.expr().tuple()
.with_exprs( .with_exprs(
fields.iter().map(|field| { fields.iter().map(|field| {
@@ -369,20 +392,13 @@ fn serialize_tuple_variant(
) )
.build(); .build();
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx,
builder,
value_ty,
args.len(),
generics,
);
quote_expr!(cx, { quote_expr!(cx, {
$visitor_struct $visitor_struct
$visitor_impl $visitor_impl
serializer.visit_enum_seq($type_name, $variant_name, Visitor { serializer.visit_enum_seq($type_name, $variant_name, Visitor {
value: $value_expr, value: $value_expr,
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData,
}) })
}) })
} }
@@ -393,6 +409,7 @@ fn serialize_struct_variant(
type_name: P<ast::Expr>, type_name: P<ast::Expr>,
variant_name: P<ast::Expr>, variant_name: P<ast::Expr>,
generics: &ast::Generics, generics: &ast::Generics,
structure_ty: P<ast::Ty>,
struct_def: &ast::StructDef, struct_def: &ast::StructDef,
fields: Vec<Ident>, fields: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
@@ -420,6 +437,7 @@ fn serialize_struct_variant(
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let (visitor_struct, visitor_impl) = serialize_struct_visitor(
cx, cx,
builder, builder,
structure_ty,
value_ty, value_ty,
struct_def, struct_def,
generics, generics,
@@ -436,6 +454,7 @@ fn serialize_struct_variant(
serializer.visit_enum_map($type_name, $variant_name, Visitor { serializer.visit_enum_map($type_name, $variant_name, Visitor {
value: $value_expr, value: $value_expr,
state: 0, state: 0,
_structure_ty: ::std::marker::PhantomData,
}) })
}) })
} }
@@ -443,7 +462,8 @@ fn serialize_struct_variant(
fn serialize_tuple_struct_visitor( fn serialize_tuple_struct_visitor(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
value_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
variant_ty: P<ast::Ty>,
fields: usize, fields: usize,
generics: &ast::Generics generics: &ast::Generics
) -> (P<ast::Item>, P<ast::Item>) { ) -> (P<ast::Item>, P<ast::Item>) {
@@ -474,11 +494,19 @@ fn serialize_tuple_struct_visitor(
.strip_bounds() .strip_bounds()
.build(); .build();
// Variants don't necessarily reference all generic lifetimes and type parameters,
// so to avoid a compilation failure, we'll just add a phantom type to capture these
// unused values.
let structure_ty = builder.ty()
.phantom_data()
.build(structure_ty);
( (
quote_item!(cx, quote_item!(cx,
struct Visitor $visitor_impl_generics $where_clause { struct Visitor $visitor_impl_generics $where_clause {
state: usize, state: usize,
value: $value_ty, value: $variant_ty,
_structure_ty: $structure_ty,
} }
).unwrap(), ).unwrap(),
@@ -488,11 +516,11 @@ fn serialize_tuple_struct_visitor(
$where_clause { $where_clause {
#[inline] #[inline]
fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error> fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
where S: ::serde::ser::Serializer, where S: ::serde::ser::Serializer
{ {
match self.state { match self.state {
$arms $arms
_ => Ok(None), _ => Ok(None)
} }
} }
@@ -508,7 +536,8 @@ fn serialize_tuple_struct_visitor(
fn serialize_struct_visitor<I>( fn serialize_struct_visitor<I>(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
value_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
variant_ty: P<ast::Ty>,
struct_def: &StructDef, struct_def: &StructDef,
generics: &ast::Generics, generics: &ast::Generics,
value_exprs: I, value_exprs: I,
@@ -517,12 +546,13 @@ fn serialize_struct_visitor<I>(
{ {
let len = struct_def.fields.len(); let len = struct_def.fields.len();
let key_exprs = struct_field_strs(cx, builder, struct_def, Direction::Serialize); let field_attrs = struct_field_attrs(cx, builder, struct_def);
let arms: Vec<ast::Arm> = key_exprs.iter() let arms: Vec<ast::Arm> = field_attrs.into_iter()
.zip(value_exprs) .zip(value_exprs)
.enumerate() .enumerate()
.map(|(i, (key_expr, value_expr))| { .map(|(i, (field, value_expr))| {
let key_expr = field.serializer_key_expr(cx);
quote_arm!(cx, quote_arm!(cx,
$i => { $i => {
self.state += 1; self.state += 1;
@@ -552,11 +582,19 @@ fn serialize_struct_visitor<I>(
.strip_bounds() .strip_bounds()
.build(); .build();
// Variants don't necessarily reference all generic lifetimes and type parameters,
// so to avoid a compilation failure, we'll just add a phantom type to capture these
// unused values.
let structure_ty = builder.ty()
.phantom_data()
.build(structure_ty);
( (
quote_item!(cx, quote_item!(cx,
struct Visitor $visitor_impl_generics $where_clause { struct Visitor $visitor_impl_generics $where_clause {
state: usize, state: usize,
value: $value_ty, value: $variant_ty,
_structure_ty: $structure_ty,
} }
).unwrap(), ).unwrap(),
@@ -571,7 +609,7 @@ fn serialize_struct_visitor<I>(
{ {
match self.state { match self.state {
$arms $arms
_ => Ok(None), _ => Ok(None)
} }
} }
+7 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_macros" name = "serde_macros"
version = "0.3.3" version = "0.4.2"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" description = "Macros to auto-generate implementations for the serde framework"
@@ -11,6 +11,9 @@ name = "serde_macros"
plugin = true plugin = true
[dependencies] [dependencies]
aster = "*" serde_codegen = { version = "*", path = "../serde_codegen", default-features = false, features = ["nightly"] }
quasi = "*"
quasi_macros = "*" [dev-dependencies]
num = "*"
rustc-serialize = "*"
serde = { version = "*", path = "../serde" }
+9
View File
@@ -0,0 +1,9 @@
#![feature(custom_attribute, custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate num;
extern crate rustc_serialize;
extern crate serde;
extern crate test;
include!("../../serde_tests/benches/bench.rs.in");
-96
View File
@@ -1,96 +0,0 @@
use syntax::ast;
use syntax::attr;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;
use aster;
pub enum Direction {
Serialize,
Deserialize,
}
pub fn field_rename<'a>(
field: &'a ast::StructField,
direction: &Direction,
) -> Option<&'a ast::Lit> {
let dir_attr = match *direction {
Direction::Serialize => "rename_serialize",
Direction::Deserialize => "rename_deserialize",
};
field.node.attrs.iter()
.find(|sa| {
if let ast::MetaList(ref n, _) = sa.node.value.node {
n == &"serde"
} else {
false
}
})
.and_then(|sa| {
if let ast::MetaList(_, ref vals) = sa.node.value.node {
attr::mark_used(&sa);
vals.iter().fold(None, |v, mi| {
if let ast::MetaNameValue(ref n, ref lit) = mi.node {
if n == &"rename" || n == &dir_attr {
Some(lit)
} else {
v
}
} else {
v
}
})
} else {
None
}
})
}
pub fn struct_field_strs(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
struct_def: &ast::StructDef,
direction: Direction,
) -> Vec<P<ast::Expr>> {
struct_def.fields.iter()
.map(|field| {
match field_rename(field, &direction) {
Some(rename) => builder.expr().build_lit(P(rename.clone())),
None => {
match field.node.kind {
ast::NamedField(name, _) => {
builder.expr().str(name)
}
ast::UnnamedField(_) => {
cx.bug("struct has named and unnamed fields")
}
}
}
}
})
.collect()
}
pub fn default_value(field: &ast::StructField) -> bool {
field.node.attrs.iter()
.any(|sa| {
if let ast::MetaItem_::MetaList(ref n, ref vals) = sa.node.value.node {
if n == &"serde" {
attr::mark_used(&sa);
vals.iter()
.map(|mi|
if let ast::MetaItem_::MetaWord(ref n) = mi.node {
n == &"default"
} else {
false
})
.any(|x| x)
} else {
false
}
}
else {
false
}
})
}
+4 -21
View File
@@ -1,27 +1,10 @@
#![feature(custom_derive, plugin, plugin_registrar, rustc_private, unboxed_closures)] #![feature(plugin_registrar, rustc_private)]
#![plugin(quasi_macros)]
extern crate aster; extern crate serde_codegen;
extern crate quasi;
extern crate rustc; extern crate rustc;
extern crate syntax;
use syntax::ext::base::Decorator;
use syntax::parse::token;
use rustc::plugin::Registry;
mod ser;
mod de;
mod field;
#[plugin_registrar] #[plugin_registrar]
#[doc(hidden)] #[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) { pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
reg.register_syntax_extension( serde_codegen::register(reg);
token::intern("derive_Serialize"),
Decorator(Box::new(ser::expand_derive_serialize)));
reg.register_syntax_extension(
token::intern("derive_Deserialize"),
Decorator(Box::new(de::expand_derive_deserialize)));
} }
+7
View File
@@ -0,0 +1,7 @@
#![feature(test, custom_attribute, custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate serde;
extern crate test;
include!("../../serde_tests/tests/test.rs.in");
+30
View File
@@ -0,0 +1,30 @@
[package]
name = "serde_tests"
version = "0.4.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
repository = "https://github.com/serde-rs/serde"
documentation = "http://serde-rs.github.io/serde/serde"
readme = "README.md"
keywords = ["serialization"]
build = "build.rs"
[build-dependencies]
syntex = { version = "*", optional = true }
syntex_syntax = { version = "*" }
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
[dev-dependencies]
num = "*"
rustc-serialize = "*"
serde = { version = "*", path = "../serde" }
syntex = "*"
[[test]]
name = "test"
path = "tests/test.rs"
[[bench]]
name = "bench"
path = "benches/bench.rs"
+8
View File
@@ -0,0 +1,8 @@
#![feature(test)]
extern crate num;
extern crate rustc_serialize;
extern crate serde;
extern crate test;
include!(concat!(env!("OUT_DIR"), "/bench.rs"));
+5
View File
@@ -0,0 +1,5 @@
mod bench_enum;
mod bench_log;
mod bench_map;
mod bench_struct;
mod bench_vec;
@@ -1,18 +1,8 @@
#![feature(custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate serde;
extern crate rustc_serialize;
extern crate test;
use test::Bencher; use test::Bencher;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::{Decoder, Decodable};
use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::{Deserializer, Deserialize};
use Animal::{Dog, Frog};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#[derive(Clone, PartialEq, Debug, RustcDecodable, Deserialize)] #[derive(Clone, PartialEq, Debug, RustcDecodable, Deserialize)]
@@ -408,7 +398,7 @@ mod deserializer {
#[bench] #[bench]
fn bench_decoder_dog(b: &mut Bencher) { fn bench_decoder_dog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Dog; let animal = Animal::Dog;
let mut d = decoder::AnimalDecoder::new(animal.clone()); let mut d = decoder::AnimalDecoder::new(animal.clone());
let value: Animal = Decodable::decode(&mut d).unwrap(); let value: Animal = Decodable::decode(&mut d).unwrap();
@@ -420,7 +410,7 @@ fn bench_decoder_dog(b: &mut Bencher) {
#[bench] #[bench]
fn bench_decoder_frog(b: &mut Bencher) { fn bench_decoder_frog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Frog("Henry".to_string(), 349); let animal = Animal::Frog("Henry".to_string(), 349);
let mut d = decoder::AnimalDecoder::new(animal.clone()); let mut d = decoder::AnimalDecoder::new(animal.clone());
let value: Animal = Decodable::decode(&mut d).unwrap(); let value: Animal = Decodable::decode(&mut d).unwrap();
@@ -432,7 +422,7 @@ fn bench_decoder_frog(b: &mut Bencher) {
#[bench] #[bench]
fn bench_deserializer_dog(b: &mut Bencher) { fn bench_deserializer_dog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Dog; let animal = Animal::Dog;
let mut d = deserializer::AnimalDeserializer::new(animal.clone()); let mut d = deserializer::AnimalDeserializer::new(animal.clone());
let value: Animal = Deserialize::deserialize(&mut d).unwrap(); let value: Animal = Deserialize::deserialize(&mut d).unwrap();
@@ -444,7 +434,7 @@ fn bench_deserializer_dog(b: &mut Bencher) {
#[bench] #[bench]
fn bench_deserializer_frog(b: &mut Bencher) { fn bench_deserializer_frog(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
let animal = Frog("Henry".to_string(), 349); let animal = Animal::Frog("Henry".to_string(), 349);
let mut d = deserializer::AnimalDeserializer::new(animal.clone()); let mut d = deserializer::AnimalDeserializer::new(animal.clone());
let value: Animal = Deserialize::deserialize(&mut d).unwrap(); let value: Animal = Deserialize::deserialize(&mut d).unwrap();
@@ -1,20 +1,14 @@
#![feature(custom_derive, collections, plugin, test)]
#![allow(non_camel_case_types)]
#![plugin(serde_macros)]
extern crate num;
extern crate rustc_serialize;
extern crate serde;
extern crate test;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use num::FromPrimitive; use num::FromPrimitive;
use test::Bencher; use test::Bencher;
use rustc_serialize;
use serde::de::{self, Deserialize, Deserializer}; use serde::de::{self, Deserialize, Deserializer};
use serde::json::ser::escape_str; use serde::json::ser::escape_str;
use serde::json; use serde::json;
use serde::ser::{self, Serialize, Serializer}; use serde::ser::{self, Serialize, Serializer};
use std::str::FromStr;
use rustc_serialize::Encodable; use rustc_serialize::Encodable;
@@ -31,6 +25,7 @@ struct Http {
request_uri: String, request_uri: String,
} }
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum HttpProtocol { enum HttpProtocol {
HTTP_PROTOCOL_UNKNOWN, HTTP_PROTOCOL_UNKNOWN,
@@ -53,6 +48,11 @@ impl rustc_serialize::Decodable for HttpProtocol {
} }
} }
impl FromStr for HttpProtocol {
type Err = ();
fn from_str(s: &str) -> Result<HttpProtocol, ()> { unimplemented!() }
}
impl FromPrimitive for HttpProtocol { impl FromPrimitive for HttpProtocol {
fn from_i64(i: i64) -> Option<HttpProtocol> { fn from_i64(i: i64) -> Option<HttpProtocol> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -86,6 +86,7 @@ impl de::Deserialize for HttpProtocol {
} }
} }
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum HttpMethod { enum HttpMethod {
METHOD_UNKNOWN, METHOD_UNKNOWN,
@@ -101,6 +102,11 @@ enum HttpMethod {
PATCH, PATCH,
} }
impl FromStr for HttpMethod {
type Err = ();
fn from_str(s: &str) -> Result<HttpMethod, ()> { unimplemented!() }
}
impl FromPrimitive for HttpMethod { impl FromPrimitive for HttpMethod {
fn from_i64(i: i64) -> Option<HttpMethod> { fn from_i64(i: i64) -> Option<HttpMethod> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -157,6 +163,7 @@ impl de::Deserialize for HttpMethod {
} }
} }
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum CacheStatus { enum CacheStatus {
CACHESTATUS_UNKNOWN, CACHESTATUS_UNKNOWN,
@@ -165,6 +172,11 @@ enum CacheStatus {
Hit, Hit,
} }
impl FromStr for CacheStatus {
type Err = ();
fn from_str(s: &str) -> Result<CacheStatus, ()> { unimplemented!() }
}
impl FromPrimitive for CacheStatus { impl FromPrimitive for CacheStatus {
fn from_i64(i: i64) -> Option<CacheStatus> { fn from_i64(i: i64) -> Option<CacheStatus> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -222,6 +234,7 @@ struct Origin {
protocol: OriginProtocol, protocol: OriginProtocol,
} }
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum OriginProtocol { enum OriginProtocol {
ORIGIN_PROTOCOL_UNKNOWN, ORIGIN_PROTOCOL_UNKNOWN,
@@ -229,6 +242,11 @@ enum OriginProtocol {
HTTPS, HTTPS,
} }
impl FromStr for OriginProtocol {
type Err = ();
fn from_str(s: &str) -> Result<OriginProtocol, ()> { unimplemented!() }
}
impl FromPrimitive for OriginProtocol { impl FromPrimitive for OriginProtocol {
fn from_i64(i: i64) -> Option<OriginProtocol> { fn from_i64(i: i64) -> Option<OriginProtocol> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -277,6 +295,7 @@ impl de::Deserialize for OriginProtocol {
} }
} }
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum ZonePlan { enum ZonePlan {
ZONEPLAN_UNKNOWN, ZONEPLAN_UNKNOWN,
@@ -286,6 +305,11 @@ enum ZonePlan {
ENT, ENT,
} }
impl FromStr for ZonePlan {
type Err = ();
fn from_str(s: &str) -> Result<ZonePlan, ()> { unimplemented!() }
}
impl FromPrimitive for ZonePlan { impl FromPrimitive for ZonePlan {
fn from_i64(i: i64) -> Option<ZonePlan> { fn from_i64(i: i64) -> Option<ZonePlan> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -596,6 +620,11 @@ enum Country {
ZW, ZW,
} }
impl FromStr for Country {
type Err = ();
fn from_str(s: &str) -> Result<Country, ()> { unimplemented!() }
}
impl FromPrimitive for Country { impl FromPrimitive for Country {
fn from_i64(i: i64) -> Option<Country> { fn from_i64(i: i64) -> Option<Country> {
FromPrimitive::from_u64(i as u64) FromPrimitive::from_u64(i as u64)
@@ -987,12 +1016,20 @@ impl MyMemWriter0 {
impl Write for MyMemWriter0 { impl Write for MyMemWriter0 {
#[cfg(feature = "nightly")]
#[inline] #[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.push_all(buf); self.buf.push_all(buf);
Ok(buf.len()) Ok(buf.len())
} }
#[cfg(not(feature = "nightly"))]
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.extend(buf.iter().cloned());
Ok(buf.len())
}
#[inline] #[inline]
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
Ok(()) Ok(())
@@ -1,16 +1,10 @@
#![feature(custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate serde;
extern crate rustc_serialize;
extern crate test;
use std::fmt::Debug; use std::fmt::Debug;
use std::collections::HashMap; use std::collections::HashMap;
use test::Bencher; use test::Bencher;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::{Decoder, Decodable};
use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::{Deserializer, Deserialize};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -1,15 +1,9 @@
#![feature(custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate serde;
extern crate rustc_serialize;
extern crate test;
use std::collections::HashMap; use std::collections::HashMap;
use test::Bencher; use test::Bencher;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::{Decoder, Decodable};
use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::{Deserializer, Deserialize};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -34,8 +28,6 @@ pub struct Outer {
pub enum Error { pub enum Error {
EndOfStream, EndOfStream,
SyntaxError, SyntaxError,
UnexpectedName,
ConversionError,
MissingField, MissingField,
OtherError, OtherError,
} }
@@ -1,15 +1,9 @@
#![feature(plugin, test)]
#![plugin(serde_macros)]
extern crate serde;
extern crate rustc_serialize;
extern crate test;
use std::fmt::Debug; use std::fmt::Debug;
use test::Bencher; use test::Bencher;
use rustc_serialize::{Decoder, Decodable}; use rustc_serialize::{Decoder, Decodable};
use serde;
use serde::de::{Deserializer, Deserialize}; use serde::de::{Deserializer, Deserialize};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
+22
View File
@@ -0,0 +1,22 @@
extern crate syntex;
extern crate serde_codegen;
use std::env;
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);
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}
+3
View File
@@ -0,0 +1,3 @@
extern crate serde;
include!(concat!(env!("OUT_DIR"), "/test.rs"));
+11
View File
@@ -0,0 +1,11 @@
/*
mod test_annotations;
mod test_bytes;
mod test_de;
mod test_json;
mod test_json_builder;
*/
mod test_macros;
/*
mod test_ser;
*/
@@ -1,9 +1,3 @@
#![feature(custom_attribute, custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate test;
extern crate serde;
use serde::json; use serde::json;
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -21,12 +15,22 @@ struct Rename {
} }
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
struct DirectionRename { struct FormatRename {
a1: i32, a1: i32,
#[serde(rename_serialize="a3", rename_deserialize="a4")] #[serde(rename(xml= "a4", json="a5"))]
a2: i32, a2: i32,
} }
#[derive(Debug, PartialEq, Deserialize, Serialize)]
enum SerEnum<A> {
Map {
a: i8,
#[serde(rename(xml= "c", json="d"))]
b: A,
},
}
#[test] #[test]
fn test_default() { fn test_default() {
let deserialized_value: Default = json::from_str(&"{\"a1\":1,\"a2\":2}").unwrap(); let deserialized_value: Default = json::from_str(&"{\"a1\":1,\"a2\":2}").unwrap();
@@ -47,11 +51,23 @@ fn test_rename() {
} }
#[test] #[test]
fn test_direction_rename() { fn test_format_rename() {
let value = DirectionRename { a1: 1, a2: 2 }; let value = FormatRename { a1: 1, a2: 2 };
let serialized_value = json::to_string(&value).unwrap(); let serialized_value = json::to_string(&value).unwrap();
assert_eq!(serialized_value, "{\"a1\":1,\"a3\":2}"); assert_eq!(serialized_value, "{\"a1\":1,\"a5\":2}");
let deserialized_value = json::from_str("{\"a1\":1,\"a4\":2}").unwrap(); let deserialized_value = json::from_str("{\"a1\":1,\"a5\":2}").unwrap();
assert_eq!(value, deserialized_value);
}
#[test]
fn test_enum_format_rename() {
let s1 = String::new();
let value = SerEnum::Map { a: 0i8, b: s1 };
let serialized_value = json::to_string(&value).unwrap();
let ans = "{\"Map\":{\"a\":0,\"d\":\"\"}}";
assert_eq!(serialized_value, ans);
let deserialized_value = json::from_str(ans).unwrap();
assert_eq!(value, deserialized_value); assert_eq!(value, deserialized_value);
} }
@@ -1,9 +1,4 @@
#![feature(custom_derive, plugin, test)] use serde;
#![plugin(serde_macros)]
extern crate test;
extern crate serde;
use serde::Serialize; use serde::Serialize;
use serde::bytes::{ByteBuf, Bytes}; use serde::bytes::{ByteBuf, Bytes};
use serde::json; use serde::json;
@@ -1,9 +1,3 @@
#![feature(custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate test;
extern crate serde;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::iter; use std::iter;
use std::vec; use std::vec;
@@ -652,6 +646,46 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_array {
[0; 0] => vec![
Token::Unit,
],
[0; 0] => vec![
Token::SeqStart(0),
Token::SeqEnd,
],
([0; 0], [1], [2, 3]) => vec![
Token::SeqStart(3),
Token::SeqSep,
Token::SeqStart(0),
Token::SeqEnd,
Token::SeqSep,
Token::SeqStart(1),
Token::SeqSep,
Token::I32(1),
Token::SeqEnd,
Token::SeqSep,
Token::SeqStart(2),
Token::SeqSep,
Token::I32(2),
Token::SeqSep,
Token::I32(3),
Token::SeqEnd,
Token::SeqEnd,
],
[0; 0] => vec![
Token::Name("Anything"),
Token::Unit,
],
[0; 0] => vec![
Token::Name("Anything"),
Token::SeqStart(0),
Token::SeqEnd,
],
}
test_tuple { test_tuple {
(1,) => vec![ (1,) => vec![
Token::SeqStart(1), Token::SeqStart(1),
@@ -1,9 +1,3 @@
#![feature(custom_derive, plugin, test, custom_attribute)]
#![plugin(serde_macros)]
extern crate test;
extern crate serde;
use std::fmt::Debug; use std::fmt::Debug;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -708,6 +702,8 @@ fn test_parse_number_errors() {
("1e", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)), ("1e", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)),
("1e+", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)), ("1e+", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)),
("1a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 2)), ("1a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 2)),
("777777777777777777777777777", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 20)),
("1e777777777777777777777777777", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 22)),
]); ]);
} }
@@ -1024,7 +1020,7 @@ fn test_missing_field() {
fn test_missing_renamed_field() { fn test_missing_renamed_field() {
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
struct Foo { struct Foo {
#[serde(rename_deserialize="y")] #[serde(rename="y")]
x: Option<u32>, x: Option<u32>,
} }
@@ -1042,3 +1038,44 @@ fn test_missing_renamed_field() {
))).unwrap(); ))).unwrap();
assert_eq!(value, Foo { x: Some(5) }); assert_eq!(value, Foo { x: Some(5) });
} }
#[test]
fn test_missing_fmt_renamed_field() {
#[derive(Debug, PartialEq, Deserialize)]
struct Foo {
#[serde(rename(json="y"))]
x: Option<u32>,
}
let value: Foo = from_str("{}").unwrap();
assert_eq!(value, Foo { x: None });
let value: Foo = from_str("{\"y\": 5}").unwrap();
assert_eq!(value, Foo { x: Some(5) });
let value: Foo = from_value(Value::Object(treemap!())).unwrap();
assert_eq!(value, Foo { x: None });
let value : Foo = from_value(Value::Object(treemap!(
"y".to_string() => Value::I64(5)
))).unwrap();
assert_eq!(value, Foo { x: Some(5) });
}
#[test]
fn test_find_path() {
let obj: Value = json::from_str(r#"{"x": {"a": 1}, "y": 2}"#).unwrap();
assert!(obj.find_path(&["x", "a"]).unwrap() == &Value::U64(1));
assert!(obj.find_path(&["y"]).unwrap() == &Value::U64(2));
assert!(obj.find_path(&["z"]).is_none());
}
#[test]
fn test_lookup() {
let obj: Value = json::from_str(r#"{"x": {"a": 1}, "y": 2}"#).unwrap();
assert!(obj.lookup("x.a").unwrap() == &Value::U64(1));
assert!(obj.lookup("y").unwrap() == &Value::U64(2));
assert!(obj.lookup("z").is_none());
}
@@ -1,5 +1,3 @@
extern crate serde;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde::json::value::Value; use serde::json::value::Value;
@@ -1,8 +1,3 @@
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate serde;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde::json::{self, Value}; use serde::json::{self, Value};
@@ -128,6 +123,14 @@ enum DeEnum<B, C: /* Trait */, D> /* where D: Trait */ {
}, },
} }
#[derive(Serialize)]
enum Lifetimes<'a> {
LifetimeSeq(&'a i32),
NoLifetimeSeq(i32),
LifetimeMap { a: &'a i32 },
NoLifetimeMap { a: i32 },
}
#[test] #[test]
fn test_named_unit() { fn test_named_unit() {
let named_unit = NamedUnit; let named_unit = NamedUnit;
@@ -443,3 +446,32 @@ fn test_de_enum_map() {
} }
); );
} }
#[test]
fn test_lifetimes() {
let value = 5;
let lifetime = Lifetimes::LifetimeSeq(&value);
assert_eq!(
json::to_string(&lifetime).unwrap(),
"{\"LifetimeSeq\":[5]}"
);
let lifetime = Lifetimes::NoLifetimeSeq(5);
assert_eq!(
json::to_string(&lifetime).unwrap(),
"{\"NoLifetimeSeq\":[5]}"
);
let value = 5;
let lifetime = Lifetimes::LifetimeMap { a: &value };
assert_eq!(
json::to_string(&lifetime).unwrap(),
"{\"LifetimeMap\":{\"a\":5}}"
);
let lifetime = Lifetimes::NoLifetimeMap { a: 5 };
assert_eq!(
json::to_string(&lifetime).unwrap(),
"{\"NoLifetimeMap\":{\"a\":5}}"
);
}
@@ -1,9 +1,3 @@
#![feature(custom_derive, plugin, test)]
#![plugin(serde_macros)]
extern crate test;
extern crate serde;
use std::vec; use std::vec;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -380,6 +374,24 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_array {
[0; 0] => vec![
Token::SeqStart(Some(0)),
Token::SeqEnd,
],
[1, 2, 3] => vec![
Token::SeqStart(Some(3)),
Token::SeqSep,
Token::I32(1),
Token::SeqSep,
Token::I32(2),
Token::SeqSep,
Token::I32(3),
Token::SeqEnd,
],
}
test_vec { test_vec {
Vec::<isize>::new() => vec![ Vec::<isize>::new() => vec![
Token::SeqStart(Some(0)), Token::SeqStart(Some(0)),