extern crate num_traits;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;
#[cfg(test)]
extern crate serde_json;
#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
mod float_impl;
pub mod checkers;
pub mod types;
pub mod prelude {
pub use types::*;
#[doc(no_inline)]
pub use num_traits::Float;
}
use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;
pub trait FloatChecker<F> {
fn check(value: F) -> bool;
fn assert(value: F);
}
#[repr(C)]
pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
value: F,
checker: PhantomData<C>
}
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
#[inline]
pub fn new(value: F) -> Self {
C::assert(value);
Self::unchecked_new(value)
}
#[inline]
fn unchecked_new(value: F) -> Self {
NoisyFloat {
value: value,
checker: PhantomData
}
}
#[inline]
pub fn try_new(value: F) -> Option<Self> {
if C::check(value) {
Some(NoisyFloat {
value: value,
checker: PhantomData
})
} else {
None
}
}
#[inline]
pub fn from_f32(value: f32) -> Self {
Self::new(F::from(value).unwrap())
}
#[inline]
pub fn from_f64(value: f64) -> Self {
Self::new(F::from(value).unwrap())
}
#[inline]
pub fn raw(self) -> F {
self.value
}
}
impl<F: Float + Default, C: FloatChecker<F>> Default for NoisyFloat<F, C> {
#[inline]
fn default() -> Self {
Self::new(F::default())
}
}
impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Debug::fmt(&self.value, f)
}
}
impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Display::fmt(&self.value, f)
}
}
impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::LowerExp::fmt(&self.value, f)
}
}
impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::UpperExp::fmt(&self.value, f)
}
}
#[cfg(feature = "serde-1")]
impl<F: Float + Serialize, C: FloatChecker<F>> Serialize for NoisyFloat<F, C> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
self.value.serialize(ser)
}
}
#[cfg(feature = "serde-1")]
impl<'de, F: Float + Deserialize<'de>, C: FloatChecker<F>> Deserialize<'de> for NoisyFloat<F, C> {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
let value = F::deserialize(de)?;
Ok(Self::new(value))
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "serde-1")]
use serde_json;
use prelude::*;
use std::f32;
use std::f64::{self, consts};
use std::mem::{size_of, align_of};
#[test]
fn smoke_test() {
assert_eq!(n64(1.0) + 2.0, 3.0);
assert_ne!(n64(3.0), n64(2.9));
assert!(r64(1.0) < 2.0);
let mut value = n64(18.0);
value %= n64(5.0);
assert_eq!(-value, n64(-3.0));
assert_eq!(r64(1.0).exp(), consts::E);
assert_eq!((N64::try_new(1.0).unwrap() / N64::infinity()), 0.0);
assert_eq!(N64::from_f32(f32::INFINITY), N64::from_f64(f64::INFINITY));
assert_eq!(R64::try_new(f64::NEG_INFINITY), None);
assert_eq!(N64::try_new(f64::NAN), None);
assert_eq!(R64::try_new(f64::NAN), None);
}
#[test]
fn ensure_layout() {
assert_eq!(size_of::<N32>(), size_of::<f32>());
assert_eq!(align_of::<N32>(), align_of::<f32>());
assert_eq!(size_of::<N64>(), size_of::<f64>());
assert_eq!(align_of::<N64>(), align_of::<f64>());
}
#[test]
#[should_panic]
fn n64_nan() {
n64(0.0) / n64(0.0);
}
#[test]
#[should_panic]
fn r64_nan() {
r64(0.0) / r64(0.0);
}
#[test]
#[should_panic]
fn r64_infinity() {
r64(1.0) / r64(0.0);
}
#[cfg(feature = "serde-1")]
#[test]
fn serialize_transparently_as_float() {
let num = R32::new(3.14);
let should_be = "3.14";
let got = serde_json::to_string(&num).unwrap();
assert_eq!(got, should_be);
}
#[cfg(feature = "serde-1")]
#[test]
fn deserialize_transparently_as_float() {
let src = "3.14";
let should_be = R32::new(3.14);
let got: R32 = serde_json::from_str(src).unwrap();
assert_eq!(got, should_be);
}
#[cfg(feature = "serde-1")]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Dummy {
value: N64,
}
#[cfg(feature = "serde-1")]
#[test]
fn deserialize_struct_containing_n64() {
let src = r#"{ "value": 3.14 }"#;
let should_be = Dummy {
value: n64(3.14),
};
let got: Dummy = serde_json::from_str(src).unwrap();
assert_eq!(got, should_be);
}
#[cfg(feature = "serde-1")]
#[test]
fn serialize_struct_containing_n64() {
let src = Dummy {
value: n64(3.14),
};
let should_be = r#"{"value":3.14}"#;
let got = serde_json::to_string(&src).unwrap();
assert_eq!(got, should_be);
}
}