Skip to content

Commit

Permalink
Merge pull request #3 from chalharu/add-time
Browse files Browse the repository at this point in the history
Add time
  • Loading branch information
chalharu committed Oct 25, 2017
2 parents 40981cb + 5459605 commit 47c37da
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![crates.io badge](https://img.shields.io/crates/v/appro-eq.svg)](https://crates.io/crates/appro-eq)
[![Build Status](https://travis-ci.org/chalharu/rust-appro-eq.svg?branch=master)](https://travis-ci.org/chalharu/rust-appro-eq)
[![docs.rs](https://docs.rs/appro-eq/badge.svg)](https://docs.rs/appro_eq)
[![docs.rs](https://docs.rs/appro-eq/badge.svg)](https://docs.rs/appro-eq)
[![Coverage Status](https://coveralls.io/repos/github/chalharu/rust-appro-eq/badge.svg?branch=master)](https://coveralls.io/github/chalharu/rust-appro-eq?branch=master)

Implementing the `ApproEq` traits, Can asserts that the two expressions are approximately equal to each other.
Expand Down
111 changes: 97 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ mod ndarray_impl;
use std::rc::{Rc, Weak};
use std::sync::Arc;
use std::cell::{Cell, RefCell};
use std::time::{Duration, Instant, SystemTime};

use std::error;
use std::fmt;
Expand All @@ -77,16 +78,19 @@ pub enum ApproEqError {
NonNumDifference,
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
DividedByZero,
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
Overflow,
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
ComponentError(
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
Box<error::Error>
),
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl fmt::Display for ApproEqError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ApproEqError::LengthMismatch => write!(f, "length mismatch"),
&ApproEqError::NonNumDifference => write!(f, "non num difference"),
&ApproEqError::DividedByZero => write!(f, "divided by zero"),
}
write!(f, "{}", error::Error::description(self))
}
}

Expand All @@ -97,15 +101,13 @@ impl error::Error for ApproEqError {
&ApproEqError::LengthMismatch => "length mismatch",
&ApproEqError::NonNumDifference => "non num difference",
&ApproEqError::DividedByZero => "divided by zero",
&ApproEqError::Overflow => "overflow",
&ApproEqError::ComponentError(ref err) => err.description()
}
}

fn cause(&self) -> Option<&error::Error> {
match self {
&ApproEqError::LengthMismatch => None,
&ApproEqError::NonNumDifference => None,
&ApproEqError::DividedByZero => None,
}
None
}
}

Expand All @@ -123,12 +125,38 @@ pub trait AbsError<Rhs: ?Sized = Self, Diff = Self> {
fn abs_error(&self, expected: &Rhs) -> ApproEqResult<Diff>;
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
pub trait AbsTolerance<Diff = Self> {
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
fn abs_tolerance() -> Diff;
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
pub trait RelTolerance<Diff = Self> {
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
fn rel_tolerance() -> Diff;
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
pub trait Tolerance<Diff = Self> {
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
fn tolerance() -> Diff;
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl<Diff: Tolerance<Diff>> AbsTolerance<Diff> for Diff {
fn abs_tolerance() -> Diff {
Diff::tolerance()
}
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl<Diff: Tolerance<Diff>> RelTolerance<Diff> for Diff {
fn rel_tolerance() -> Diff {
Diff::tolerance()
}
}

/// Trait for approximately equality comparisons.
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
pub trait AbsApproEqWithTol<Rhs: ?Sized = Self, Diff = Self> {
Expand Down Expand Up @@ -177,10 +205,10 @@ pub trait AbsApproEq<Rhs: ?Sized = Self, Diff = Self> {
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl<Rhs, Diff: PartialOrd + Tolerance<Diff>, T: AbsApproEqWithTol<Rhs, Diff>> AbsApproEq<Rhs, Diff>
impl<Rhs, Diff: PartialOrd + AbsTolerance<Diff>, T: AbsApproEqWithTol<Rhs, Diff>> AbsApproEq<Rhs, Diff>
for T {
fn abs_appro_eq(&self, other: &Rhs) -> bool {
self.abs_appro_eq_with_tol(other, &Diff::tolerance())
self.abs_appro_eq_with_tol(other, &Diff::abs_tolerance())
}
}

Expand Down Expand Up @@ -232,13 +260,14 @@ pub trait RelApproEq<Rhs: ?Sized = Self, Diff = Self> {
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl<Rhs, Diff: PartialOrd + Tolerance<Diff>, T: RelApproEqWithTol<Rhs, Diff>> RelApproEq<Rhs, Diff>
impl<Rhs, Diff: PartialOrd + RelTolerance<Diff>, T: RelApproEqWithTol<Rhs, Diff>> RelApproEq<Rhs, Diff>
for T {
fn rel_appro_eq(&self, other: &Rhs) -> bool {
self.rel_appro_eq_with_tol(other, &Diff::tolerance())
self.rel_appro_eq_with_tol(other, &Diff::rel_tolerance())
}
}

/// tolerance is 1e-6 for f32
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl Tolerance for f32 {
fn tolerance() -> f32 {
Expand All @@ -264,6 +293,7 @@ impl RelError for f32 {
}
}

/// tolerance is 1e-6 for f64
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl Tolerance for f64 {
fn tolerance() -> f64 {
Expand Down Expand Up @@ -328,6 +358,7 @@ impl RelError<f32, f32> for f64 {
macro_rules! itype_impls {
($($T:ty)+) => {
$(
/// tolerance is zero for $T
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.1.0"))]
impl Tolerance for $T {
fn tolerance() -> $T {
Expand Down Expand Up @@ -595,3 +626,55 @@ impl<A: ?Sized, D: PartialOrd, B: RelError<A, D> + ?Sized> RelError<RefCell<A>,
}
}

/// absolute tolerance is 1s for Duration
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl AbsTolerance for Duration {
fn abs_tolerance() -> Duration {
Duration::new(1, 0) // 1s
}
}

/// relative tolerance is 1ms(1/1000) for Duration
#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl RelTolerance for Duration {
fn rel_tolerance() -> Duration {
Duration::new(0, 1000000) // 1ms (1/1000)
}
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl AbsError<Instant, Duration> for Instant {
fn abs_error(&self, expected: &Instant) -> ApproEqResult<Duration> {
Ok(Some(if *self > *expected { *self - *expected } else { *expected - *self }))
}
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl AbsError<SystemTime, Duration> for SystemTime {
fn abs_error(&self, expected: &SystemTime) -> ApproEqResult<Duration> {
match if *self > *expected { self.duration_since(*expected) } else { expected.duration_since(*self) } {
Ok(v) => Ok(Some(v)),
Err(e) => Err(ApproEqError::ComponentError(Box::new(e) as Box<error::Error>)),
}
}
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl AbsError for Duration {
fn abs_error(&self, expected: &Duration) -> ApproEqResult<Duration> {
Ok(Some(if *self > *expected { *self - *expected } else { *expected - *self }))
}
}

#[cfg_attr(feature = "docs", stable(feature = "default", since = "0.2.0"))]
impl RelError for Duration {
fn rel_error(&self, expected: &Duration) -> ApproEqResult<Duration> {
if *expected == Duration::new(0, 0) {
Err(ApproEqError::DividedByZero)
} else if expected.as_secs() > std::u32::MAX as u64 {
Err(ApproEqError::DividedByZero)
} else {
Ok(Some((if *self > *expected { *self - *expected } else { *expected - *self }) / expected.as_secs() as u32))
}
}
}
53 changes: 53 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use ndarray::{ArrayD, IxDyn, arr1, arr2, arr3};
use std::rc::Rc;
use std::sync::Arc;
use std::cell::{Cell, RefCell};
use std::time::{Duration, Instant, SystemTime};

macro_rules! panic_test_rel {
($name:ident, $($arg:tt)*) => (
Expand Down Expand Up @@ -485,3 +486,55 @@ panic_test_all!(
arr3(&[[[1f32, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.001]]]),
arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0]]])
);

ok_test_none!(
compare_with_systemtime_none,
SystemTime::now(),
SystemTime::now()
);

ok_test_abs!(
compare_with_systemtime_abs,
SystemTime::now(),
SystemTime::now()
);

panic_test_none!(
bad_compare_with_systemtime_none,
SystemTime::now() - Duration::new(10, 0),
SystemTime::now()
);

panic_test_abs!(
bad_compare_with_systemtime_abs,
SystemTime::now() - Duration::new(10, 0),
SystemTime::now()
);

ok_test_abs!(compare_with_instant_abs, Instant::now(), Instant::now());

ok_test_none!(compare_with_instant_none, Instant::now(), Instant::now());

panic_test_abs!(
bad_compare_with_instant_abs,
Instant::now() - Duration::new(10, 0),
Instant::now()
);

panic_test_none!(
bad_compare_with_instant_none,
Instant::now() - Duration::new(10, 0),
Instant::now()
);

ok_test_all!(
compare_with_duration,
Duration::new(10, 0),
Duration::new(10, 1)
);

panic_test_all!(
bad_compare_with_duration,
Duration::new(9, 0),
Duration::new(10, 1)
);

0 comments on commit 47c37da

Please sign in to comment.