Skip to content

Commit 696f5ef

Browse files
lemmihmbrubeck
authored andcommitted
Implement traits from the 'rand' crate.
1 parent 2b176d3 commit 696f5ef

File tree

2 files changed

+167
-12
lines changed

2 files changed

+167
-12
lines changed

Cargo.toml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
[package]
2-
name = "ordered-float"
3-
version = "2.4.0"
4-
authors = ["Jonathan Reem <jonathan.reem@gmail.com>", "Matt Brubeck <mbrubeck@limpet.net>"]
5-
license = "MIT"
2+
name = "ordered-float"
3+
version = "2.4.0"
4+
authors = [
5+
"Jonathan Reem <jonathan.reem@gmail.com>",
6+
"Matt Brubeck <mbrubeck@limpet.net>",
7+
]
8+
license = "MIT"
69
description = "Wrappers for total ordering on floats"
7-
repository = "https://github.com/reem/rust-ordered-float"
8-
readme = "README.md"
9-
keywords = ["no_std", "ord", "f64", "f32", "sort"]
10-
categories = ["science", "rust-patterns", "no-std"]
11-
edition = "2018"
10+
repository = "https://github.com/reem/rust-ordered-float"
11+
readme = "README.md"
12+
keywords = ["no_std", "ord", "f64", "f32", "sort"]
13+
categories = ["science", "rust-patterns", "no-std"]
14+
edition = "2018"
1215

1316
[dependencies]
1417
num-traits = { version = "0.2.1", default-features = false }
15-
serde = { version = "1.0", optional = true, default-features = false }
16-
schemars = { version = "0.6.5", optional = true }
18+
serde = { version = "1.0", optional = true, default-features = false }
19+
schemars = { version = "0.6.5", optional = true }
20+
rand = { version = "0.8.3", optional = true, default-features = false }
1721

1822
[dev-dependencies]
1923
serde_test = "1.0"
2024

2125
[features]
2226
default = ["std"]
23-
std = ["num-traits/std"]
27+
std = ["num-traits/std", "rand/std", "rand/std_rng"]

src/lib.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,3 +1232,154 @@ mod impl_schemars {
12321232
}
12331233
}
12341234
}
1235+
1236+
#[cfg(all(feature = "std", feature = "rand"))]
1237+
mod impl_rand {
1238+
use super::{NotNan, OrderedFloat};
1239+
use rand::distributions::{Distribution, Open01, OpenClosed01, Standard};
1240+
use rand::distributions::uniform::*;
1241+
use rand::Rng;
1242+
1243+
macro_rules! impl_distribution {
1244+
($dist:ident, $($f:ty),+) => {
1245+
$(
1246+
impl Distribution<NotNan<$f>> for $dist {
1247+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> NotNan<$f> {
1248+
// 'rand' never generates NaN values in the Standard, Open01, or
1249+
// OpenClosed01 distributions. Using 'unchecked_new' is therefore
1250+
// safe.
1251+
unsafe { NotNan::unchecked_new(self.sample(rng)) }
1252+
}
1253+
}
1254+
1255+
impl Distribution<OrderedFloat<$f>> for $dist {
1256+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> OrderedFloat<$f> {
1257+
OrderedFloat(self.sample(rng))
1258+
}
1259+
}
1260+
)*
1261+
}
1262+
}
1263+
1264+
impl_distribution! { Standard, f32, f64 }
1265+
impl_distribution! { Open01, f32, f64 }
1266+
impl_distribution! { OpenClosed01, f32, f64 }
1267+
1268+
pub struct UniformNotNan<T>(UniformFloat<T>);
1269+
impl SampleUniform for NotNan<f32> {
1270+
type Sampler = UniformNotNan<f32>;
1271+
}
1272+
impl SampleUniform for NotNan<f64> {
1273+
type Sampler = UniformNotNan<f64>;
1274+
}
1275+
1276+
pub struct UniformOrdered<T>(UniformFloat<T>);
1277+
impl SampleUniform for OrderedFloat<f32> {
1278+
type Sampler = UniformOrdered<f32>;
1279+
}
1280+
impl SampleUniform for OrderedFloat<f64> {
1281+
type Sampler = UniformOrdered<f64>;
1282+
}
1283+
1284+
macro_rules! impl_uniform_sampler {
1285+
($f:ty) => {
1286+
impl UniformSampler for UniformNotNan<$f> {
1287+
type X = NotNan<$f>;
1288+
fn new<B1, B2>(low: B1, high: B2) -> Self
1289+
where B1: SampleBorrow<Self::X> + Sized,
1290+
B2: SampleBorrow<Self::X> + Sized
1291+
{
1292+
UniformNotNan(UniformFloat::<$f>::new(low.borrow().0, high.borrow().0))
1293+
}
1294+
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
1295+
where B1: SampleBorrow<Self::X> + Sized,
1296+
B2: SampleBorrow<Self::X> + Sized
1297+
{
1298+
UniformSampler::new(low, high)
1299+
}
1300+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
1301+
unsafe { NotNan::unchecked_new(self.0.sample(rng)) }
1302+
}
1303+
}
1304+
1305+
impl UniformSampler for UniformOrdered<$f> {
1306+
type X = OrderedFloat<$f>;
1307+
fn new<B1, B2>(low: B1, high: B2) -> Self
1308+
where B1: SampleBorrow<Self::X> + Sized,
1309+
B2: SampleBorrow<Self::X> + Sized
1310+
{
1311+
UniformOrdered(UniformFloat::<$f>::new(low.borrow().0, high.borrow().0))
1312+
}
1313+
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
1314+
where B1: SampleBorrow<Self::X> + Sized,
1315+
B2: SampleBorrow<Self::X> + Sized
1316+
{
1317+
UniformSampler::new(low, high)
1318+
}
1319+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
1320+
OrderedFloat(self.0.sample(rng))
1321+
}
1322+
}
1323+
}
1324+
}
1325+
1326+
impl_uniform_sampler!{ f32 }
1327+
impl_uniform_sampler!{ f64 }
1328+
1329+
#[cfg(test)]
1330+
fn sample_fuzz<T>()
1331+
where
1332+
Standard: Distribution<NotNan<T>>,
1333+
Open01: Distribution<NotNan<T>>,
1334+
OpenClosed01: Distribution<NotNan<T>>,
1335+
Standard: Distribution<OrderedFloat<T>>,
1336+
Open01: Distribution<OrderedFloat<T>>,
1337+
OpenClosed01: Distribution<OrderedFloat<T>>,
1338+
T: super::Float,
1339+
{
1340+
let mut rng = rand::thread_rng();
1341+
let f1: NotNan<T> = rng.sample(Standard);
1342+
let f2: NotNan<T> = rng.sample(Open01);
1343+
let f3: NotNan<T> = rng.sample(OpenClosed01);
1344+
let _: OrderedFloat<T> = rng.sample(Standard);
1345+
let _: OrderedFloat<T> = rng.sample(Open01);
1346+
let _: OrderedFloat<T> = rng.sample(OpenClosed01);
1347+
assert!(!f1.into_inner().is_nan());
1348+
assert!(!f2.into_inner().is_nan());
1349+
assert!(!f3.into_inner().is_nan());
1350+
}
1351+
1352+
#[test]
1353+
fn sampling_f32_does_not_panic() {
1354+
sample_fuzz::<f32>();
1355+
}
1356+
1357+
#[test]
1358+
fn sampling_f64_does_not_panic() {
1359+
sample_fuzz::<f64>();
1360+
}
1361+
1362+
#[test]
1363+
#[should_panic]
1364+
fn uniform_sampling_panic_on_infinity_notnan() {
1365+
let (low, high) = (NotNan::new(0f64).unwrap(), NotNan::new(f64::INFINITY).unwrap());
1366+
let uniform = Uniform::new(low,high);
1367+
let _ = uniform.sample(&mut rand::thread_rng());
1368+
}
1369+
1370+
#[test]
1371+
#[should_panic]
1372+
fn uniform_sampling_panic_on_infinity_ordered() {
1373+
let (low, high) = (OrderedFloat(0f64), OrderedFloat(f64::INFINITY));
1374+
let uniform = Uniform::new(low,high);
1375+
let _ = uniform.sample(&mut rand::thread_rng());
1376+
}
1377+
1378+
#[test]
1379+
#[should_panic]
1380+
fn uniform_sampling_panic_on_nan_ordered() {
1381+
let (low, high) = (OrderedFloat(0f64), OrderedFloat(f64::NAN));
1382+
let uniform = Uniform::new(low,high);
1383+
let _ = uniform.sample(&mut rand::thread_rng());
1384+
}
1385+
}

0 commit comments

Comments
 (0)