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
//!
//! `num-order` implements numerically consistent [Eq][core::cmp::Eq], [Ord][core::cmp::Ord] and
//! [Hash][core::hash::Hash] for various `num` types.
//!
//! ```rust
//! use std::cmp::Ordering;
//! use std::hash::Hasher;
//! use std::collections::hash_map::DefaultHasher;
//! use num_order::{NumOrd, NumHash};
//!
//! assert!(NumOrd::num_eq(&3u64, &3.0f32));
//! assert!(NumOrd::num_lt(&-4.7f64, &-4i8));
//! assert!(!NumOrd::num_ge(&-3i8, &1u16));
//!
//! // 40_000_000 can be exactly represented in f32, 40_000_001 cannot
//! // 40_000_001 becames 40_000_000.0 in f32
//! assert_eq!(NumOrd::num_cmp(&40_000_000f32, &40_000_000u32), Ordering::Equal);
//! assert_ne!(NumOrd::num_cmp(&40_000_001f32, &40_000_001u32), Ordering::Equal);
//! assert_eq!(NumOrd::num_partial_cmp(&f32::NAN, &40_000_002u32), None);
//!
//! // same hash values are guaranteed for equal numbers
//! let mut hasher1 = DefaultHasher::new();
//! 3u64.num_hash(&mut hasher1);
//! let mut hasher2 = DefaultHasher::new();
//! 3.0f32.num_hash(&mut hasher2);
//! assert_eq!(hasher1.finish(), hasher2.finish())
//! ```
//!
//! This crate can serve applications where [float-ord](https://crates.io/crates/float-ord),
//! [num-cmp](https://crates.io/crates/num-cmp), [numcmp](https://crates.io/crates/numcmp) are used.
//! Meanwhile it also supports hashing and more numeric types.
//!
#![no_std]
#[cfg(any(feature = "std", test))]
extern crate std;
#[cfg(all(not(feature = "std"), feature = "libm"))]
extern crate libm;
use core::cmp::Ordering;
use core::hash::Hasher;
/// Consistent comparison among different numeric types.
pub trait NumOrd<Other> {
/// [PartialOrd::partial_cmp] on different numeric types
fn num_partial_cmp(&self, other: &Other) -> Option<Ordering>;
#[inline]
/// [PartialEq::eq] on different numeric types
fn num_eq(&self, other: &Other) -> bool {
matches!(self.num_partial_cmp(other), Some(Ordering::Equal))
}
#[inline]
/// [PartialEq::ne] on different numeric types
fn num_ne(&self, other: &Other) -> bool {
!self.num_eq(other)
}
#[inline]
/// [PartialOrd::lt] on different numeric types
fn num_lt(&self, other: &Other) -> bool {
matches!(self.num_partial_cmp(other), Some(Ordering::Less))
}
#[inline]
/// [PartialOrd::le] on different numeric types
fn num_le(&self, other: &Other) -> bool {
matches!(self.num_partial_cmp(other), Some(Ordering::Equal) | Some(Ordering::Less))
}
#[inline]
/// [PartialOrd::gt] on different numeric types
fn num_gt(&self, other: &Other) -> bool {
matches!(self.num_partial_cmp(other), Some(Ordering::Greater))
}
#[inline]
/// [PartialOrd::ge] on different numeric types
fn num_ge(&self, other: &Other) -> bool {
matches!(self.num_partial_cmp(other), Some(Ordering::Equal) | Some(Ordering::Greater))
}
#[inline]
/// [Ord::cmp] on different numeric types. It panics if either of the numeric values contains NaN.
fn num_cmp(&self, other: &Other) -> Ordering {
self.num_partial_cmp(other).unwrap()
}
}
/// Consistent hash implementation among different numeric types.
pub trait NumHash {
/// Consistent [Hash::hash][core::hash::Hash::hash] on different numeric types.
///
/// This function will ensures if `a.num_eq(b)`, then `a.num_hash()` and `b.num_hash()` manipulate the state in the same way.
fn num_hash<H: Hasher>(&self, state: &mut H);
}
mod ord;
mod hash;
#[cfg(test)] mod tests;