From 443577d48562fed9d3339e84c141129f6eaaf2c4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 10 Oct 2018 20:17:14 -0600 Subject: [PATCH 1/6] Add support for i128 and u128 i128 and u128 can now be serialized and deserialized. Support is conditionalized on the disabled-by-default `i128` feature flag, and requires rustc 1.26.0 or later. The minimum required version of Serde is now 1.0.60. Fixes #108 --- .travis.yml | 4 + Cargo.toml | 6 +- src/de.rs | 44 ++++++ src/lib.rs | 12 ++ src/number.rs | 323 ++++++++++++++++++++++++++++++++++++++++++-- src/ser.rs | 30 ++++ src/value/de.rs | 68 ++++++++++ src/value/mod.rs | 119 +++++++++++++++- tests/test_de.rs | 5 +- tests/test_serde.rs | 48 +++++++ 10 files changed, 644 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a49f2f3..32800694 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ matrix: - rust: 1.17.0 script: cargo check - rust: 1.21.0 + script: + - cargo build + - cargo test - rust: nightly env: CLIPPY script: | @@ -18,3 +21,4 @@ matrix: script: - cargo build - cargo test + - caro test --features "i128" diff --git a/Cargo.toml b/Cargo.toml index e1c698f0..1cdf03ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,10 @@ readme = "README.md" keywords = ["yaml", "serde"] [dependencies] +cfg-if = "0.1" dtoa = "0.4" linked-hash-map = "0.5" -serde = "1.0" +serde = "1.0.60" yaml-rust = "0.4" [dev-dependencies] @@ -20,5 +21,8 @@ serde_derive = "1.0" unindent = "0.1" version-sync = "0.5" +[features] +i128 = [] + [badges] travis-ci = { repository = "dtolnay/serde-yaml" } diff --git a/src/de.rs b/src/de.rs index 8d6b1fe2..2fc1171d 100644 --- a/src/de.rs +++ b/src/de.rs @@ -565,9 +565,19 @@ where if let Ok(n) = v.parse() { return visitor.visit_u64(n); } + serde_if_integer128! { + if let Ok(n) = v.parse() { + return visitor.visit_u128(n); + } + } if let Ok(n) = v.parse() { return visitor.visit_i64(n); } + serde_if_integer128! { + if let Ok(n) = v.parse() { + return visitor.visit_i128(n); + } + } match v.trim_left_matches('+') { ".inf" | ".Inf" | ".INF" => return visitor.visit_f64(f64::INFINITY), _ => (), @@ -685,6 +695,23 @@ impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut Deserializer<'a> { self.deserialize_scalar(visitor) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + #[cfg(not(feature = "i128"))] + fn deserialize_i128(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, @@ -713,6 +740,23 @@ impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut Deserializer<'a> { self.deserialize_scalar(visitor) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + #[cfg(not(feature = "i128"))] + fn deserialize_u128(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, diff --git a/src/lib.rs b/src/lib.rs index ea114269..b4315eef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,16 @@ //! assert_eq!(point, deserialized_point); //! # } //! ``` +//! +//! ## 128 bit numbers +//! +//! Support for `i128` and `u128` on Rust toolchains after `1.26.0` is enabled +//! through the `i128` feature. Add the following to `Cargo.toml`: +//! +//! ```toml,ignore +//! [dependencies.serde-yaml] +//! features = ["i128"] +//! ``` #![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.5")] #![deny(missing_docs)] @@ -88,6 +98,8 @@ result_unwrap_used, ))] +#[macro_use] +extern crate cfg_if; extern crate dtoa; extern crate linked_hash_map; #[macro_use] diff --git a/src/number.rs b/src/number.rs index 7081ab57..3b262d3e 100644 --- a/src/number.rs +++ b/src/number.rs @@ -8,10 +8,13 @@ use error::Error; use serde::de::{Unexpected, Visitor}; +serde_if_integer128! { + use serde::de::Error as SError; +} use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; -use std::i64; +use std::{i64, u64}; use std::mem; use private; @@ -32,6 +35,12 @@ enum N { NegInt(i64), /// May be infinite or NaN. Float(f64), + /// Always greater than u64::MAX + #[cfg(feature = "i128")] + PosInt128(u128), + /// Always less than i64::MIN + #[cfg(feature = "i128")] + NegInt128(i128) } impl Number { @@ -72,6 +81,60 @@ impl Number { N::PosInt(v) => v <= i64::max_value() as u64, N::NegInt(_) => true, N::Float(_) => false, + #[cfg(feature = "i128")] + N::PosInt128(v) => v <= i64::max_value() as u128, + #[cfg(feature = "i128")] + N::NegInt128(v) => v >= i64::min_value() as i128 + } + } + + /// Returns true if the `Number` is an integer between `i128::MIN` and + /// `i128::MAX`. + /// + /// For any Number on which `is_i128` returns true, `as_i128` is guaranteed + /// to return the integer value. + /// + /// ```rust + /// # #[macro_use] + /// # extern crate serde_yaml; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # fn main() { + /// let v = yaml(r#" + /// a: 64 + /// b: -64 + /// c: 256.0 + /// ## d does not fit in a u64 + /// d: 18446744073709551616 + /// ## e does not fit in an i64 + /// e: -9223372036854775809 + /// ## f does not fit in an i128 + /// f: 170141183460469231731687303715884105728 + /// "#); + /// + /// assert!(v["a"].is_i128()); + /// assert!(v["d"].is_i128()); + /// + /// // Negative integers. + /// assert!(v["b"].is_i128()); + /// assert!(v["e"].is_i128()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i128()); + /// + /// // Integers that are too big for i128 + /// assert!(!v["f"].is_i128()); + /// # } + /// ``` + #[cfg(feature = "i128")] + #[inline] + pub fn is_i128(&self) -> bool { + match self.n { + N::PosInt(_) => true, + N::NegInt(_) => true, + N::Float(_) => false, + N::PosInt128(v) => v <= i128::max_value() as u128, + N::NegInt128(_) => true, } } @@ -105,7 +168,48 @@ impl Number { pub fn is_u64(&self) -> bool { match self.n { N::PosInt(_) => true, - N::NegInt(_) | N::Float(_) => false, + _ => false, + } + } + + /// Returns true if the `Number` is an integer between zero and `u128::MAX`. + /// + /// For any Number on which `is_u128` returns true, `as_u128` is guaranteed + /// to return the integer value. + /// + /// ```rust + /// # #[macro_use] + /// # extern crate serde_yaml; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # fn main() { + /// let v = yaml(r#" + /// a: 64 + /// b: -64 + /// c: 256.0 + /// ## d does not fit in a u64 + /// d: 18446744073709551616 + /// ## e does not fit in an i64 + /// e: -9223372036854775809 + /// "#); + /// + /// assert!(v["a"].is_u128()); + /// assert!(v["d"].is_u128()); + /// + /// // Negative integers. + /// assert!(!v["b"].is_u128()); + /// assert!(!v["e"].is_u128()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u128()); + /// # } + /// ``` + #[cfg(feature = "i128")] + #[inline] + pub fn is_u128(&self) -> bool { + match self.n { + N::PosInt(_) | N::PosInt128(_) => true, + _ => false, } } @@ -141,7 +245,7 @@ impl Number { pub fn is_f64(&self) -> bool { match self.n { N::Float(_) => true, - N::PosInt(_) | N::NegInt(_) => false, + _ => false, } } @@ -177,7 +281,68 @@ impl Number { } else { None }, + #[cfg(feature = "i128")] + N::PosInt128(n) => if n <= i64::max_value() as u128 { + Some(n as i64) + } else { + None + }, N::NegInt(n) => Some(n), + #[cfg(feature = "i128")] + N::NegInt128(n) => if n >= i64::min_value() as i128 { + Some(n as i64) + } else { + None + }, + N::Float(_) => None, + } + } + + /// If the `Number` is an integer, represent it as i128 if possible. Returns + /// None otherwise. + /// + /// ```rust + /// # #[macro_use] + /// # extern crate serde_yaml; + /// # use std::i128; + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # fn main() { + /// println!("i128::MAX is {:?}", i128::MAX); + /// let v = yaml(r#" + /// --- + /// c: 256.0 + /// ## d fits in an i64 + /// d: -9223372036854775808 + /// ## e does not fit in an i64 + /// e: -9223372036854775809 + /// ## f fits in a u64 + /// f: 18446744073709551615 + /// ## g does not fit in a u64 + /// g: 18446744073709551616 + /// ## h does not fit in an i128 + /// h: 170141183460469231731687303715884105728 + /// "#); + /// + /// assert_eq!(v["c"].as_i128(), None); + /// assert_eq!(v["d"].as_i128(), Some(-9223372036854775808)); + /// assert_eq!(v["e"].as_i128(), Some(-9223372036854775809)); + /// assert_eq!(v["f"].as_i128(), Some(18446744073709551615)); + /// assert_eq!(v["g"].as_i128(), Some(18446744073709551616)); + /// assert_eq!(v["h"].as_i128(), None); + /// # } + /// ``` + #[cfg(feature = "i128")] + #[inline] + pub fn as_i128(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n as i128), + N::PosInt128(n) => if n <= i128::max_value() as u128 { + Some(n as i128) + } else { + None + }, + N::NegInt(n) => Some(n as i128), + N::NegInt128(n) => Some(n), N::Float(_) => None, } } @@ -207,7 +372,51 @@ impl Number { pub fn as_u64(&self) -> Option { match self.n { N::PosInt(n) => Some(n), - N::NegInt(_) | N::Float(_) => None, + #[cfg(feature = "i128")] + N::PosInt128(n) if n <= u64::MAX as u128 => Some(n as u64), + _ => None, + } + } + + /// If the `Number` is an integer, represent it as u128 if possible. Returns + /// None otherwise. + /// + /// ```rust + /// # #[macro_use] + /// # extern crate serde_yaml; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # fn main() { + /// let v = yaml(r#" + /// --- + /// c: 256.0 + /// ## d fits in an i64 + /// d: -9223372036854775808 + /// ## e does not fit in an i64 + /// e: -9223372036854775809 + /// ## f fits in a u64 + /// f: 18446744073709551615 + /// ## g does not fit in a u64 + /// g: 18446744073709551616 + /// ## h does not fit in an i128 + /// h: 170141183460469231731687303715884105728 + /// "#); + /// + /// assert_eq!(v["c"].as_u128(), None); + /// assert_eq!(v["d"].as_u128(), None); + /// assert_eq!(v["e"].as_u128(), None); + /// assert_eq!(v["f"].as_u128(), Some(18446744073709551615)); + /// assert_eq!(v["g"].as_u128(), Some(18446744073709551616)); + /// assert_eq!(v["h"].as_u128(), Some(170141183460469231731687303715884105728)); + /// # } + /// ``` + #[cfg(feature = "i128")] + #[inline] + pub fn as_u128(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n as u128), + N::PosInt128(n) => Some(n), + _ => None, } } @@ -243,6 +452,10 @@ impl Number { pub fn as_f64(&self) -> Option { match self.n { N::PosInt(n) => Some(n as f64), + #[cfg(feature = "i128")] + N::PosInt128(n) => Some(n as f64), + #[cfg(feature = "i128")] + N::NegInt128(n) => Some(n as f64), N::NegInt(n) => Some(n as f64), N::Float(n) => Some(n), } @@ -268,8 +481,8 @@ impl Number { #[inline] pub fn is_nan(&self) -> bool { match self.n { - N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_nan(), + _ => false, } } @@ -294,8 +507,8 @@ impl Number { #[inline] pub fn is_infinite(&self) -> bool { match self.n { - N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_infinite(), + _ => false, } } @@ -319,8 +532,8 @@ impl Number { #[inline] pub fn is_finite(&self) -> bool { match self.n { - N::PosInt(_) | N::NegInt(_) => true, N::Float(f) => f.is_finite(), + _ => true, } } } @@ -329,6 +542,10 @@ impl fmt::Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.n { N::PosInt(i) => Display::fmt(&i, formatter), + #[cfg(feature = "i128")] + N::PosInt128(i) => Display::fmt(&i, formatter), + #[cfg(feature = "i128")] + N::NegInt128(i) => Display::fmt(&i, formatter), N::NegInt(i) => Display::fmt(&i, formatter), N::Float(f) if f.is_nan() => formatter.write_str(".nan"), N::Float(f) if f.is_infinite() => { @@ -353,6 +570,10 @@ impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) { (N::PosInt(a), N::PosInt(b)) => a == b, + #[cfg(feature = "i128")] + (N::PosInt128(a), N::PosInt128(b)) => a == b, + #[cfg(feature = "i128")] + (N::NegInt128(a), N::NegInt128(b)) => a == b, (N::NegInt(a), N::NegInt(b)) => a == b, (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { @@ -379,6 +600,10 @@ impl Serialize for Number { { match self.n { N::PosInt(i) => serializer.serialize_u64(i), + #[cfg(feature = "i128")] + N::PosInt128(i) => serializer.serialize_u128(i), + #[cfg(feature = "i128")] + N::NegInt128(i) => serializer.serialize_i128(i), N::NegInt(i) => serializer.serialize_i64(i), N::Float(f) => serializer.serialize_f64(f), } @@ -405,11 +630,49 @@ impl<'de> Deserialize<'de> for Number { Ok(value.into()) } + serde_if_integer128! { + #[cfg(feature = "i128")] + #[inline] + fn visit_i128(self, value: i128) -> Result + where + E: SError, + { + Ok(value.into()) + } + #[cfg(not(feature = "i128"))] + #[inline] + fn visit_i128(self, _value: i128) -> Result + where + E: SError, + { + Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + #[inline] fn visit_u64(self, value: u64) -> Result { Ok(value.into()) } + serde_if_integer128! { + #[cfg(feature = "i128")] + #[inline] + fn visit_u128(self, value: u128) -> Result + where + E: SError, + { + Ok(value.into()) + } + #[cfg(not(feature = "i128"))] + #[inline] + fn visit_u128(self, _value: u128) -> Result + where + E: SError, + { + Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + #[inline] fn visit_f64(self, value: f64) -> Result { Ok(value.into()) @@ -430,13 +693,17 @@ impl<'de> Deserializer<'de> for Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), + #[cfg(feature = "i128")] + N::PosInt128(i) => visitor.visit_u128(i), + #[cfg(feature = "i128")] + N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { - bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } @@ -452,13 +719,17 @@ impl<'de, 'a> Deserializer<'de> for &'a Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), + #[cfg(feature = "i128")] + N::PosInt128(i) => visitor.visit_u128(i), + #[cfg(feature = "i128")] + N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { - bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } @@ -470,6 +741,19 @@ macro_rules! from_signed { impl From<$signed_ty> for Number { #[inline] #[cfg_attr(feature = "cargo-clippy", allow(cast_sign_loss))] + #[cfg(feature = "i128")] + fn from(i: $signed_ty) -> Self { + if i < 0 && i as i128 >= i64::MIN as i128 { + Number { n: N::NegInt(i as i64) } + } else if i < 0 { + Number { n: N::NegInt128(i as i128) } + } else if i as u128 <= u64::MAX as u128 { + Number { n: N::PosInt(i as u64) } + } else { + Number { n: N::PosInt128(i as u128) } + } + } + #[cfg(not(feature = "i128"))] fn from(i: $signed_ty) -> Self { if i < 0 { Number { n: N::NegInt(i as i64) } @@ -487,6 +771,15 @@ macro_rules! from_unsigned { $( impl From<$unsigned_ty> for Number { #[inline] + #[cfg(feature = "i128")] + fn from(u: $unsigned_ty) -> Self { + if u as u128 > u64::MAX as u128 { + Number { n: N::PosInt128(u as u128) } + } else { + Number { n: N::PosInt(u as u64) } + } + } + #[cfg(not(feature = "i128"))] fn from(u: $unsigned_ty) -> Self { Number { n: N::PosInt(u as u64) } } @@ -509,7 +802,11 @@ macro_rules! from_float { } from_signed!(i8 i16 i32 i64 isize); +#[cfg(feature = "i128")] +from_signed!(i128); from_unsigned!(u8 u16 u32 u64 usize); +#[cfg(feature = "i128")] +from_unsigned!(u128); from_float!(f32 f64); // This is fine, because we don't _really_ implement hash for floats @@ -523,7 +820,11 @@ impl Hash for Number { 3.hash(state) } N::PosInt(u) => u.hash(state), + #[cfg(feature = "i128")] + N::PosInt128(u) => u.hash(state), N::NegInt(i) => i.hash(state), + #[cfg(feature = "i128")] + N::NegInt128(i) => i.hash(state), } } } @@ -532,7 +833,11 @@ impl private { pub fn number_unexpected(number: &Number) -> Unexpected { match number.n { N::PosInt(u) => Unexpected::Unsigned(u), + #[cfg(feature = "i128")] + N::PosInt128(_) => unimplemented!(), N::NegInt(i) => Unexpected::Signed(i), + #[cfg(feature = "i128")] + N::NegInt128(_) => unimplemented!(), N::Float(f) => Unexpected::Float(f), } } diff --git a/src/ser.rs b/src/ser.rs index 61f10ed5..ba76edf5 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -53,6 +53,21 @@ impl ser::Serializer for Serializer { Ok(Yaml::Integer(v)) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn serialize_i128(self, v: i128) -> Result { + if v <= i64::max_value() as i128 && v >= i64::min_value() as i128 { + self.serialize_i64(v as i64) + } else { + Ok(Yaml::Real(v.to_string())) + } + } + #[cfg(not(feature = "i128"))] + fn serialize_i128(self, _v: i128) -> Result { + Err(ser::Error::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn serialize_u8(self, v: u8) -> Result { self.serialize_i64(v as i64) } @@ -73,6 +88,21 @@ impl ser::Serializer for Serializer { } } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn serialize_u128(self, v: u128) -> Result { + if v <= i64::max_value() as u128 { + self.serialize_i64(v as i64) + } else { + Ok(Yaml::Real(v.to_string())) + } + } + #[cfg(not(feature = "i128"))] + fn serialize_u128(self, _v: u128) -> Result { + Err(ser::Error::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn serialize_f32(self, v: f32) -> Result { self.serialize_f64(v as f64) } diff --git a/src/value/de.rs b/src/value/de.rs index 53613ee4..18619293 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -36,6 +36,23 @@ impl<'de> Deserialize<'de> for Value { Ok(Value::Number(i.into())) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn visit_i128(self, i: i128) -> Result + where + E: SError, + { + Ok(Value::Number(i.into())) + } + #[cfg(not(feature = "i128"))] + fn visit_i128(self, _i: i128) -> Result + where + E: SError, + { + Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn visit_u64(self, u: u64) -> Result where E: SError, @@ -43,6 +60,23 @@ impl<'de> Deserialize<'de> for Value { Ok(Value::Number(u.into())) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn visit_u128(self, u: u128) -> Result + where + E: SError, + { + Ok(Value::Number(u.into())) + } + #[cfg(not(feature = "i128"))] + fn visit_u128(self, _i: u128) -> Result + where + E: SError, + { + Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn visit_f64(self, f: f64) -> Result where E: SError, @@ -213,6 +247,23 @@ impl<'de> Deserializer<'de> for Value { self.deserialize_number(visitor) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + #[cfg(not(feature = "i128"))] + fn deserialize_i128(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, @@ -241,6 +292,23 @@ impl<'de> Deserializer<'de> for Value { self.deserialize_number(visitor) } + serde_if_integer128! { + #[cfg(feature = "i128")] + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + #[cfg(not(feature = "i128"))] + fn deserialize_u128(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) + } + } + fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, diff --git a/src/value/mod.rs b/src/value/mod.rs index deb5c351..1650877e 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -8,6 +8,8 @@ use std::f64; use std::hash::{Hash, Hasher}; +#[cfg(feature = "i128")] +use std::num::ParseIntError; use std::str::FromStr; use serde::de::{Deserialize, DeserializeOwned}; @@ -269,6 +271,28 @@ impl Value { self.as_i64().is_some() } + /// Returns true if the `Value` is an integer between `i128::MIN` and + /// `i128::MAX`. + /// + /// For any Value on which `is_i128` returns true, `as_i128` is guaranteed to + /// return the integer value. + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_i128()); + /// ``` + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_i128()); + /// ``` + #[cfg(feature = "i128")] + pub fn is_i128(&self) -> bool { + self.as_i128().is_some() + } + /// If the `Value` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// @@ -290,6 +314,28 @@ impl Value { } } + /// If the `Value` is an integer, represent it as i128 if possible. Returns + /// None otherwise. + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_i128(), Some(1337)); + /// ``` + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_i128(), None); + /// ``` + #[cfg(feature = "i128")] + pub fn as_i128(&self) -> Option { + match *self { + Value::Number(ref n) => n.as_i128(), + _ => None + } + } + /// Returns true if the `Value` is an integer between `u64::MIN` and /// `u64::MAX`. /// @@ -311,6 +357,28 @@ impl Value { self.as_u64().is_some() } + /// Returns true if the `Value` is an integer between `u128::MIN` and + /// `u128::MAX`. + /// + /// For any Value on which `is_u128` returns true, `as_u128` is guaranteed to + /// return the integer value. + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_u128()); + /// ``` + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_u128()); + /// ``` + #[cfg(feature = "i128")] + pub fn is_u128(&self) -> bool { + self.as_u128().is_some() + } + /// If the `Value` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// @@ -332,6 +400,28 @@ impl Value { } } + /// If the `Value` is an integer, represent it as u128 if possible. Returns + /// None otherwise. + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_u128(), Some(1337)); + /// ``` + /// + /// ```rust + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_u128(), None); + /// ``` + #[cfg(feature = "i128")] + pub fn as_u128(&self) -> Option { + match *self { + Value::Number(ref n) => n.as_u128(), + _ => None + } + } + /// Returns true if the `Value` is a number that can be represented by f64. /// /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to @@ -565,10 +655,33 @@ fn yaml_to_value(yaml: Yaml) -> Value { Value::Number(n.into()) } else if let Ok(n) = i64::from_str(&f) { Value::Number(n.into()) - } else if let Ok(n) = f64::from_str(&f) { - Value::Number(n.into()) } else { - Value::String(f) + cfg_if! { + if #[cfg(feature = "i128")] { + fn u128_from_str(f: &str) -> Result { + u128::from_str(f) + } + fn i128_from_str(f: &str) -> Result { + i128::from_str(f) + } + } else { + fn u128_from_str(_f: &str) -> Result { + Err(()) + } + fn i128_from_str(_f: &str) -> Result { + Err(()) + } + } + } + if let Ok(n) = u128_from_str(&f) { + Value::Number(n.into()) + } else if let Ok(n) = i128_from_str(&f) { + Value::Number(n.into()) + } else if let Ok(n) = f64::from_str(&f) { + Value::Number(n.into()) + } else { + Value::String(f) + } } } Yaml::Integer(i) => Value::Number(i.into()), diff --git a/tests/test_de.rs b/tests/test_de.rs index 89b23d26..7b223df3 100644 --- a/tests/test_de.rs +++ b/tests/test_de.rs @@ -169,10 +169,11 @@ fn test_number_as_string() { let yaml = unindent( " --- - value: 123456789012345678901234567890", + # Cannot be represented as u128 + value: 340282366920938463463374607431768211457", ); let expected = Num { - value: "123456789012345678901234567890".to_owned(), + value: "340282366920938463463374607431768211457".to_owned(), }; test_de(&yaml, &expected); } diff --git a/tests/test_serde.rs b/tests/test_serde.rs index b36beb36..6b334522 100644 --- a/tests/test_serde.rs +++ b/tests/test_serde.rs @@ -91,6 +91,54 @@ fn test_int_max_i64() { test_serde(&thing, &yaml); } +#[cfg(feature = "i128")] +#[test] +fn test_i128_small() { + let thing: i128 = -256; + let yaml = unindent( + " + --- + -256", + ); + test_serde(&thing, &yaml); +} + +#[cfg(feature = "i128")] +#[test] +fn test_i128_big() { + let thing: i128 = ::std::i64::MIN as i128 - 1; + let yaml = unindent( + " + --- + -9223372036854775809", + ); + test_serde(&thing, &yaml); +} + +#[cfg(feature = "i128")] +#[test] +fn test_u128_small() { + let thing: u128 = 256; + let yaml = unindent( + " + --- + 256", + ); + test_serde(&thing, &yaml); +} + +#[cfg(feature = "i128")] +#[test] +fn test_u128_big() { + let thing: u128 = ::std::u64::MAX as u128 + 1; + let yaml = unindent( + " + --- + 18446744073709551616", + ); + test_serde(&thing, &yaml); +} + #[test] fn test_float() { let thing = 25.6; From b5cea453aa1f30ca0da0c443db50db5678a631c6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Oct 2018 09:42:35 -0600 Subject: [PATCH 2/6] fix typo in Value::as_u64 docs --- src/value/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/value/mod.rs b/src/value/mod.rs index 1650877e..fd0540f2 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -379,7 +379,7 @@ impl Value { self.as_u128().is_some() } - /// If the `Value` is an integer, represent it as i64 if possible. Returns + /// If the `Value` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// /// ```rust From 5eb6ead0e91a8b3c9e128b2be0375d87f2197956 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Oct 2018 12:09:59 -0600 Subject: [PATCH 3/6] Fix typo in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 32800694..552cc79a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ matrix: script: - cargo build - cargo test - - caro test --features "i128" + - cargo test --features "i128" From c61139b12d9dd5c7d0e595589032d3f518fbd95f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Oct 2018 13:20:31 -0600 Subject: [PATCH 4/6] Remove the i128 feature flag 128-bit support is now automatically detected. --- .travis.yml | 4 --- Cargo.toml | 4 +-- build.rs | 58 +++++++++++++++++++++++++++++++ src/de.rs | 16 --------- src/lib.rs | 9 ++--- src/number.rs | 84 ++++++++++++++++++--------------------------- src/ser.rs | 10 ------ src/value/de.rs | 32 ----------------- src/value/mod.rs | 18 +++++----- tests/test_serde.rs | 8 ++--- 10 files changed, 108 insertions(+), 135 deletions(-) create mode 100644 build.rs diff --git a/.travis.yml b/.travis.yml index 552cc79a..7a49f2f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,6 @@ matrix: - rust: 1.17.0 script: cargo check - rust: 1.21.0 - script: - - cargo build - - cargo test - rust: nightly env: CLIPPY script: | @@ -21,4 +18,3 @@ matrix: script: - cargo build - cargo test - - cargo test --features "i128" diff --git a/Cargo.toml b/Cargo.toml index 1cdf03ea..efe7174d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/dtolnay/serde-yaml" documentation = "https://docs.rs/serde_yaml/" readme = "README.md" keywords = ["yaml", "serde"] +build = "build.rs" [dependencies] cfg-if = "0.1" @@ -21,8 +22,5 @@ serde_derive = "1.0" unindent = "0.1" version-sync = "0.5" -[features] -i128 = [] - [badges] travis-ci = { repository = "dtolnay/serde-yaml" } diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..8ab99e2c --- /dev/null +++ b/build.rs @@ -0,0 +1,58 @@ +// Automatically detect 128-bit integer support. +// The build script is copied from Serde +// https://github.com/serde-rs/serde/blob/7385b50249db95a6f819c11064eaf030afdc805d/serde/build.rs + +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // 128-bit integers stabilized in Rust 1.26: + // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html + // + // Disabled on Emscripten targets as Emscripten doesn't + // currently support integers larger than 64 bits. + if minor >= 26 && !emscripten { + println!("cargo:rustc-cfg=integer128"); + } +} + +fn rustc_minor_version() -> Option { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/src/de.rs b/src/de.rs index 2fc1171d..e7ee6b00 100644 --- a/src/de.rs +++ b/src/de.rs @@ -696,20 +696,12 @@ impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut Deserializer<'a> { } serde_if_integer128! { - #[cfg(feature = "i128")] fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } - #[cfg(not(feature = "i128"))] - fn deserialize_i128(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - Err(de::Error::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn deserialize_u8(self, visitor: V) -> Result @@ -741,20 +733,12 @@ impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut Deserializer<'a> { } serde_if_integer128! { - #[cfg(feature = "i128")] fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } - #[cfg(not(feature = "i128"))] - fn deserialize_u128(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - Err(de::Error::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn deserialize_f32(self, visitor: V) -> Result diff --git a/src/lib.rs b/src/lib.rs index b4315eef..7cfe10bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,13 +62,8 @@ //! //! ## 128 bit numbers //! -//! Support for `i128` and `u128` on Rust toolchains after `1.26.0` is enabled -//! through the `i128` feature. Add the following to `Cargo.toml`: -//! -//! ```toml,ignore -//! [dependencies.serde-yaml] -//! features = ["i128"] -//! ``` +//! Support for `i128` and `u128` is automatically enabled when using Rust +//! toolchains after `1.26.0`. #![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.5")] #![deny(missing_docs)] diff --git a/src/number.rs b/src/number.rs index 3b262d3e..d03c4197 100644 --- a/src/number.rs +++ b/src/number.rs @@ -36,10 +36,10 @@ enum N { /// May be infinite or NaN. Float(f64), /// Always greater than u64::MAX - #[cfg(feature = "i128")] + #[cfg(integer128)] PosInt128(u128), /// Always less than i64::MIN - #[cfg(feature = "i128")] + #[cfg(integer128)] NegInt128(i128) } @@ -81,9 +81,9 @@ impl Number { N::PosInt(v) => v <= i64::max_value() as u64, N::NegInt(_) => true, N::Float(_) => false, - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(v) => v <= i64::max_value() as u128, - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(v) => v >= i64::min_value() as i128 } } @@ -126,7 +126,7 @@ impl Number { /// assert!(!v["f"].is_i128()); /// # } /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] #[inline] pub fn is_i128(&self) -> bool { match self.n { @@ -204,7 +204,7 @@ impl Number { /// assert!(!v["c"].is_u128()); /// # } /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] #[inline] pub fn is_u128(&self) -> bool { match self.n { @@ -281,14 +281,14 @@ impl Number { } else { None }, - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(n) => if n <= i64::max_value() as u128 { Some(n as i64) } else { None }, N::NegInt(n) => Some(n), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(n) => if n >= i64::min_value() as i128 { Some(n as i64) } else { @@ -331,7 +331,7 @@ impl Number { /// assert_eq!(v["h"].as_i128(), None); /// # } /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] #[inline] pub fn as_i128(&self) -> Option { match self.n { @@ -372,7 +372,7 @@ impl Number { pub fn as_u64(&self) -> Option { match self.n { N::PosInt(n) => Some(n), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(n) if n <= u64::MAX as u128 => Some(n as u64), _ => None, } @@ -410,7 +410,7 @@ impl Number { /// assert_eq!(v["h"].as_u128(), Some(170141183460469231731687303715884105728)); /// # } /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] #[inline] pub fn as_u128(&self) -> Option { match self.n { @@ -452,9 +452,9 @@ impl Number { pub fn as_f64(&self) -> Option { match self.n { N::PosInt(n) => Some(n as f64), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(n) => Some(n as f64), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(n) => Some(n as f64), N::NegInt(n) => Some(n as f64), N::Float(n) => Some(n), @@ -542,9 +542,9 @@ impl fmt::Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.n { N::PosInt(i) => Display::fmt(&i, formatter), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(i) => Display::fmt(&i, formatter), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(i) => Display::fmt(&i, formatter), N::NegInt(i) => Display::fmt(&i, formatter), N::Float(f) if f.is_nan() => formatter.write_str(".nan"), @@ -570,9 +570,9 @@ impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) { (N::PosInt(a), N::PosInt(b)) => a == b, - #[cfg(feature = "i128")] + #[cfg(integer128)] (N::PosInt128(a), N::PosInt128(b)) => a == b, - #[cfg(feature = "i128")] + #[cfg(integer128)] (N::NegInt128(a), N::NegInt128(b)) => a == b, (N::NegInt(a), N::NegInt(b)) => a == b, (N::Float(a), N::Float(b)) => { @@ -600,9 +600,9 @@ impl Serialize for Number { { match self.n { N::PosInt(i) => serializer.serialize_u64(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(i) => serializer.serialize_u128(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(i) => serializer.serialize_i128(i), N::NegInt(i) => serializer.serialize_i64(i), N::Float(f) => serializer.serialize_f64(f), @@ -631,7 +631,6 @@ impl<'de> Deserialize<'de> for Number { } serde_if_integer128! { - #[cfg(feature = "i128")] #[inline] fn visit_i128(self, value: i128) -> Result where @@ -639,14 +638,6 @@ impl<'de> Deserialize<'de> for Number { { Ok(value.into()) } - #[cfg(not(feature = "i128"))] - #[inline] - fn visit_i128(self, _value: i128) -> Result - where - E: SError, - { - Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } #[inline] @@ -655,7 +646,6 @@ impl<'de> Deserialize<'de> for Number { } serde_if_integer128! { - #[cfg(feature = "i128")] #[inline] fn visit_u128(self, value: u128) -> Result where @@ -663,14 +653,6 @@ impl<'de> Deserialize<'de> for Number { { Ok(value.into()) } - #[cfg(not(feature = "i128"))] - #[inline] - fn visit_u128(self, _value: u128) -> Result - where - E: SError, - { - Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } #[inline] @@ -693,9 +675,9 @@ impl<'de> Deserializer<'de> for Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(i) => visitor.visit_u128(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), @@ -719,9 +701,9 @@ impl<'de, 'a> Deserializer<'de> for &'a Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(i) => visitor.visit_u128(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), @@ -741,7 +723,7 @@ macro_rules! from_signed { impl From<$signed_ty> for Number { #[inline] #[cfg_attr(feature = "cargo-clippy", allow(cast_sign_loss))] - #[cfg(feature = "i128")] + #[cfg(integer128)] fn from(i: $signed_ty) -> Self { if i < 0 && i as i128 >= i64::MIN as i128 { Number { n: N::NegInt(i as i64) } @@ -753,7 +735,7 @@ macro_rules! from_signed { Number { n: N::PosInt128(i as u128) } } } - #[cfg(not(feature = "i128"))] + #[cfg(not(integer128))] fn from(i: $signed_ty) -> Self { if i < 0 { Number { n: N::NegInt(i as i64) } @@ -771,7 +753,7 @@ macro_rules! from_unsigned { $( impl From<$unsigned_ty> for Number { #[inline] - #[cfg(feature = "i128")] + #[cfg(integer128)] fn from(u: $unsigned_ty) -> Self { if u as u128 > u64::MAX as u128 { Number { n: N::PosInt128(u as u128) } @@ -779,7 +761,7 @@ macro_rules! from_unsigned { Number { n: N::PosInt(u as u64) } } } - #[cfg(not(feature = "i128"))] + #[cfg(not(integer128))] fn from(u: $unsigned_ty) -> Self { Number { n: N::PosInt(u as u64) } } @@ -802,10 +784,10 @@ macro_rules! from_float { } from_signed!(i8 i16 i32 i64 isize); -#[cfg(feature = "i128")] +#[cfg(integer128)] from_signed!(i128); from_unsigned!(u8 u16 u32 u64 usize); -#[cfg(feature = "i128")] +#[cfg(integer128)] from_unsigned!(u128); from_float!(f32 f64); @@ -820,10 +802,10 @@ impl Hash for Number { 3.hash(state) } N::PosInt(u) => u.hash(state), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(u) => u.hash(state), N::NegInt(i) => i.hash(state), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(i) => i.hash(state), } } @@ -833,10 +815,10 @@ impl private { pub fn number_unexpected(number: &Number) -> Unexpected { match number.n { N::PosInt(u) => Unexpected::Unsigned(u), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::PosInt128(_) => unimplemented!(), N::NegInt(i) => Unexpected::Signed(i), - #[cfg(feature = "i128")] + #[cfg(integer128)] N::NegInt128(_) => unimplemented!(), N::Float(f) => Unexpected::Float(f), } diff --git a/src/ser.rs b/src/ser.rs index ba76edf5..2aed141c 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -54,7 +54,6 @@ impl ser::Serializer for Serializer { } serde_if_integer128! { - #[cfg(feature = "i128")] fn serialize_i128(self, v: i128) -> Result { if v <= i64::max_value() as i128 && v >= i64::min_value() as i128 { self.serialize_i64(v as i64) @@ -62,10 +61,6 @@ impl ser::Serializer for Serializer { Ok(Yaml::Real(v.to_string())) } } - #[cfg(not(feature = "i128"))] - fn serialize_i128(self, _v: i128) -> Result { - Err(ser::Error::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn serialize_u8(self, v: u8) -> Result { @@ -89,7 +84,6 @@ impl ser::Serializer for Serializer { } serde_if_integer128! { - #[cfg(feature = "i128")] fn serialize_u128(self, v: u128) -> Result { if v <= i64::max_value() as u128 { self.serialize_i64(v as i64) @@ -97,10 +91,6 @@ impl ser::Serializer for Serializer { Ok(Yaml::Real(v.to_string())) } } - #[cfg(not(feature = "i128"))] - fn serialize_u128(self, _v: u128) -> Result { - Err(ser::Error::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn serialize_f32(self, v: f32) -> Result { diff --git a/src/value/de.rs b/src/value/de.rs index 18619293..41bb8b05 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -37,20 +37,12 @@ impl<'de> Deserialize<'de> for Value { } serde_if_integer128! { - #[cfg(feature = "i128")] fn visit_i128(self, i: i128) -> Result where E: SError, { Ok(Value::Number(i.into())) } - #[cfg(not(feature = "i128"))] - fn visit_i128(self, _i: i128) -> Result - where - E: SError, - { - Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn visit_u64(self, u: u64) -> Result @@ -61,20 +53,12 @@ impl<'de> Deserialize<'de> for Value { } serde_if_integer128! { - #[cfg(feature = "i128")] fn visit_u128(self, u: u128) -> Result where E: SError, { Ok(Value::Number(u.into())) } - #[cfg(not(feature = "i128"))] - fn visit_u128(self, _i: u128) -> Result - where - E: SError, - { - Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn visit_f64(self, f: f64) -> Result @@ -248,20 +232,12 @@ impl<'de> Deserializer<'de> for Value { } serde_if_integer128! { - #[cfg(feature = "i128")] fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } - #[cfg(not(feature = "i128"))] - fn deserialize_i128(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - Err(SError::custom("i128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn deserialize_u8(self, visitor: V) -> Result @@ -293,20 +269,12 @@ impl<'de> Deserializer<'de> for Value { } serde_if_integer128! { - #[cfg(feature = "i128")] fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } - #[cfg(not(feature = "i128"))] - fn deserialize_u128(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - Err(SError::custom("u128 is not supported. Enable the `i128` feature of `serde-yaml`")) - } } fn deserialize_f32(self, visitor: V) -> Result diff --git a/src/value/mod.rs b/src/value/mod.rs index fd0540f2..a49b8b39 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -8,7 +8,7 @@ use std::f64; use std::hash::{Hash, Hasher}; -#[cfg(feature = "i128")] +#[cfg(integer128)] use std::num::ParseIntError; use std::str::FromStr; @@ -288,7 +288,7 @@ impl Value { /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert!(!v.is_i128()); /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] pub fn is_i128(&self) -> bool { self.as_i128().is_some() } @@ -328,7 +328,7 @@ impl Value { /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_i128(), None); /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] pub fn as_i128(&self) -> Option { match *self { Value::Number(ref n) => n.as_i128(), @@ -374,7 +374,7 @@ impl Value { /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert!(!v.is_u128()); /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] pub fn is_u128(&self) -> bool { self.as_u128().is_some() } @@ -414,7 +414,7 @@ impl Value { /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_u128(), None); /// ``` - #[cfg(feature = "i128")] + #[cfg(integer128)] pub fn as_u128(&self) -> Option { match *self { Value::Number(ref n) => n.as_u128(), @@ -657,11 +657,13 @@ fn yaml_to_value(yaml: Yaml) -> Value { Value::Number(n.into()) } else { cfg_if! { - if #[cfg(feature = "i128")] { - fn u128_from_str(f: &str) -> Result { + if #[cfg(integer128)] { + fn u128_from_str(f: &str) -> Result + { u128::from_str(f) } - fn i128_from_str(f: &str) -> Result { + fn i128_from_str(f: &str) -> Result + { i128::from_str(f) } } else { diff --git a/tests/test_serde.rs b/tests/test_serde.rs index 6b334522..5706e86c 100644 --- a/tests/test_serde.rs +++ b/tests/test_serde.rs @@ -91,7 +91,7 @@ fn test_int_max_i64() { test_serde(&thing, &yaml); } -#[cfg(feature = "i128")] +#[cfg(integer128)] #[test] fn test_i128_small() { let thing: i128 = -256; @@ -103,7 +103,7 @@ fn test_i128_small() { test_serde(&thing, &yaml); } -#[cfg(feature = "i128")] +#[cfg(integer128)] #[test] fn test_i128_big() { let thing: i128 = ::std::i64::MIN as i128 - 1; @@ -115,7 +115,7 @@ fn test_i128_big() { test_serde(&thing, &yaml); } -#[cfg(feature = "i128")] +#[cfg(integer128)] #[test] fn test_u128_small() { let thing: u128 = 256; @@ -127,7 +127,7 @@ fn test_u128_small() { test_serde(&thing, &yaml); } -#[cfg(feature = "i128")] +#[cfg(integer128)] #[test] fn test_u128_big() { let thing: u128 = ::std::u64::MAX as u128 + 1; From d79d55e14eaf2f31591e605d7889312071646ed4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Oct 2018 13:53:58 -0600 Subject: [PATCH 5/6] Clippy fixes --- src/number.rs | 18 ++++++++++-------- src/ser.rs | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/number.rs b/src/number.rs index d03c4197..faa30c5e 100644 --- a/src/number.rs +++ b/src/number.rs @@ -35,7 +35,7 @@ enum N { NegInt(i64), /// May be infinite or NaN. Float(f64), - /// Always greater than u64::MAX + /// Always greater than u64::max_value() #[cfg(integer128)] PosInt128(u128), /// Always less than i64::MIN @@ -130,11 +130,9 @@ impl Number { #[inline] pub fn is_i128(&self) -> bool { match self.n { - N::PosInt(_) => true, - N::NegInt(_) => true, + N::PosInt(_) | N::NegInt(_) | N::NegInt128(_) => true, N::Float(_) => false, N::PosInt128(v) => v <= i128::max_value() as u128, - N::NegInt128(_) => true, } } @@ -274,6 +272,7 @@ impl Number { /// # } /// ``` #[inline] + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] pub fn as_i64(&self) -> Option { match self.n { N::PosInt(n) => if n <= i64::max_value() as u64 { @@ -369,11 +368,12 @@ impl Number { /// # } /// ``` #[inline] + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] pub fn as_u64(&self) -> Option { match self.n { N::PosInt(n) => Some(n), #[cfg(integer128)] - N::PosInt128(n) if n <= u64::MAX as u128 => Some(n as u64), + N::PosInt128(n) if n <= u64::max_value() as u128 => Some(n as u64), _ => None, } } @@ -723,13 +723,14 @@ macro_rules! from_signed { impl From<$signed_ty> for Number { #[inline] #[cfg_attr(feature = "cargo-clippy", allow(cast_sign_loss))] + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] #[cfg(integer128)] fn from(i: $signed_ty) -> Self { - if i < 0 && i as i128 >= i64::MIN as i128 { + if i < 0 && i as i128 >= i64::min_value() as i128 { Number { n: N::NegInt(i as i64) } } else if i < 0 { Number { n: N::NegInt128(i as i128) } - } else if i as u128 <= u64::MAX as u128 { + } else if i as u128 <= u64::max_value() as u128 { Number { n: N::PosInt(i as u64) } } else { Number { n: N::PosInt128(i as u128) } @@ -754,8 +755,9 @@ macro_rules! from_unsigned { impl From<$unsigned_ty> for Number { #[inline] #[cfg(integer128)] + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] fn from(u: $unsigned_ty) -> Self { - if u as u128 > u64::MAX as u128 { + if u as u128 > u64::max_value() as u128 { Number { n: N::PosInt128(u as u128) } } else { Number { n: N::PosInt(u as u64) } diff --git a/src/ser.rs b/src/ser.rs index 2aed141c..370aa6b1 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -54,6 +54,7 @@ impl ser::Serializer for Serializer { } serde_if_integer128! { + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] fn serialize_i128(self, v: i128) -> Result { if v <= i64::max_value() as i128 && v >= i64::min_value() as i128 { self.serialize_i64(v as i64) @@ -84,6 +85,7 @@ impl ser::Serializer for Serializer { } serde_if_integer128! { + #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] fn serialize_u128(self, v: u128) -> Result { if v <= i64::max_value() as u128 { self.serialize_i64(v as i64) From 3df4cce7380192eb5fa327a73d825e5736589934 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 14 Oct 2018 13:41:18 -0700 Subject: [PATCH 6/6] Remove 128-bit integer variants from Number --- Cargo.toml | 2 - build.rs | 58 --------- src/lib.rs | 7 - src/number.rs | 311 ++------------------------------------------ src/value/de.rs | 18 --- src/value/mod.rs | 121 +---------------- tests/test_de.rs | 26 ++++ tests/test_serde.rs | 68 ++++------ 8 files changed, 63 insertions(+), 548 deletions(-) delete mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index efe7174d..8b182594 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,8 @@ repository = "https://github.com/dtolnay/serde-yaml" documentation = "https://docs.rs/serde_yaml/" readme = "README.md" keywords = ["yaml", "serde"] -build = "build.rs" [dependencies] -cfg-if = "0.1" dtoa = "0.4" linked-hash-map = "0.5" serde = "1.0.60" diff --git a/build.rs b/build.rs deleted file mode 100644 index 8ab99e2c..00000000 --- a/build.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Automatically detect 128-bit integer support. -// The build script is copied from Serde -// https://github.com/serde-rs/serde/blob/7385b50249db95a6f819c11064eaf030afdc805d/serde/build.rs - -use std::env; -use std::process::Command; -use std::str::{self, FromStr}; - -// The rustc-cfg strings below are *not* public API. Please let us know by -// opening a GitHub issue if your build environment requires some way to enable -// these cfgs other than by executing our build script. -fn main() { - let minor = match rustc_minor_version() { - Some(minor) => minor, - None => return, - }; - - let target = env::var("TARGET").unwrap(); - let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; - - // 128-bit integers stabilized in Rust 1.26: - // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html - // - // Disabled on Emscripten targets as Emscripten doesn't - // currently support integers larger than 64 bits. - if minor >= 26 && !emscripten { - println!("cargo:rustc-cfg=integer128"); - } -} - -fn rustc_minor_version() -> Option { - let rustc = match env::var_os("RUSTC") { - Some(rustc) => rustc, - None => return None, - }; - - let output = match Command::new(rustc).arg("--version").output() { - Ok(output) => output, - Err(_) => return None, - }; - - let version = match str::from_utf8(&output.stdout) { - Ok(version) => version, - Err(_) => return None, - }; - - let mut pieces = version.split('.'); - if pieces.next() != Some("rustc 1") { - return None; - } - - let next = match pieces.next() { - Some(next) => next, - None => return None, - }; - - u32::from_str(next).ok() -} diff --git a/src/lib.rs b/src/lib.rs index 7cfe10bf..ea114269 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,11 +59,6 @@ //! assert_eq!(point, deserialized_point); //! # } //! ``` -//! -//! ## 128 bit numbers -//! -//! Support for `i128` and `u128` is automatically enabled when using Rust -//! toolchains after `1.26.0`. #![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.5")] #![deny(missing_docs)] @@ -93,8 +88,6 @@ result_unwrap_used, ))] -#[macro_use] -extern crate cfg_if; extern crate dtoa; extern crate linked_hash_map; #[macro_use] diff --git a/src/number.rs b/src/number.rs index faa30c5e..964ba688 100644 --- a/src/number.rs +++ b/src/number.rs @@ -8,13 +8,10 @@ use error::Error; use serde::de::{Unexpected, Visitor}; -serde_if_integer128! { - use serde::de::Error as SError; -} use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; -use std::{i64, u64}; +use std::i64; use std::mem; use private; @@ -35,12 +32,6 @@ enum N { NegInt(i64), /// May be infinite or NaN. Float(f64), - /// Always greater than u64::max_value() - #[cfg(integer128)] - PosInt128(u128), - /// Always less than i64::MIN - #[cfg(integer128)] - NegInt128(i128) } impl Number { @@ -81,58 +72,6 @@ impl Number { N::PosInt(v) => v <= i64::max_value() as u64, N::NegInt(_) => true, N::Float(_) => false, - #[cfg(integer128)] - N::PosInt128(v) => v <= i64::max_value() as u128, - #[cfg(integer128)] - N::NegInt128(v) => v >= i64::min_value() as i128 - } - } - - /// Returns true if the `Number` is an integer between `i128::MIN` and - /// `i128::MAX`. - /// - /// For any Number on which `is_i128` returns true, `as_i128` is guaranteed - /// to return the integer value. - /// - /// ```rust - /// # #[macro_use] - /// # extern crate serde_yaml; - /// # - /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } - /// # fn main() { - /// let v = yaml(r#" - /// a: 64 - /// b: -64 - /// c: 256.0 - /// ## d does not fit in a u64 - /// d: 18446744073709551616 - /// ## e does not fit in an i64 - /// e: -9223372036854775809 - /// ## f does not fit in an i128 - /// f: 170141183460469231731687303715884105728 - /// "#); - /// - /// assert!(v["a"].is_i128()); - /// assert!(v["d"].is_i128()); - /// - /// // Negative integers. - /// assert!(v["b"].is_i128()); - /// assert!(v["e"].is_i128()); - /// - /// // Numbers with a decimal point are not considered integers. - /// assert!(!v["c"].is_i128()); - /// - /// // Integers that are too big for i128 - /// assert!(!v["f"].is_i128()); - /// # } - /// ``` - #[cfg(integer128)] - #[inline] - pub fn is_i128(&self) -> bool { - match self.n { - N::PosInt(_) | N::NegInt(_) | N::NegInt128(_) => true, - N::Float(_) => false, - N::PosInt128(v) => v <= i128::max_value() as u128, } } @@ -166,48 +105,7 @@ impl Number { pub fn is_u64(&self) -> bool { match self.n { N::PosInt(_) => true, - _ => false, - } - } - - /// Returns true if the `Number` is an integer between zero and `u128::MAX`. - /// - /// For any Number on which `is_u128` returns true, `as_u128` is guaranteed - /// to return the integer value. - /// - /// ```rust - /// # #[macro_use] - /// # extern crate serde_yaml; - /// # - /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } - /// # fn main() { - /// let v = yaml(r#" - /// a: 64 - /// b: -64 - /// c: 256.0 - /// ## d does not fit in a u64 - /// d: 18446744073709551616 - /// ## e does not fit in an i64 - /// e: -9223372036854775809 - /// "#); - /// - /// assert!(v["a"].is_u128()); - /// assert!(v["d"].is_u128()); - /// - /// // Negative integers. - /// assert!(!v["b"].is_u128()); - /// assert!(!v["e"].is_u128()); - /// - /// // Numbers with a decimal point are not considered integers. - /// assert!(!v["c"].is_u128()); - /// # } - /// ``` - #[cfg(integer128)] - #[inline] - pub fn is_u128(&self) -> bool { - match self.n { - N::PosInt(_) | N::PosInt128(_) => true, - _ => false, + N::NegInt(_) | N::Float(_) => false, } } @@ -243,7 +141,7 @@ impl Number { pub fn is_f64(&self) -> bool { match self.n { N::Float(_) => true, - _ => false, + N::PosInt(_) | N::NegInt(_) => false, } } @@ -272,7 +170,6 @@ impl Number { /// # } /// ``` #[inline] - #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] pub fn as_i64(&self) -> Option { match self.n { N::PosInt(n) => if n <= i64::max_value() as u64 { @@ -280,68 +177,7 @@ impl Number { } else { None }, - #[cfg(integer128)] - N::PosInt128(n) => if n <= i64::max_value() as u128 { - Some(n as i64) - } else { - None - }, N::NegInt(n) => Some(n), - #[cfg(integer128)] - N::NegInt128(n) => if n >= i64::min_value() as i128 { - Some(n as i64) - } else { - None - }, - N::Float(_) => None, - } - } - - /// If the `Number` is an integer, represent it as i128 if possible. Returns - /// None otherwise. - /// - /// ```rust - /// # #[macro_use] - /// # extern crate serde_yaml; - /// # use std::i128; - /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } - /// # fn main() { - /// println!("i128::MAX is {:?}", i128::MAX); - /// let v = yaml(r#" - /// --- - /// c: 256.0 - /// ## d fits in an i64 - /// d: -9223372036854775808 - /// ## e does not fit in an i64 - /// e: -9223372036854775809 - /// ## f fits in a u64 - /// f: 18446744073709551615 - /// ## g does not fit in a u64 - /// g: 18446744073709551616 - /// ## h does not fit in an i128 - /// h: 170141183460469231731687303715884105728 - /// "#); - /// - /// assert_eq!(v["c"].as_i128(), None); - /// assert_eq!(v["d"].as_i128(), Some(-9223372036854775808)); - /// assert_eq!(v["e"].as_i128(), Some(-9223372036854775809)); - /// assert_eq!(v["f"].as_i128(), Some(18446744073709551615)); - /// assert_eq!(v["g"].as_i128(), Some(18446744073709551616)); - /// assert_eq!(v["h"].as_i128(), None); - /// # } - /// ``` - #[cfg(integer128)] - #[inline] - pub fn as_i128(&self) -> Option { - match self.n { - N::PosInt(n) => Some(n as i128), - N::PosInt128(n) => if n <= i128::max_value() as u128 { - Some(n as i128) - } else { - None - }, - N::NegInt(n) => Some(n as i128), - N::NegInt128(n) => Some(n), N::Float(_) => None, } } @@ -368,55 +204,10 @@ impl Number { /// # } /// ``` #[inline] - #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] pub fn as_u64(&self) -> Option { match self.n { N::PosInt(n) => Some(n), - #[cfg(integer128)] - N::PosInt128(n) if n <= u64::max_value() as u128 => Some(n as u64), - _ => None, - } - } - - /// If the `Number` is an integer, represent it as u128 if possible. Returns - /// None otherwise. - /// - /// ```rust - /// # #[macro_use] - /// # extern crate serde_yaml; - /// # - /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } - /// # fn main() { - /// let v = yaml(r#" - /// --- - /// c: 256.0 - /// ## d fits in an i64 - /// d: -9223372036854775808 - /// ## e does not fit in an i64 - /// e: -9223372036854775809 - /// ## f fits in a u64 - /// f: 18446744073709551615 - /// ## g does not fit in a u64 - /// g: 18446744073709551616 - /// ## h does not fit in an i128 - /// h: 170141183460469231731687303715884105728 - /// "#); - /// - /// assert_eq!(v["c"].as_u128(), None); - /// assert_eq!(v["d"].as_u128(), None); - /// assert_eq!(v["e"].as_u128(), None); - /// assert_eq!(v["f"].as_u128(), Some(18446744073709551615)); - /// assert_eq!(v["g"].as_u128(), Some(18446744073709551616)); - /// assert_eq!(v["h"].as_u128(), Some(170141183460469231731687303715884105728)); - /// # } - /// ``` - #[cfg(integer128)] - #[inline] - pub fn as_u128(&self) -> Option { - match self.n { - N::PosInt(n) => Some(n as u128), - N::PosInt128(n) => Some(n), - _ => None, + N::NegInt(_) | N::Float(_) => None, } } @@ -452,10 +243,6 @@ impl Number { pub fn as_f64(&self) -> Option { match self.n { N::PosInt(n) => Some(n as f64), - #[cfg(integer128)] - N::PosInt128(n) => Some(n as f64), - #[cfg(integer128)] - N::NegInt128(n) => Some(n as f64), N::NegInt(n) => Some(n as f64), N::Float(n) => Some(n), } @@ -481,8 +268,8 @@ impl Number { #[inline] pub fn is_nan(&self) -> bool { match self.n { + N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_nan(), - _ => false, } } @@ -507,8 +294,8 @@ impl Number { #[inline] pub fn is_infinite(&self) -> bool { match self.n { + N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_infinite(), - _ => false, } } @@ -532,8 +319,8 @@ impl Number { #[inline] pub fn is_finite(&self) -> bool { match self.n { + N::PosInt(_) | N::NegInt(_) => true, N::Float(f) => f.is_finite(), - _ => true, } } } @@ -542,10 +329,6 @@ impl fmt::Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.n { N::PosInt(i) => Display::fmt(&i, formatter), - #[cfg(integer128)] - N::PosInt128(i) => Display::fmt(&i, formatter), - #[cfg(integer128)] - N::NegInt128(i) => Display::fmt(&i, formatter), N::NegInt(i) => Display::fmt(&i, formatter), N::Float(f) if f.is_nan() => formatter.write_str(".nan"), N::Float(f) if f.is_infinite() => { @@ -570,10 +353,6 @@ impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) { (N::PosInt(a), N::PosInt(b)) => a == b, - #[cfg(integer128)] - (N::PosInt128(a), N::PosInt128(b)) => a == b, - #[cfg(integer128)] - (N::NegInt128(a), N::NegInt128(b)) => a == b, (N::NegInt(a), N::NegInt(b)) => a == b, (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { @@ -600,10 +379,6 @@ impl Serialize for Number { { match self.n { N::PosInt(i) => serializer.serialize_u64(i), - #[cfg(integer128)] - N::PosInt128(i) => serializer.serialize_u128(i), - #[cfg(integer128)] - N::NegInt128(i) => serializer.serialize_i128(i), N::NegInt(i) => serializer.serialize_i64(i), N::Float(f) => serializer.serialize_f64(f), } @@ -630,31 +405,11 @@ impl<'de> Deserialize<'de> for Number { Ok(value.into()) } - serde_if_integer128! { - #[inline] - fn visit_i128(self, value: i128) -> Result - where - E: SError, - { - Ok(value.into()) - } - } - #[inline] fn visit_u64(self, value: u64) -> Result { Ok(value.into()) } - serde_if_integer128! { - #[inline] - fn visit_u128(self, value: u128) -> Result - where - E: SError, - { - Ok(value.into()) - } - } - #[inline] fn visit_f64(self, value: f64) -> Result { Ok(value.into()) @@ -675,18 +430,14 @@ impl<'de> Deserializer<'de> for Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), - #[cfg(integer128)] - N::PosInt128(i) => visitor.visit_u128(i), - #[cfg(integer128)] - N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes - byte_buf option unit unit_struct newtype_struct seq tuple + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } @@ -701,18 +452,14 @@ impl<'de, 'a> Deserializer<'de> for &'a Number { { match self.n { N::PosInt(i) => visitor.visit_u64(i), - #[cfg(integer128)] - N::PosInt128(i) => visitor.visit_u128(i), - #[cfg(integer128)] - N::NegInt128(i) => visitor.visit_i128(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes - byte_buf option unit unit_struct newtype_struct seq tuple + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } @@ -723,20 +470,6 @@ macro_rules! from_signed { impl From<$signed_ty> for Number { #[inline] #[cfg_attr(feature = "cargo-clippy", allow(cast_sign_loss))] - #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] - #[cfg(integer128)] - fn from(i: $signed_ty) -> Self { - if i < 0 && i as i128 >= i64::min_value() as i128 { - Number { n: N::NegInt(i as i64) } - } else if i < 0 { - Number { n: N::NegInt128(i as i128) } - } else if i as u128 <= u64::max_value() as u128 { - Number { n: N::PosInt(i as u64) } - } else { - Number { n: N::PosInt128(i as u128) } - } - } - #[cfg(not(integer128))] fn from(i: $signed_ty) -> Self { if i < 0 { Number { n: N::NegInt(i as i64) } @@ -754,16 +487,6 @@ macro_rules! from_unsigned { $( impl From<$unsigned_ty> for Number { #[inline] - #[cfg(integer128)] - #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] - fn from(u: $unsigned_ty) -> Self { - if u as u128 > u64::max_value() as u128 { - Number { n: N::PosInt128(u as u128) } - } else { - Number { n: N::PosInt(u as u64) } - } - } - #[cfg(not(integer128))] fn from(u: $unsigned_ty) -> Self { Number { n: N::PosInt(u as u64) } } @@ -786,11 +509,7 @@ macro_rules! from_float { } from_signed!(i8 i16 i32 i64 isize); -#[cfg(integer128)] -from_signed!(i128); from_unsigned!(u8 u16 u32 u64 usize); -#[cfg(integer128)] -from_unsigned!(u128); from_float!(f32 f64); // This is fine, because we don't _really_ implement hash for floats @@ -804,11 +523,7 @@ impl Hash for Number { 3.hash(state) } N::PosInt(u) => u.hash(state), - #[cfg(integer128)] - N::PosInt128(u) => u.hash(state), N::NegInt(i) => i.hash(state), - #[cfg(integer128)] - N::NegInt128(i) => i.hash(state), } } } @@ -817,11 +532,7 @@ impl private { pub fn number_unexpected(number: &Number) -> Unexpected { match number.n { N::PosInt(u) => Unexpected::Unsigned(u), - #[cfg(integer128)] - N::PosInt128(_) => unimplemented!(), N::NegInt(i) => Unexpected::Signed(i), - #[cfg(integer128)] - N::NegInt128(_) => unimplemented!(), N::Float(f) => Unexpected::Float(f), } } diff --git a/src/value/de.rs b/src/value/de.rs index 41bb8b05..9fdee7e3 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -36,15 +36,6 @@ impl<'de> Deserialize<'de> for Value { Ok(Value::Number(i.into())) } - serde_if_integer128! { - fn visit_i128(self, i: i128) -> Result - where - E: SError, - { - Ok(Value::Number(i.into())) - } - } - fn visit_u64(self, u: u64) -> Result where E: SError, @@ -52,15 +43,6 @@ impl<'de> Deserialize<'de> for Value { Ok(Value::Number(u.into())) } - serde_if_integer128! { - fn visit_u128(self, u: u128) -> Result - where - E: SError, - { - Ok(Value::Number(u.into())) - } - } - fn visit_f64(self, f: f64) -> Result where E: SError, diff --git a/src/value/mod.rs b/src/value/mod.rs index a49b8b39..020785df 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -8,8 +8,6 @@ use std::f64; use std::hash::{Hash, Hasher}; -#[cfg(integer128)] -use std::num::ParseIntError; use std::str::FromStr; use serde::de::{Deserialize, DeserializeOwned}; @@ -271,28 +269,6 @@ impl Value { self.as_i64().is_some() } - /// Returns true if the `Value` is an integer between `i128::MIN` and - /// `i128::MAX`. - /// - /// For any Value on which `is_i128` returns true, `as_i128` is guaranteed to - /// return the integer value. - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("1337").unwrap(); - /// assert!(v.is_i128()); - /// ``` - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("null").unwrap(); - /// assert!(!v.is_i128()); - /// ``` - #[cfg(integer128)] - pub fn is_i128(&self) -> bool { - self.as_i128().is_some() - } - /// If the `Value` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// @@ -314,28 +290,6 @@ impl Value { } } - /// If the `Value` is an integer, represent it as i128 if possible. Returns - /// None otherwise. - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("1337").unwrap(); - /// assert_eq!(v.as_i128(), Some(1337)); - /// ``` - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("false").unwrap(); - /// assert_eq!(v.as_i128(), None); - /// ``` - #[cfg(integer128)] - pub fn as_i128(&self) -> Option { - match *self { - Value::Number(ref n) => n.as_i128(), - _ => None - } - } - /// Returns true if the `Value` is an integer between `u64::MIN` and /// `u64::MAX`. /// @@ -357,28 +311,6 @@ impl Value { self.as_u64().is_some() } - /// Returns true if the `Value` is an integer between `u128::MIN` and - /// `u128::MAX`. - /// - /// For any Value on which `is_u128` returns true, `as_u128` is guaranteed to - /// return the integer value. - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("1337").unwrap(); - /// assert!(v.is_u128()); - /// ``` - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("null").unwrap(); - /// assert!(!v.is_u128()); - /// ``` - #[cfg(integer128)] - pub fn is_u128(&self) -> bool { - self.as_u128().is_some() - } - /// If the `Value` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// @@ -400,28 +332,6 @@ impl Value { } } - /// If the `Value` is an integer, represent it as u128 if possible. Returns - /// None otherwise. - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("1337").unwrap(); - /// assert_eq!(v.as_u128(), Some(1337)); - /// ``` - /// - /// ```rust - /// # use serde_yaml::Value; - /// let v: Value = serde_yaml::from_str("false").unwrap(); - /// assert_eq!(v.as_u128(), None); - /// ``` - #[cfg(integer128)] - pub fn as_u128(&self) -> Option { - match *self { - Value::Number(ref n) => n.as_u128(), - _ => None - } - } - /// Returns true if the `Value` is a number that can be represented by f64. /// /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to @@ -655,35 +565,10 @@ fn yaml_to_value(yaml: Yaml) -> Value { Value::Number(n.into()) } else if let Ok(n) = i64::from_str(&f) { Value::Number(n.into()) + } else if let Ok(n) = f64::from_str(&f) { + Value::Number(n.into()) } else { - cfg_if! { - if #[cfg(integer128)] { - fn u128_from_str(f: &str) -> Result - { - u128::from_str(f) - } - fn i128_from_str(f: &str) -> Result - { - i128::from_str(f) - } - } else { - fn u128_from_str(_f: &str) -> Result { - Err(()) - } - fn i128_from_str(_f: &str) -> Result { - Err(()) - } - } - } - if let Ok(n) = u128_from_str(&f) { - Value::Number(n.into()) - } else if let Ok(n) = i128_from_str(&f) { - Value::Number(n.into()) - } else if let Ok(n) = f64::from_str(&f) { - Value::Number(n.into()) - } else { - Value::String(f) - } + Value::String(f) } } Yaml::Integer(i) => Value::Number(i.into()), diff --git a/tests/test_de.rs b/tests/test_de.rs index 7b223df3..17482463 100644 --- a/tests/test_de.rs +++ b/tests/test_de.rs @@ -9,7 +9,9 @@ #[macro_use] extern crate serde_derive; +#[macro_use] extern crate serde; + extern crate serde_yaml; extern crate unindent; @@ -178,6 +180,30 @@ fn test_number_as_string() { test_de(&yaml, &expected); } +serde_if_integer128! { + #[test] + fn test_i128_big() { + let expected: i128 = ::std::i64::MIN as i128 - 1; + let yaml = unindent( + " + --- + -9223372036854775809", + ); + assert_eq!(expected, serde_yaml::from_str::(&yaml).unwrap()); + } + + #[test] + fn test_u128_big() { + let expected: u128 = ::std::u64::MAX as u128 + 1; + let yaml = unindent( + " + --- + 18446744073709551616", + ); + assert_eq!(expected, serde_yaml::from_str::(&yaml).unwrap()); + } +} + #[test] fn test_number_alias_as_string() { #[derive(Deserialize, PartialEq, Debug)] diff --git a/tests/test_serde.rs b/tests/test_serde.rs index 5706e86c..81fee70e 100644 --- a/tests/test_serde.rs +++ b/tests/test_serde.rs @@ -14,7 +14,9 @@ #[macro_use] extern crate serde_derive; +#[macro_use] extern crate serde; + extern crate serde_yaml; extern crate unindent; @@ -91,52 +93,28 @@ fn test_int_max_i64() { test_serde(&thing, &yaml); } -#[cfg(integer128)] -#[test] -fn test_i128_small() { - let thing: i128 = -256; - let yaml = unindent( - " - --- - -256", - ); - test_serde(&thing, &yaml); -} - -#[cfg(integer128)] -#[test] -fn test_i128_big() { - let thing: i128 = ::std::i64::MIN as i128 - 1; - let yaml = unindent( - " - --- - -9223372036854775809", - ); - test_serde(&thing, &yaml); -} - -#[cfg(integer128)] -#[test] -fn test_u128_small() { - let thing: u128 = 256; - let yaml = unindent( - " - --- - 256", - ); - test_serde(&thing, &yaml); -} +serde_if_integer128! { + #[test] + fn test_i128_small() { + let thing: i128 = -256; + let yaml = unindent( + " + --- + -256", + ); + test_serde(&thing, &yaml); + } -#[cfg(integer128)] -#[test] -fn test_u128_big() { - let thing: u128 = ::std::u64::MAX as u128 + 1; - let yaml = unindent( - " - --- - 18446744073709551616", - ); - test_serde(&thing, &yaml); + #[test] + fn test_u128_small() { + let thing: u128 = 256; + let yaml = unindent( + " + --- + 256", + ); + test_serde(&thing, &yaml); + } } #[test]