strict-num-0.1.1/.cargo_vcs_info.json0000644000000001360000000000100131400ustar { "git": { "sha1": "edf5020c215063c3a9eb8fcac463c82eaceba6df" }, "path_in_vcs": "" }strict-num-0.1.1/.github/workflows/main.yml000064400000000000000000000010441046102023000167730ustar 00000000000000name: Build on: [push, pull_request] env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-20.04 strategy: matrix: rust: - stable - 1.35.0 steps: - name: Checkout uses: actions/checkout@v2 - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true - name: Build without approx-eq run: cargo build - name: Run tests run: cargo test --features approx-eq strict-num-0.1.1/.gitignore000064400000000000000000000000501046102023000137130ustar 00000000000000/target Cargo.lock .directory .DS_Store strict-num-0.1.1/CHANGELOG.md000064400000000000000000000012461046102023000135440ustar 00000000000000# Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## [0.1.1] ### Added - `PartialEq<{float}>` for all types. Meaning one can write: ```rust let n = FiniteF32::new(1.0).unwrap(); assert_eq!(n, 1.0); // instead of assert_eq!(n.get(), 1.0); ``` - Reexport `float_cmp::Ulps` ## 0.1.0 - 2022-07-23 ### Added - Initial version [Unreleased]: https://github.com/RazrFalcon/strict-num/compare/v0.1.1...HEAD [0.1.1]: https://github.com/RazrFalcon/strict-num/compare/v0.1.0...v0.1.1 strict-num-0.1.1/Cargo.toml0000644000000017410000000000100111410ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "strict-num" version = "0.1.1" authors = ["Yevhenii Reizner "] description = "A collection of bounded numeric types" documentation = "https://docs.rs/strict-num/" readme = "README.md" categories = [ "mathematics", "no-std", ] license = "MIT" repository = "https://github.com/RazrFalcon/strict-num" [dependencies.float-cmp] version = "0.9" features = ["std"] optional = true default-features = false [features] approx-eq = ["float-cmp"] default = ["approx-eq"] strict-num-0.1.1/Cargo.toml.orig000064400000000000000000000012141046102023000146150ustar 00000000000000[package] name = "strict-num" version = "0.1.1" authors = ["Yevhenii Reizner "] license = "MIT" description = "A collection of bounded numeric types" repository = "https://github.com/RazrFalcon/strict-num" documentation = "https://docs.rs/strict-num/" categories = ["mathematics", "no-std"] readme = "README.md" edition = "2018" [dependencies] float-cmp = { version = "0.9", default-features = false, features = ["std"], optional = true } [features] default = ["approx-eq"] # Implements `ApproxEq` and `ApproxEqUlps` traits for floating point numbers # via the `float-cmp` crate. # Disables `no_std`. approx-eq = ["float-cmp"] strict-num-0.1.1/LICENSE000064400000000000000000000020441046102023000127350ustar 00000000000000Copyright (c) 2022 Yevhenii Reizner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. strict-num-0.1.1/README.md000064400000000000000000000013131046102023000132050ustar 00000000000000# strict-num ![Build Status](https://github.com/RazrFalcon/strict-num/workflows/Build/badge.svg) [![Crates.io](https://img.shields.io/crates/v/strict-num.svg)](https://crates.io/crates/strict-num) [![Documentation](https://docs.rs/strict-num/badge.svg)](https://docs.rs/strict-num) [![Rust 1.35+](https://img.shields.io/badge/rust-1.35+-orange.svg)](https://www.rust-lang.org) A collection of bounded numeric types. Includes: - `FiniteF32` - `FiniteF64` - `NonZeroPositiveF32` - `NonZeroPositiveF64` - `PositiveF32` - `PositiveF64` - `NormalizedF32` - `NormalizedF64` Unlike `f32`/`f64`, all float types implement `Ord`, `PartialOrd` and `Hash`, since it's guaranteed that they all are finite. ## License MIT strict-num-0.1.1/src/lib.rs000064400000000000000000000500561046102023000136410ustar 00000000000000/*! A collection of bounded numeric types. Includes: - [`FiniteF32`] - [`FiniteF64`] - [`NonZeroPositiveF32`] - [`NonZeroPositiveF64`] - [`PositiveF32`] - [`PositiveF64`] - [`NormalizedF32`] - [`NormalizedF64`] Unlike `f32`/`f64`, all float types implement `Ord`, `PartialOrd` and `Hash`, since it's guaranteed that they all are finite. */ #![no_std] #![deny(missing_docs)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] macro_rules! impl_display { ($t:ident) => { impl core::fmt::Display for $t { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", self.get()) } } }; } #[cfg(feature = "approx-eq")] pub use float_cmp::{ApproxEq, ApproxEqUlps, Ulps}; #[cfg(feature = "approx-eq")] macro_rules! impl_approx_32 { ($t:ident) => { impl float_cmp::ApproxEq for $t { type Margin = float_cmp::F32Margin; #[inline] fn approx_eq>(self, other: Self, margin: M) -> bool { self.0.approx_eq(other.0, margin) } } impl float_cmp::ApproxEqUlps for $t { type Flt = f32; #[inline] fn approx_eq_ulps(&self, other: &Self, ulps: i32) -> bool { self.0.approx_eq_ulps(&other.0, ulps) } } }; } #[cfg(not(feature = "approx-eq"))] macro_rules! impl_approx_32 { ($t:ident) => {}; } #[cfg(feature = "approx-eq")] macro_rules! impl_approx_64 { ($t:ident) => { #[cfg(feature = "approx-eq")] impl float_cmp::ApproxEq for $t { type Margin = float_cmp::F64Margin; #[inline] fn approx_eq>(self, other: Self, margin: M) -> bool { self.0.approx_eq(other.0, margin) } } #[cfg(feature = "approx-eq")] impl float_cmp::ApproxEqUlps for $t { type Flt = f64; #[inline] fn approx_eq_ulps(&self, other: &Self, ulps: i64) -> bool { self.0.approx_eq_ulps(&other.0, ulps) } } }; } #[cfg(not(feature = "approx-eq"))] macro_rules! impl_approx_64 { ($t:ident) => {}; } /// An immutable, finite `f32`. /// /// Unlike `f32`, implements `Ord`, `PartialOrd` and `Hash`. #[derive(Copy, Clone, Default, Debug)] #[repr(transparent)] pub struct FiniteF32(f32); impl FiniteF32 { /// Creates a finite `f32`. /// /// Returns `None` for NaN and infinity. #[inline] pub fn new(n: f32) -> Option { if n.is_finite() { Some(FiniteF32(n)) } else { None } } /// Creates a finite `f32` without checking the value. /// /// # Safety /// /// `n` must be finite. #[inline] pub const unsafe fn new_unchecked(n: f32) -> Self { FiniteF32(n) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f32 { self.0 } } impl Eq for FiniteF32 {} impl PartialEq for FiniteF32 { #[inline] fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl Ord for FiniteF32 { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { if self.0 < other.0 { core::cmp::Ordering::Less } else if self.0 > other.0 { core::cmp::Ordering::Greater } else { core::cmp::Ordering::Equal } } } impl PartialOrd for FiniteF32 { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl core::hash::Hash for FiniteF32 { #[inline] fn hash(&self, state: &mut H) { self.0.to_bits().hash(state); } } impl PartialEq for FiniteF32 { #[inline] fn eq(&self, other: &f32) -> bool { self.get() == *other } } impl_display!(FiniteF32); impl_approx_32!(FiniteF32); /// An immutable, finite `f64`. /// /// Unlike `f64`, implements `Ord`, `PartialOrd` and `Hash`. #[derive(Copy, Clone, Default, Debug)] #[repr(transparent)] pub struct FiniteF64(f64); impl FiniteF64 { /// Creates a finite `f64`. /// /// Returns `None` for NaN and infinity. #[inline] pub fn new(n: f64) -> Option { if n.is_finite() { Some(FiniteF64(n)) } else { None } } /// Creates a finite `f64` without checking the value. /// /// # Safety /// /// `n` must be finite. #[inline] pub const unsafe fn new_unchecked(n: f64) -> Self { FiniteF64(n) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f64 { self.0 } } impl Eq for FiniteF64 {} impl PartialEq for FiniteF64 { #[inline] fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl Ord for FiniteF64 { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { if self.0 < other.0 { core::cmp::Ordering::Less } else if self.0 > other.0 { core::cmp::Ordering::Greater } else { core::cmp::Ordering::Equal } } } impl PartialOrd for FiniteF64 { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl core::hash::Hash for FiniteF64 { #[inline] fn hash(&self, state: &mut H) { self.0.to_bits().hash(state); } } impl PartialEq for FiniteF64 { #[inline] fn eq(&self, other: &f64) -> bool { self.get() == *other } } impl_display!(FiniteF64); impl_approx_64!(FiniteF64); /// An immutable, finite `f32` that is known to be >= 0. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default, Debug)] #[repr(transparent)] pub struct PositiveF32(FiniteF32); impl PositiveF32 { /// A `PositiveF32` value initialized with zero. pub const ZERO: Self = PositiveF32(FiniteF32(0.0)); /// Creates a new `PositiveF32` if the given value is >= 0. /// /// Returns `None` for negative, NaN and infinity. #[inline] pub fn new(n: f32) -> Option { if n.is_finite() && n >= 0.0 { Some(PositiveF32(FiniteF32(n))) } else { None } } /// Creates a new `PositiveF32` without checking the value. /// /// # Safety /// /// `n` must be finite and >= 0. #[inline] pub const unsafe fn new_unchecked(n: f32) -> Self { PositiveF32(FiniteF32(n)) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f32 { self.0.get() } /// Returns the value as a `FiniteF32`. #[inline] pub const fn get_finite(&self) -> FiniteF32 { self.0 } } impl PartialEq for PositiveF32 { #[inline] fn eq(&self, other: &f32) -> bool { self.get() == *other } } impl_display!(PositiveF32); impl_approx_32!(PositiveF32); /// An immutable, finite `f64` that is known to be >= 0. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default, Debug)] #[repr(transparent)] pub struct PositiveF64(FiniteF64); impl PositiveF64 { /// A `PositiveF64` value initialized with zero. pub const ZERO: Self = PositiveF64(FiniteF64(0.0)); /// Creates a new `PositiveF64` if the given value is >= 0. /// /// Returns `None` for negative, NaN and infinity. #[inline] pub fn new(n: f64) -> Option { if n.is_finite() && n >= 0.0 { Some(PositiveF64(FiniteF64(n))) } else { None } } /// Creates a new `PositiveF64` without checking the value. /// /// # Safety /// /// `n` must be finite and >= 0. #[inline] pub const unsafe fn new_unchecked(n: f64) -> Self { PositiveF64(FiniteF64(n)) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f64 { self.0.get() } /// Returns the value as a `FiniteF64`. #[inline] pub const fn get_finite(&self) -> FiniteF64 { self.0 } } impl PartialEq for PositiveF64 { #[inline] fn eq(&self, other: &f64) -> bool { self.get() == *other } } impl_display!(PositiveF64); impl_approx_64!(PositiveF64); /// An immutable, finite `f32` that is known to be > 0. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[repr(transparent)] pub struct NonZeroPositiveF32(FiniteF32); impl NonZeroPositiveF32 { /// Creates a new `NonZeroPositiveF32` if the given value is > 0. /// /// Returns `None` for negative, zero, NaN and infinity. #[inline] pub fn new(n: f32) -> Option { if n.is_finite() && n > 0.0 { Some(NonZeroPositiveF32(FiniteF32(n))) } else { None } } /// Creates a new `NonZeroPositiveF32` without checking the value. /// /// # Safety /// /// `n` must be finite and > 0. #[inline] pub const unsafe fn new_unchecked(n: f32) -> Self { NonZeroPositiveF32(FiniteF32(n)) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f32 { self.0.get() } /// Returns the value as a `FiniteF32`. #[inline] pub const fn get_finite(&self) -> FiniteF32 { self.0 } } impl PartialEq for NonZeroPositiveF32 { #[inline] fn eq(&self, other: &f32) -> bool { self.get() == *other } } impl_display!(NonZeroPositiveF32); impl_approx_32!(NonZeroPositiveF32); /// An immutable, finite `f64` that is known to be > 0. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[repr(transparent)] pub struct NonZeroPositiveF64(FiniteF64); impl NonZeroPositiveF64 { /// Creates a new `NonZeroPositiveF64` if the given value is > 0. /// /// Returns `None` for negative, zero, NaN and infinity. #[inline] pub fn new(n: f64) -> Option { if n.is_finite() && n > 0.0 { Some(NonZeroPositiveF64(FiniteF64(n))) } else { None } } /// Creates a new `NonZeroPositiveF64` without checking the value. /// /// # Safety /// /// `n` must be finite and > 0. #[inline] pub const unsafe fn new_unchecked(n: f64) -> Self { NonZeroPositiveF64(FiniteF64(n)) } /// Returns the value as a primitive type. #[inline] pub const fn get(&self) -> f64 { self.0.get() } /// Returns the value as a `FiniteF64`. #[inline] pub const fn get_finite(&self) -> FiniteF64 { self.0 } } impl PartialEq for NonZeroPositiveF64 { #[inline] fn eq(&self, other: &f64) -> bool { self.get() == *other } } impl_display!(NonZeroPositiveF64); impl_approx_64!(NonZeroPositiveF64); /// An immutable, finite `f32` in a 0..=1 range. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[repr(transparent)] pub struct NormalizedF32(FiniteF32); impl NormalizedF32 { /// A `NormalizedF32` value initialized with zero. pub const ZERO: Self = NormalizedF32(FiniteF32(0.0)); /// A `NormalizedF32` value initialized with one. pub const ONE: Self = NormalizedF32(FiniteF32(1.0)); /// Creates a `NormalizedF32` if the given value is in a 0..=1 range. #[inline] pub fn new(n: f32) -> Option { if n.is_finite() && n >= 0.0 && n <= 1.0 { Some(NormalizedF32(FiniteF32(n))) } else { None } } /// Creates a new `NormalizedF32` without checking the value. /// /// # Safety /// /// `n` must be in 0..=1 range. #[inline] pub const unsafe fn new_unchecked(n: f32) -> Self { NormalizedF32(FiniteF32(n)) } /// Creates a `NormalizedF32` clamping the given value to a 0..=1 range. /// /// Returns zero in case of NaN or infinity. #[inline] pub fn new_clamped(n: f32) -> Self { if n.is_finite() { NormalizedF32(FiniteF32(clamp_f32(0.0, n, 1.0))) } else { Self::ZERO } } /// Creates a `NormalizedF32` by dividing the given value by 255. #[inline] pub fn new_u8(n: u8) -> Self { NormalizedF32(FiniteF32(f32::from(n) / 255.0)) } /// Creates a `NormalizedF64` by dividing the given value by 65535. #[inline] pub fn new_u16(n: u16) -> Self { NormalizedF32(FiniteF32(f32::from(n) / 65535.0)) } /// Returns the value as a primitive type. #[inline] pub const fn get(self) -> f32 { self.0.get() } /// Returns the value as a `FiniteF32`. #[inline] pub const fn get_finite(&self) -> FiniteF32 { self.0 } /// Returns the value as a `u8`. #[inline] pub fn to_u8(&self) -> u8 { ((self.0).0 * 255.0 + 0.5) as u8 } /// Returns the value as a `u16`. #[inline] pub fn to_u16(&self) -> u16 { ((self.0).0 * 65535.0 + 0.5) as u16 } } impl core::ops::Mul for NormalizedF32 { type Output = Self; #[inline] fn mul(self, rhs: Self) -> Self::Output { Self::new_clamped((self.0).0 * (rhs.0).0) } } impl PartialEq for NormalizedF32 { #[inline] fn eq(&self, other: &f32) -> bool { self.get() == *other } } impl_display!(NormalizedF32); impl_approx_32!(NormalizedF32); /// An immutable, finite `f64` in a 0..=1 range. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[repr(transparent)] pub struct NormalizedF64(FiniteF64); impl NormalizedF64 { /// A `NormalizedF64` value initialized with zero. pub const ZERO: Self = NormalizedF64(FiniteF64(0.0)); /// A `NormalizedF64` value initialized with one. pub const ONE: Self = NormalizedF64(FiniteF64(1.0)); /// Creates a `NormalizedF64` if the given value is in a 0..=1 range. #[inline] pub fn new(n: f64) -> Option { if n >= 0.0 && n <= 1.0 { Some(NormalizedF64(FiniteF64(n))) } else { None } } /// Creates a new `NormalizedF64` without checking the value. /// /// # Safety /// /// `n` must be in 0..=1 range. #[inline] pub const unsafe fn new_unchecked(n: f64) -> Self { NormalizedF64(FiniteF64(n)) } /// Creates a `NormalizedF64` clamping the given value to a 0..=1 range. /// /// Returns zero in case of NaN or infinity. #[inline] pub fn new_clamped(n: f64) -> Self { if n.is_finite() { NormalizedF64(FiniteF64(clamp_f64(0.0, n, 1.0))) } else { Self::ZERO } } /// Creates a `NormalizedF64` by dividing the given value by 255. #[inline] pub fn new_u8(n: u8) -> Self { NormalizedF64(FiniteF64(f64::from(n) / 255.0)) } /// Creates a `NormalizedF64` by dividing the given value by 65535. #[inline] pub fn new_u16(n: u16) -> Self { NormalizedF64(FiniteF64(f64::from(n) / 65535.0)) } /// Returns the value as a primitive type. #[inline] pub const fn get(self) -> f64 { self.0.get() } /// Returns the value as a `FiniteF64`. #[inline] pub const fn get_finite(&self) -> FiniteF64 { self.0 } /// Returns the value as a `u8`. #[inline] pub fn to_u8(&self) -> u8 { ((self.0).0 * 255.0 + 0.5) as u8 } /// Returns the value as a `u16`. #[inline] pub fn to_u16(&self) -> u16 { ((self.0).0 * 65535.0 + 0.5) as u16 } } impl core::ops::Mul for NormalizedF64 { type Output = Self; #[inline] fn mul(self, rhs: Self) -> Self::Output { Self::new_clamped((self.0).0 * (rhs.0).0) } } impl PartialEq for NormalizedF64 { #[inline] fn eq(&self, other: &f64) -> bool { self.get() == *other } } impl_display!(NormalizedF64); impl_approx_64!(NormalizedF64); #[inline] fn clamp_f32(min: f32, val: f32, max: f32) -> f32 { max.min(val).max(min) } #[inline] fn clamp_f64(min: f64, val: f64, max: f64) -> f64 { max.min(val).max(min) } #[cfg(test)] mod tests { use super::*; #[test] fn finite_f32() { assert_eq!(FiniteF32::new(0.0).map(|n| n.get()), Some(0.0)); assert_eq!(FiniteF32::new(core::f32::NAN), None); assert_eq!(FiniteF32::new(core::f32::INFINITY), None); assert_eq!(FiniteF32::new(core::f32::NEG_INFINITY), None); } #[test] fn positive_f32() { assert_eq!(NonZeroPositiveF32::new(-1.0).map(|n| n.get()), None); assert_eq!(NonZeroPositiveF32::new(0.0).map(|n| n.get()), None); assert_eq!(NonZeroPositiveF32::new(1.0).map(|n| n.get()), Some(1.0)); assert_eq!( NonZeroPositiveF32::new(core::f32::EPSILON).map(|n| n.get()), Some(core::f32::EPSILON) ); assert_eq!( NonZeroPositiveF32::new(-core::f32::EPSILON).map(|n| n.get()), None ); assert_eq!(NonZeroPositiveF32::new(core::f32::NAN), None); assert_eq!(NonZeroPositiveF32::new(core::f32::INFINITY), None); assert_eq!(NonZeroPositiveF32::new(core::f32::NEG_INFINITY), None); } #[test] fn positive_f64() { assert_eq!(NonZeroPositiveF32::new(-1.0).map(|n| n.get()), None); assert_eq!(NonZeroPositiveF64::new(0.0).map(|n| n.get()), None); assert_eq!(NonZeroPositiveF64::new(1.0).map(|n| n.get()), Some(1.0)); assert_eq!( NonZeroPositiveF64::new(core::f64::EPSILON).map(|n| n.get()), Some(core::f64::EPSILON) ); assert_eq!( NonZeroPositiveF64::new(-core::f64::EPSILON).map(|n| n.get()), None ); assert_eq!(NonZeroPositiveF64::new(core::f64::NAN), None); assert_eq!(NonZeroPositiveF64::new(core::f64::INFINITY), None); assert_eq!(NonZeroPositiveF64::new(core::f64::NEG_INFINITY), None); } #[test] fn norm_f32() { assert_eq!(NormalizedF32::new(-0.5), None); assert_eq!( NormalizedF32::new(-core::f32::EPSILON).map(|n| n.get()), None ); assert_eq!(NormalizedF32::new(0.0).map(|n| n.get()), Some(0.0)); assert_eq!(NormalizedF32::new(0.5).map(|n| n.get()), Some(0.5)); assert_eq!(NormalizedF32::new(1.0).map(|n| n.get()), Some(1.0)); assert_eq!(NormalizedF32::new(1.5), None); assert_eq!(NormalizedF32::new(core::f32::NAN), None); assert_eq!(NormalizedF32::new(core::f32::INFINITY), None); assert_eq!(NormalizedF32::new(core::f32::NEG_INFINITY), None); } #[test] fn clamped_norm_f32() { assert_eq!(NormalizedF32::new_clamped(-0.5).get(), 0.0); assert_eq!(NormalizedF32::new_clamped(0.5).get(), 0.5); assert_eq!(NormalizedF32::new_clamped(1.5).get(), 1.0); assert_eq!(NormalizedF32::new_clamped(core::f32::NAN).get(), 0.0); assert_eq!(NormalizedF32::new_clamped(core::f32::INFINITY).get(), 0.0); assert_eq!( NormalizedF32::new_clamped(core::f32::NEG_INFINITY).get(), 0.0 ); } #[test] fn norm_f64() { assert_eq!(NormalizedF64::new(-0.5), None); assert_eq!( NormalizedF64::new(-core::f64::EPSILON).map(|n| n.get()), None ); assert_eq!(NormalizedF64::new(0.0).map(|n| n.get()), Some(0.0)); assert_eq!(NormalizedF64::new(0.5).map(|n| n.get()), Some(0.5)); assert_eq!(NormalizedF64::new(1.0).map(|n| n.get()), Some(1.0)); assert_eq!(NormalizedF64::new(1.5), None); assert_eq!(NormalizedF64::new(core::f64::NAN), None); assert_eq!(NormalizedF64::new(core::f64::INFINITY), None); assert_eq!(NormalizedF64::new(core::f64::NEG_INFINITY), None); } #[test] fn clamped_norm_f64() { assert_eq!(NormalizedF64::new_clamped(-0.5).get(), 0.0); assert_eq!(NormalizedF64::new_clamped(0.5).get(), 0.5); assert_eq!(NormalizedF64::new_clamped(1.5).get(), 1.0); assert_eq!(NormalizedF64::new_clamped(core::f64::NAN).get(), 0.0); assert_eq!(NormalizedF64::new_clamped(core::f64::INFINITY).get(), 0.0); assert_eq!( NormalizedF64::new_clamped(core::f64::NEG_INFINITY).get(), 0.0 ); } }