///|
/// A JSON number with serde_json's internal classification.
///
/// serde_json (without `arbitrary_precision`) keeps non-negative integers
/// that fit in `u64` as `PosInt`, negative integers that fit in `i64` as
/// `NegInt`, and everything else as a finite `Float`. The classification is
/// observable: `1` and `1.0` are different values and only the former is an
/// integer.
pub(all) enum Number {
PosInt(UInt64)
NegInt(Int64)
Float(Double)
} derive(Debug)
///|
/// Equality follows serde_json: numbers of different classes are never equal.
pub impl Eq for Number with fn equal(self, other) {
match (self, other) {
(PosInt(a), PosInt(b)) => a == b
(NegInt(a), NegInt(b)) => a == b
(Float(a), Float(b)) => a == b
_ => false
}
}
///|
/// Build a number from a `u64`.
pub fn Number::from_u64(n : UInt64) -> Number {
PosInt(n)
}
///|
/// Build a number from an `i64`, normalising non-negative values to
/// `PosInt` like serde_json's `From`.
pub fn Number::from_i64(n : Int64) -> Number {
if n >= 0 {
PosInt(n.reinterpret_as_uint64())
} else {
NegInt(n)
}
}
///|
/// Build a number from a finite `f64`; returns `None` for NaN or infinities.
pub fn Number::from_f64(d : Double) -> Number? {
if d.is_nan() || d.is_inf() {
None
} else {
Some(Float(d))
}
}
///|
pub fn Number::is_u64(self : Number) -> Bool {
self is PosInt(_)
}
///|
pub fn Number::is_i64(self : Number) -> Bool {
match self {
PosInt(n) => n <= 0x7FFF_FFFF_FFFF_FFFFUL
NegInt(_) => true
Float(_) => false
}
}
///|
pub fn Number::is_f64(self : Number) -> Bool {
self is Float(_)
}
///|
pub fn Number::as_u64(self : Number) -> UInt64? {
match self {
PosInt(n) => Some(n)
_ => None
}
}
///|
pub fn Number::as_i64(self : Number) -> Int64? {
match self {
PosInt(n) =>
if n <= 0x7FFF_FFFF_FFFF_FFFFUL {
Some(n.reinterpret_as_int64())
} else {
None
}
NegInt(n) => Some(n)
Float(_) => None
}
}
///|
/// Any number converts to `f64` (possibly losing precision), like serde_json.
pub fn Number::as_f64(self : Number) -> Double {
match self {
PosInt(n) => n.to_double()
NegInt(n) => n.to_double()
Float(d) => d
}
}
///|
/// Render like serde_json's `Display` for `Number` (itoa / ryu).
pub fn Number::to_string(self : Number) -> String {
match self {
PosInt(n) => n.to_string()
NegInt(n) => n.to_string()
Float(d) => format_f64(d)
}
}
///|
pub impl Show for Number with fn output(self, logger) {
logger.write_string(self.to_string())
}