usecrate::de; usecrate::error::{self, Error, ErrorImpl}; use serde::de::{Unexpected, Visitor}; use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::Ordering; use std::fmt::{self, Display}; use std::hash::{Hash, Hasher}; use std::str::FromStr;
/// 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)] 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. /// /// ``` /// # fn main() -> serde_yaml::Result<()> { /// let big = i64::MAX as u64 + 10; /// let v: serde_yaml::Value = serde_yaml::from_str(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()); /// # Ok(()) /// # } /// ``` #[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 main() -> serde_yaml::Result<()> { /// let v: serde_yaml::Value = serde_yaml::from_str(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()); /// # Ok(()) /// # } /// ``` #[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 main() -> serde_yaml::Result<()> { /// let v: serde_yaml::Value = serde_yaml::from_str(r#" /// a: 256.0 /// b: 64 /// c: -64 /// "#)?; /// /// assert!(v["a"].is_f64()); /// /// // Integers. /// assert!(!v["b"].is_f64()); /// assert!(!v["c"].is_f64()); /// # Ok(()) /// # } /// ``` #[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. /// /// ``` /// # fn main() -> serde_yaml::Result<()> { /// let big = i64::MAX as u64 + 10; /// let v: serde_yaml::Value = serde_yaml::from_str(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); /// # Ok(()) /// # } /// ``` #[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 main() -> serde_yaml::Result<()> { /// let v: serde_yaml::Value = serde_yaml::from_str(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); /// # Ok(()) /// # } /// ``` #[inline] pubfn as_u64(&self) -> Option<u64> { matchself.n {
N::PosInt(n) => Some(n),
N::NegInt(_) | N::Float(_) => None,
}
}
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,
}
}
}
impl From<f32> for Number { fn from(f: f32) -> Self {
Number::from(f as f64)
}
}
impl From<f64> for Number { fn from(mut f: f64) -> Self { if f.is_nan() { // Destroy NaN sign, signaling, and payload. YAML only has one NaN.
f = f64::NAN.copysign(1.0);
}
Number { n: N::Float(f) }
}
}
// This is fine, because we don't _really_ implement hash for floats // all other hash functions should work as expected #[allow(clippy::derived_hash_with_manual_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.