1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

//! Wrappers for total order on Floats.

extern crate num;

use num::Float;
use std::cmp::Ordering;

/// A wrapper around Floats providing an implementation of Ord.
///
/// NaN is sorted as *greater* than all other values and *equal*
/// to itself, in contradiction with the IEEE standard.
#[derive(PartialOrd, Debug, Clone, Hash, Copy)]
pub struct OrderedFloat<T: Float + Copy>(pub T);

impl<T: Float + Copy> AsRef<T> for OrderedFloat<T> {
    /// Get the value out.
    fn as_ref(&self) -> &T {
        let OrderedFloat(ref val) = *self;
        val
    }
}

impl<T: Float + Copy + PartialOrd> Ord for OrderedFloat<T> {
    fn cmp(&self, other: &OrderedFloat<T>) -> Ordering {
        match self.as_ref().partial_cmp(&other.as_ref()) {
            Some(ordering) => ordering,
            None => {
                if self.as_ref().is_nan() {
                    if other.as_ref().is_nan() {
                        Ordering::Equal
                    } else {
                        Ordering::Greater
                    }
                } else {
                    Ordering::Less
                }
            }
        }
    }
}

impl<T: Float + Copy + PartialEq> PartialEq for OrderedFloat<T> {
    fn eq(&self, other: &OrderedFloat<T>) -> bool {
        if self.as_ref().is_nan() {
            if other.as_ref().is_nan() {
                true
            } else {
                false
            }
        } else if other.as_ref().is_nan() {
            false
        } else {
            self.as_ref() == other.as_ref()
        }

    }
}

impl<T: Float + Copy + PartialEq> Eq for OrderedFloat<T> { }

/// A wrapper around Floats providing an implementation of Ord.
///
/// If NaN is encountered because NotNaN was manually constructed
/// with a NaN value, this will panic.
#[derive(PartialOrd, Debug, Clone, Hash, Copy)]
pub struct NotNaN<T: Float + Copy>(pub T);

impl<T: Float + Copy> NotNaN<T> {
    /// Create a NotNaN value.
    ///
    /// ## Panics
    ///
    /// Panics if the val is NaN
    pub fn new(val: T) -> NotNaN<T> {
        if val.is_nan() { panic!("NaN encountered in NotNaN construction.") }
        NotNaN(val)
    }

    /// Get the value out.
    pub fn as_ref(self) -> T {
        let NotNaN(val) = self;
        val
    }
}

impl<T: Float + Copy + PartialOrd> Ord for NotNaN<T> {
    fn cmp(&self, other: &NotNaN<T>) -> Ordering {
        self.as_ref()
            .partial_cmp(&other.as_ref())
            .expect("NaN encountered in NotNaN comparison.")
    }
}

impl<T: Float + Copy + PartialEq> PartialEq for NotNaN<T> {
    fn eq(&self, other: &NotNaN<T>) -> bool {
        if self.as_ref().is_nan() || other.as_ref().is_nan() {
            panic!("NaN encountered in NotNaN comparison.")
        } else {
            self.as_ref() == other.as_ref()
        }
    }
}

impl<T: Float + Copy + PartialEq> Eq for NotNaN<T> {}