use serde::{Deserialize, Serialize};
use std::fmt;
use super::Error;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct OpenUnitIntervalNumber(f64);
impl OpenUnitIntervalNumber {
#[must_use]
#[inline]
pub fn get(&self) -> f64 {
self.0
}
}
impl TryFrom<f64> for OpenUnitIntervalNumber {
type Error = Error;
#[inline]
fn try_from(v: f64) -> Result<OpenUnitIntervalNumber, Error> {
if !v.is_finite() {
Err(Error::NotFinite(v))
} else if v <= 0.0 || v >= 1.0 {
Err(Error::NotInOpenUnitInterval(v))
} else {
Ok(OpenUnitIntervalNumber(v))
}
}
}
impl fmt::Display for OpenUnitIntervalNumber {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert2::check;
#[test]
fn open_unit_validation() {
let result = OpenUnitIntervalNumber::try_from(f64::INFINITY);
check!(result == Err(Error::NotFinite(f64::INFINITY)));
let result = OpenUnitIntervalNumber::try_from(-f64::INFINITY);
check!(result == Err(Error::NotFinite(-f64::INFINITY)));
let result = OpenUnitIntervalNumber::try_from(f64::NAN);
check!(matches!(result, Err(Error::NotFinite(_))));
let result = OpenUnitIntervalNumber::try_from(0.0);
check!(matches!(result, Err(Error::NotInOpenUnitInterval(_))));
let result = OpenUnitIntervalNumber::try_from(-1.0);
check!(matches!(result, Err(Error::NotInOpenUnitInterval(_))));
let result = OpenUnitIntervalNumber::try_from(1.0_f64.next_down());
check!(result == Ok(OpenUnitIntervalNumber(1.0_f64.next_down())));
}
}