usecrate::Error; use serde::de::{Unexpected, Visitor}; use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::Ordering; use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; use std::i64;
/// Represents a YAML number, whether integer or floating point. #[derive(Clone, PartialEq, PartialOrd)] pubstruct Number {
n: N,
}
// "N" is a prefix of "NegInt"... this is a false positive. // https://github.com/Manishearth/rust-clippy/issues/1241 #[allow(clippy::enum_variant_names)] #[derive(Copy, Clone, Debug)] enum N {
PosInt(u64), /// Always less than zero.
NegInt(i64), /// May be infinite or NaN.
Float(f64),
}
impl Number { /// Returns true if the `Number` is an integer between `i64::MIN` and /// `i64::MAX`. /// /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to /// return the integer value. /// /// ``` /// # use std::i64; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let big = i64::MAX as u64 + 10; /// let v = yaml(r#" /// a: 64 /// b: 9223372036854775817 /// c: 256.0 /// "#); /// /// assert!(v["a"].is_i64()); /// /// // Greater than i64::MAX. /// assert!(!v["b"].is_i64()); /// /// // Numbers with a decimal point are not considered integers. /// assert!(!v["c"].is_i64()); /// ``` #[inline] #[allow(clippy::cast_sign_loss)] pubfn is_i64(&self) -> bool { matchself.n {
N::PosInt(v) => v <= i64::max_value() as u64,
N::NegInt(_) => true,
N::Float(_) => false,
}
}
/// Returns true if the `Number` is an integer between zero and `u64::MAX`. /// /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to /// return the integer value. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// a: 64 /// b: -64 /// c: 256.0 /// "#); /// /// assert!(v["a"].is_u64()); /// /// // Negative integer. /// assert!(!v["b"].is_u64()); /// /// // Numbers with a decimal point are not considered integers. /// assert!(!v["c"].is_u64()); /// ``` #[inline] pubfn is_u64(&self) -> bool { matchself.n {
N::PosInt(_) => true,
N::NegInt(_) | N::Float(_) => false,
}
}
/// Returns true if the `Number` can be represented by f64. /// /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to /// return the floating point value. /// /// Currently this function returns true if and only if both `is_i64` and /// `is_u64` return false but this is not a guarantee in the future. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// --- /// a: 256.0 /// b: 64 /// c: -64 /// "#); /// /// assert!(v["a"].is_f64()); /// /// // Integers. /// assert!(!v["b"].is_f64()); /// assert!(!v["c"].is_f64()); /// ``` #[inline] pubfn is_f64(&self) -> bool { matchself.n {
N::Float(_) => true,
N::PosInt(_) | N::NegInt(_) => false,
}
}
/// If the `Number` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// /// ``` /// # use std::i64; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let big = i64::MAX as u64 + 10; /// let v = yaml(r#" /// --- /// a: 64 /// b: 9223372036854775817 /// c: 256.0 /// "#); /// /// assert_eq!(v["a"].as_i64(), Some(64)); /// assert_eq!(v["b"].as_i64(), None); /// assert_eq!(v["c"].as_i64(), None); /// ``` #[inline] pubfn as_i64(&self) -> Option<i64> { matchself.n {
N::PosInt(n) => { if n <= i64::max_value() as u64 {
Some(n as i64)
} else {
None
}
}
N::NegInt(n) => Some(n),
N::Float(_) => None,
}
}
/// If the `Number` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// --- /// a: 64 /// b: -64 /// c: 256.0 /// "#); /// /// assert_eq!(v["a"].as_u64(), Some(64)); /// assert_eq!(v["b"].as_u64(), None); /// assert_eq!(v["c"].as_u64(), None); /// ``` #[inline] pubfn as_u64(&self) -> Option<u64> { matchself.n {
N::PosInt(n) => Some(n),
N::NegInt(_) | N::Float(_) => None,
}
}
/// Returns true if this value is NaN and false otherwise. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(!Number::from(256.0).is_nan()); /// /// assert!(Number::from(f64::NAN).is_nan()); /// /// assert!(!Number::from(f64::INFINITY).is_nan()); /// /// assert!(!Number::from(f64::NEG_INFINITY).is_nan()); /// /// assert!(!Number::from(1).is_nan()); /// ``` #[inline] pubfn is_nan(&self) -> bool { matchself.n {
N::PosInt(_) | N::NegInt(_) => false,
N::Float(f) => f.is_nan(),
}
}
/// Returns true if this value is positive infinity or negative infinity and /// false otherwise. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(!Number::from(256.0).is_infinite()); /// /// assert!(!Number::from(f64::NAN).is_infinite()); /// /// assert!(Number::from(f64::INFINITY).is_infinite()); /// /// assert!(Number::from(f64::NEG_INFINITY).is_infinite()); /// /// assert!(!Number::from(1).is_infinite()); /// ``` #[inline] pubfn is_infinite(&self) -> bool { matchself.n {
N::PosInt(_) | N::NegInt(_) => false,
N::Float(f) => f.is_infinite(),
}
}
/// Returns true if this number is neither infinite nor NaN. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(Number::from(256.0).is_finite()); /// /// assert!(!Number::from(f64::NAN).is_finite()); /// /// assert!(!Number::from(f64::INFINITY).is_finite()); /// /// assert!(!Number::from(f64::NEG_INFINITY).is_finite()); /// /// assert!(Number::from(1).is_finite()); /// ``` #[inline] pubfn is_finite(&self) -> bool { matchself.n {
N::PosInt(_) | N::NegInt(_) => true,
N::Float(f) => f.is_finite(),
}
}
}
impl fmt::Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { matchself.n {
N::PosInt(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() => { if f.is_sign_negative() {
formatter.write_str("-.inf")
} else {
formatter.write_str(".inf")
}
}
N::Float(f) => Display::fmt(&f, formatter),
}
}
}
impl Debug for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.n, formatter)
}
}
impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) {
(N::PosInt(a), N::PosInt(b)) => a == b,
(N::NegInt(a), N::NegInt(b)) => a == b,
(N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN; // the bit representation isn't preserved true
} else {
a == b
}
}
_ => false,
}
}
}
impl PartialOrd for N { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { match (*self, *other) {
(N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN
Some(Ordering::Equal)
} else {
a.partial_cmp(&b)
}
}
_ => Some(self.total_cmp(other)),
}
}
}
impl N { fn total_cmp(&self, other: &Self) -> Ordering { match (*self, *other) {
(N::PosInt(a), N::PosInt(b)) => a.cmp(&b),
(N::NegInt(a), N::NegInt(b)) => a.cmp(&b), // negint is always less than zero
(N::NegInt(_), N::PosInt(_)) => Ordering::Less,
(N::PosInt(_), N::NegInt(_)) => Ordering::Greater,
(N::Float(a), N::Float(b)) => a.partial_cmp(&b).unwrap_or_else(|| { // arbitrarily sort the NaN last if !a.is_nan() {
Ordering::Less
} elseif !b.is_nan() {
Ordering::Greater
} else {
Ordering::Equal
}
}), // arbitrarily sort integers below floats // FIXME: maybe something more sensible?
(_, N::Float(_)) => Ordering::Less,
(N::Float(_), _) => Ordering::Greater,
}
}
}
// This is fine, because we don't _really_ implement hash for floats // all other hash functions should work as expected #[allow(clippy::derive_hash_xor_eq)] impl Hash for Number { fn hash<H: Hasher>(&self, state: &mut H) { matchself.n {
N::Float(_) => { // you should feel bad for using f64 as a map key 3.hash(state);
}
N::PosInt(u) => u.hash(state),
N::NegInt(i) => i.hash(state),
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.