diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 195bb017..17abe1b2 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde" -version = "0.6.1" +version = "0.6.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" @@ -14,3 +14,7 @@ num = "^0.1.27" [features] nightly = [] +num-impls = ["num-bigint", "num-complex", "num-rational"] +num-bigint = ["num/bigint"] +num-complex = ["num/complex"] +num-rational = ["num/rational"] diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index 2ae1d5bf..df6ba502 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -895,3 +895,87 @@ impl Deserialize for Result where T: Deserialize, E: Deserialize { deserializer.visit_enum("Result", VARIANTS, Visitor(PhantomData)) } } + +/////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "num-bigint")] +impl Deserialize for ::num::bigint::BigInt { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer, + { + use ::num::Num; + use ::num::bigint::BigInt; + + struct BigIntVisitor; + + impl Visitor for BigIntVisitor { + type Value = BigInt; + + fn visit_str(&mut self, s: &str) -> Result + where E: Error, + { + match BigInt::from_str_radix(s, 10) { + Ok(v) => Ok(v), + Err(err) => Err(Error::invalid_value(&err.to_string())), + } + } + } + + deserializer.visit(BigIntVisitor) + } +} + +#[cfg(feature = "num-bigint")] +impl Deserialize for ::num::bigint::BigUint { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer, + { + use ::num::Num; + use ::num::bigint::BigUint; + + struct BigUintVisitor; + + impl Visitor for BigUintVisitor { + type Value = ::num::bigint::BigUint; + + fn visit_str(&mut self, s: &str) -> Result + where E: Error, + { + match BigUint::from_str_radix(s, 10) { + Ok(v) => Ok(v), + Err(err) => Err(Error::invalid_value(&err.to_string())), + } + } + } + + deserializer.visit(BigUintVisitor) + } +} + +#[cfg(feature = "num-complex")] +impl Deserialize for ::num::complex::Complex + where T: Deserialize + Clone + ::num::Num +{ + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer, + { + let (re, im) = try!(Deserialize::deserialize(deserializer)); + Ok(::num::complex::Complex::new(re, im)) + } +} + +#[cfg(feature = "num-rational")] +impl Deserialize for ::num::rational::Ratio + where T: Deserialize + Clone + ::num::Integer + PartialOrd +{ + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer, + { + let (numer, denom) = try!(Deserialize::deserialize(deserializer)); + if denom == ::num::Zero::zero() { + Err(Error::invalid_value("denominator is zero")) + } else { + Ok(::num::rational::Ratio::new_raw(numer, denom)) + } + } +} diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 51626a4e..75c3f4b0 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -21,6 +21,11 @@ pub trait Error: Sized { Error::syntax("incorrect type") } + /// Raised when a `Deserialize` was passed an incorrect value. + fn invalid_value(msg: &str) -> Self { + Error::syntax(msg) + } + /// Raised when a `Deserialize` type unexpectedly hit the end of the stream. fn end_of_stream() -> Self; diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 63aea2ec..6a9a369e 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -700,3 +700,37 @@ impl Serialize for NonZero where T: Serialize + Zeroable { (**self).serialize(serializer) } } + +/////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "num-bigint")] +impl Serialize for ::num::bigint::BigInt { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + self.to_str_radix(10).serialize(serializer) + } +} + +#[cfg(feature = "num-bigint")] +impl Serialize for ::num::bigint::BigUint { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + self.to_str_radix(10).serialize(serializer) + } +} + +#[cfg(feature = "num-complex")] +impl Serialize for ::num::complex::Complex + where T: Serialize + Clone + ::num::Num +{ + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + (&self.re, &self.im).serialize(serializer) + } +} + +#[cfg(feature = "num-rational")] +impl Serialize for ::num::rational::Ratio + where T: Serialize + Clone + ::num::Integer + PartialOrd +{ + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + (self.numer(), self.denom()).serialize(serializer) + } +} diff --git a/serde_macros/Cargo.toml b/serde_macros/Cargo.toml index e89f4017..93b01fc0 100644 --- a/serde_macros/Cargo.toml +++ b/serde_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_macros" -version = "0.6.5" +version = "0.6.6" authors = ["Erick Tryzelaar "] license = "MIT/Apache-2.0" description = "Macros to auto-generate implementations for the serde framework" @@ -18,4 +18,4 @@ serde_codegen = { version = "*", path = "../serde_codegen", default-features = f [dev-dependencies] num = "^0.1.27" rustc-serialize = "^0.3.16" -serde = { version = "*", path = "../serde", features = ["nightly"] } +serde = { version = "*", path = "../serde", features = ["nightly", "num-impls"] } diff --git a/serde_macros/tests/test.rs b/serde_macros/tests/test.rs index fd353e1b..26ab0042 100644 --- a/serde_macros/tests/test.rs +++ b/serde_macros/tests/test.rs @@ -1,6 +1,7 @@ #![feature(test, custom_attribute, custom_derive, plugin)] #![plugin(serde_macros)] +extern crate num; extern crate serde; extern crate test; diff --git a/serde_tests/Cargo.toml b/serde_tests/Cargo.toml index 86977330..c570e85f 100644 --- a/serde_tests/Cargo.toml +++ b/serde_tests/Cargo.toml @@ -18,7 +18,7 @@ serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-sy [dev-dependencies] num = "^0.1.27" rustc-serialize = "^0.3.16" -serde = { version = "*", path = "../serde" } +serde = { version = "*", path = "../serde", features = ["num-impls"] } syntex = "^0.22.0" [[test]] diff --git a/serde_tests/tests/test.rs b/serde_tests/tests/test.rs index 732c1432..416704ce 100644 --- a/serde_tests/tests/test.rs +++ b/serde_tests/tests/test.rs @@ -1,3 +1,4 @@ +extern crate num; extern crate serde; include!(concat!(env!("OUT_DIR"), "/test.rs")); diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index eebe179e..5f847770 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -1,5 +1,10 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use num::FromPrimitive; +use num::bigint::{BigInt, BigUint}; +use num::complex::Complex; +use num::rational::Ratio; + use serde::de::{Deserializer, Visitor}; use token::{Token, assert_de_tokens}; @@ -555,4 +560,33 @@ declare_tests! { Token::Unit, ], } + test_num_bigint { + BigInt::from_i64(123).unwrap() => vec![Token::Str("123")], + BigInt::from_i64(-123).unwrap() => vec![Token::Str("-123")], + } + test_num_biguint { + BigUint::from_i64(123).unwrap() => vec![Token::Str("123")], + } + test_num_complex { + Complex::new(1, 2) => vec![ + Token::SeqStart(Some(2)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + Token::SeqEnd, + ], + } + test_num_ratio { + Ratio::new(1, 2) => vec![ + Token::SeqStart(Some(2)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + Token::SeqEnd, + ], + } } diff --git a/serde_tests/tests/test_ser.rs b/serde_tests/tests/test_ser.rs index 29c22938..6a454814 100644 --- a/serde_tests/tests/test_ser.rs +++ b/serde_tests/tests/test_ser.rs @@ -1,5 +1,10 @@ use std::collections::BTreeMap; +use num::FromPrimitive; +use num::bigint::{BigInt, BigUint}; +use num::complex::Complex; +use num::rational::Ratio; + use token::Token; ////////////////////////////////////////////////////////////////////////// @@ -259,4 +264,33 @@ declare_ser_tests! { Token::MapEnd, ], } + test_num_bigint { + BigInt::from_i64(123).unwrap() => &[Token::Str("123")], + BigInt::from_i64(-123).unwrap() => &[Token::Str("-123")], + } + test_num_biguint { + BigUint::from_i64(123).unwrap() => &[Token::Str("123")], + } + test_num_complex { + Complex::new(1, 2) => &[ + Token::SeqStart(Some(2)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + Token::SeqEnd, + ], + } + test_num_ratio { + Ratio::new(1, 2) => &[ + Token::SeqStart(Some(2)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + Token::SeqEnd, + ], + } }