Allows building XSD assumptions into itpull/171/head
parent
dc1acd17a8
commit
1c7bec5226
@ -0,0 +1,281 @@ |
||||
use crate::model::xsd::Float; |
||||
use std::cmp::Ordering; |
||||
use std::fmt; |
||||
use std::hash::{Hash, Hasher}; |
||||
use std::num::ParseFloatError; |
||||
use std::ops::{Add, Div, Mul, Neg, Sub}; |
||||
use std::str::FromStr; |
||||
|
||||
/// [XML Schema `double` datatype](https://www.w3.org/TR/xmlschema11-2/#double) implementation.
|
||||
///
|
||||
/// The "==" implementation is identity, not equality
|
||||
#[derive(Debug, Clone, Copy, Default)] |
||||
#[repr(transparent)] |
||||
pub struct Double { |
||||
value: f64, |
||||
} |
||||
|
||||
impl Double { |
||||
#[inline] |
||||
pub fn from_be_bytes(bytes: [u8; 8]) -> Self { |
||||
Self { |
||||
value: f64::from_be_bytes(bytes), |
||||
} |
||||
} |
||||
|
||||
#[inline] |
||||
pub fn to_be_bytes(self) -> [u8; 8] { |
||||
self.value.to_be_bytes() |
||||
} |
||||
|
||||
/// [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs)
|
||||
#[inline] |
||||
pub fn abs(self) -> Self { |
||||
self.value.abs().into() |
||||
} |
||||
|
||||
/// [fn:ceiling](https://www.w3.org/TR/xpath-functions/#func-ceiling)
|
||||
#[inline] |
||||
pub fn ceil(self) -> Self { |
||||
self.value.ceil().into() |
||||
} |
||||
|
||||
/// [fn:floor](https://www.w3.org/TR/xpath-functions/#func-floor)
|
||||
#[inline] |
||||
pub fn floor(self) -> Self { |
||||
self.value.floor().into() |
||||
} |
||||
|
||||
/// [fn:round](https://www.w3.org/TR/xpath-functions/#func-round)
|
||||
#[inline] |
||||
pub fn round(self) -> Self { |
||||
self.value.round().into() |
||||
} |
||||
|
||||
/// Casts i64 into `Double`
|
||||
#[inline] |
||||
#[allow(clippy::cast_precision_loss)] |
||||
pub fn from_i64(value: i64) -> Self { |
||||
Self { |
||||
value: value as f64, |
||||
} |
||||
} |
||||
|
||||
/// Casts `Double` into i64 without taking care of loss
|
||||
#[inline] |
||||
#[allow(clippy::cast_possible_truncation)] |
||||
pub fn to_i64(self) -> i64 { |
||||
self.value as i64 |
||||
} |
||||
|
||||
/// Casts `Double` into f32 without taking care of loss
|
||||
#[inline] |
||||
#[allow(clippy::cast_possible_truncation)] |
||||
pub fn to_f32(self) -> f32 { |
||||
self.value as f32 |
||||
} |
||||
|
||||
/// Creates a `bool` from a `Decimal` according to xsd:boolean cast constraints
|
||||
#[inline] |
||||
pub fn to_bool(self) -> bool { |
||||
self.value != 0. && !self.value.is_nan() |
||||
} |
||||
} |
||||
|
||||
impl From<Double> for f64 { |
||||
#[inline] |
||||
fn from(value: Double) -> Self { |
||||
value.value |
||||
} |
||||
} |
||||
|
||||
impl From<f64> for Double { |
||||
#[inline] |
||||
fn from(value: f64) -> Self { |
||||
Self { value } |
||||
} |
||||
} |
||||
|
||||
impl From<i8> for Double { |
||||
#[inline] |
||||
fn from(value: i8) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<i16> for Double { |
||||
#[inline] |
||||
fn from(value: i16) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<i32> for Double { |
||||
#[inline] |
||||
fn from(value: i32) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<u8> for Double { |
||||
#[inline] |
||||
fn from(value: u8) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<u16> for Double { |
||||
#[inline] |
||||
fn from(value: u16) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<u32> for Double { |
||||
#[inline] |
||||
fn from(value: u32) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<Float> for Double { |
||||
#[inline] |
||||
fn from(value: Float) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl FromStr for Double { |
||||
type Err = ParseFloatError; |
||||
|
||||
/// Parses decimals lexical mapping
|
||||
#[inline] |
||||
fn from_str(input: &str) -> Result<Self, ParseFloatError> { |
||||
Ok(f64::from_str(input)?.into()) |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Double { |
||||
#[inline] |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if self.value == f64::INFINITY { |
||||
f.write_str("INF") |
||||
} else if self.value == f64::NEG_INFINITY { |
||||
f.write_str("-INF") |
||||
} else { |
||||
self.value.fmt(f) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl PartialEq for Double { |
||||
#[inline] |
||||
fn eq(&self, other: &Self) -> bool { |
||||
self.value.to_ne_bytes() == other.value.to_ne_bytes() |
||||
} |
||||
} |
||||
|
||||
impl Eq for Double {} |
||||
|
||||
impl PartialOrd for Double { |
||||
#[inline] |
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
||||
self.value.partial_cmp(&other.value) |
||||
} |
||||
} |
||||
|
||||
impl Hash for Double { |
||||
#[inline] |
||||
fn hash<H: Hasher>(&self, state: &mut H) { |
||||
state.write(&self.value.to_ne_bytes()) |
||||
} |
||||
} |
||||
|
||||
impl Neg for Double { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn neg(self) -> Self { |
||||
(-self.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Add for Double { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn add(self, rhs: Self) -> Self { |
||||
(self.value + rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Sub for Double { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn sub(self, rhs: Self) -> Self { |
||||
(self.value - rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Mul for Double { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn mul(self, rhs: Self) -> Self { |
||||
(self.value * rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Div for Double { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn div(self, rhs: Self) -> Self { |
||||
(self.value / rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn eq() { |
||||
assert_eq!(Double::from(0_f64), Double::from(0_f64)); |
||||
assert_eq!(Double::from(f64::NAN), Double::from(f64::NAN)); |
||||
assert_ne!(Double::from(-0.), Double::from(0.)); |
||||
} |
||||
|
||||
#[test] |
||||
fn from_str() -> Result<(), ParseFloatError> { |
||||
assert_eq!(Double::from(f64::NAN), Double::from_str("NaN")?); |
||||
assert_eq!(Double::from(f64::INFINITY), Double::from_str("INF")?); |
||||
assert_eq!(Double::from(f64::INFINITY), Double::from_str("+INF")?); |
||||
assert_eq!(Double::from(f64::NEG_INFINITY), Double::from_str("-INF")?); |
||||
assert_eq!(Double::from(0.), Double::from_str("0.0E0")?); |
||||
assert_eq!(Double::from(-0.), Double::from_str("-0.0E0")?); |
||||
Ok(()) |
||||
} |
||||
|
||||
#[test] |
||||
fn to_string() { |
||||
assert_eq!("NaN", Double::from(f64::NAN).to_string()); |
||||
assert_eq!("INF", Double::from(f64::INFINITY).to_string()); |
||||
assert_eq!("-INF", Double::from(f64::NEG_INFINITY).to_string()); |
||||
} |
||||
} |
@ -0,0 +1,253 @@ |
||||
use std::cmp::Ordering; |
||||
use std::fmt; |
||||
use std::hash::{Hash, Hasher}; |
||||
use std::num::ParseFloatError; |
||||
use std::ops::{Add, Div, Mul, Neg, Sub}; |
||||
use std::str::FromStr; |
||||
|
||||
/// [XML Schema `float` datatype](https://www.w3.org/TR/xmlschema11-2/#float) implementation.
|
||||
///
|
||||
/// The "==" implementation is identity, not equality
|
||||
#[derive(Debug, Clone, Copy, Default)] |
||||
#[repr(transparent)] |
||||
pub struct Float { |
||||
value: f32, |
||||
} |
||||
|
||||
impl Float { |
||||
#[inline] |
||||
pub fn from_be_bytes(bytes: [u8; 4]) -> Self { |
||||
Self { |
||||
value: f32::from_be_bytes(bytes), |
||||
} |
||||
} |
||||
|
||||
#[inline] |
||||
pub fn to_be_bytes(self) -> [u8; 4] { |
||||
self.value.to_be_bytes() |
||||
} |
||||
|
||||
/// [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs)
|
||||
#[inline] |
||||
pub fn abs(self) -> Self { |
||||
self.value.abs().into() |
||||
} |
||||
|
||||
/// [fn:ceiling](https://www.w3.org/TR/xpath-functions/#func-ceiling)
|
||||
#[inline] |
||||
pub fn ceil(self) -> Self { |
||||
self.value.ceil().into() |
||||
} |
||||
|
||||
/// [fn:floor](https://www.w3.org/TR/xpath-functions/#func-floor)
|
||||
#[inline] |
||||
pub fn floor(self) -> Self { |
||||
self.value.floor().into() |
||||
} |
||||
|
||||
/// [fn:round](https://www.w3.org/TR/xpath-functions/#func-round)
|
||||
#[inline] |
||||
pub fn round(self) -> Self { |
||||
self.value.round().into() |
||||
} |
||||
|
||||
/// Casts i64 into `Float`
|
||||
#[inline] |
||||
#[allow(clippy::cast_precision_loss)] |
||||
pub fn from_i64(value: i64) -> Self { |
||||
Self { |
||||
value: value as f32, |
||||
} |
||||
} |
||||
|
||||
/// Casts `Float` into i64 without taking care of loss
|
||||
#[inline] |
||||
#[allow(clippy::cast_possible_truncation)] |
||||
pub fn to_i64(self) -> i64 { |
||||
self.value as i64 |
||||
} |
||||
|
||||
/// Creates a `bool` from a `Decimal` according to xsd:boolean cast constraints
|
||||
#[inline] |
||||
pub fn to_bool(self) -> bool { |
||||
self.value != 0. && !self.value.is_nan() |
||||
} |
||||
} |
||||
|
||||
impl From<Float> for f32 { |
||||
#[inline] |
||||
fn from(value: Float) -> Self { |
||||
value.value |
||||
} |
||||
} |
||||
|
||||
impl From<Float> for f64 { |
||||
#[inline] |
||||
fn from(value: Float) -> Self { |
||||
value.value.into() |
||||
} |
||||
} |
||||
|
||||
impl From<f32> for Float { |
||||
#[inline] |
||||
fn from(value: f32) -> Self { |
||||
Self { value } |
||||
} |
||||
} |
||||
|
||||
impl From<i8> for Float { |
||||
#[inline] |
||||
fn from(value: i8) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<i16> for Float { |
||||
#[inline] |
||||
fn from(value: i16) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<u8> for Float { |
||||
#[inline] |
||||
fn from(value: u8) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<u16> for Float { |
||||
#[inline] |
||||
fn from(value: u16) -> Self { |
||||
Self { |
||||
value: value.into(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl FromStr for Float { |
||||
type Err = ParseFloatError; |
||||
|
||||
/// Parses decimals lexical mapping
|
||||
#[inline] |
||||
fn from_str(input: &str) -> Result<Self, ParseFloatError> { |
||||
Ok(f32::from_str(input)?.into()) |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Float { |
||||
#[inline] |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if self.value == f32::INFINITY { |
||||
f.write_str("INF") |
||||
} else if self.value == f32::NEG_INFINITY { |
||||
f.write_str("-INF") |
||||
} else { |
||||
self.value.fmt(f) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl PartialEq for Float { |
||||
#[inline] |
||||
fn eq(&self, other: &Self) -> bool { |
||||
self.value.to_ne_bytes() == other.value.to_ne_bytes() |
||||
} |
||||
} |
||||
|
||||
impl Eq for Float {} |
||||
|
||||
impl PartialOrd for Float { |
||||
#[inline] |
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
||||
self.value.partial_cmp(&other.value) |
||||
} |
||||
} |
||||
|
||||
impl Hash for Float { |
||||
#[inline] |
||||
fn hash<H: Hasher>(&self, state: &mut H) { |
||||
state.write(&self.value.to_ne_bytes()) |
||||
} |
||||
} |
||||
|
||||
impl Neg for Float { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn neg(self) -> Self { |
||||
(-self.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Add for Float { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn add(self, rhs: Self) -> Self { |
||||
(self.value + rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Sub for Float { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn sub(self, rhs: Self) -> Self { |
||||
(self.value - rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Mul for Float { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn mul(self, rhs: Self) -> Self { |
||||
(self.value * rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
impl Div for Float { |
||||
type Output = Self; |
||||
|
||||
#[inline] |
||||
fn div(self, rhs: Self) -> Self { |
||||
(self.value / rhs.value).into() |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn eq() { |
||||
assert_eq!(Float::from(0_f32), Float::from(0_f32)); |
||||
assert_eq!(Float::from(f32::NAN), Float::from(f32::NAN)); |
||||
assert_ne!(Float::from(-0.), Float::from(0.)); |
||||
} |
||||
|
||||
#[test] |
||||
fn from_str() -> Result<(), ParseFloatError> { |
||||
assert_eq!(Float::from(f32::NAN), Float::from_str("NaN")?); |
||||
assert_eq!(Float::from(f32::INFINITY), Float::from_str("INF")?); |
||||
assert_eq!(Float::from(f32::INFINITY), Float::from_str("+INF")?); |
||||
assert_eq!(Float::from(f32::NEG_INFINITY), Float::from_str("-INF")?); |
||||
assert_eq!(Float::from(0.), Float::from_str("0.0E0")?); |
||||
assert_eq!(Float::from(-0.), Float::from_str("-0.0E0")?); |
||||
Ok(()) |
||||
} |
||||
|
||||
#[test] |
||||
fn to_string() { |
||||
assert_eq!("NaN", Float::from(f32::NAN).to_string()); |
||||
assert_eq!("INF", Float::from(f32::INFINITY).to_string()); |
||||
assert_eq!("-INF", Float::from(f32::NEG_INFINITY).to_string()); |
||||
} |
||||
} |
@ -1,9 +1,13 @@ |
||||
pub mod date_time; |
||||
pub mod decimal; |
||||
mod double; |
||||
mod duration; |
||||
mod float; |
||||
mod parser; |
||||
|
||||
pub use self::date_time::{Date, DateTime, GDay, GMonth, GMonthDay, GYear, GYearMonth, Time}; |
||||
pub use self::decimal::Decimal; |
||||
pub use self::double::Double; |
||||
pub use self::duration::{DayTimeDuration, Duration, YearMonthDuration}; |
||||
pub use self::float::Float; |
||||
pub use self::parser::XsdParseError; |
||||
|
Loading…
Reference in new issue