Skip to content

Commit 7d73990

Browse files
authored
Make Uniform constructors return a result (#1229)
* Forbid unsafe code in crates without unsafe code This helps tools like `cargo geiger`. * Make `Uniform` constructors return a result - This is a breaking change. - The new error type had to be made public, otherwise `Uniform` could not be extended for user-defined types by implementing `UniformSampler`. - `rand_distr` was updated accordingly. - Also forbid unsafe code for crates where none is used. Fixes #1195, #1211. * Address review feedback * Make `sample_single` return a `Result` * Fix benchmarks * Small fixes * Update src/distributions/uniform.rs
1 parent ae4b48e commit 7d73990

23 files changed

+261
-228
lines changed

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
88

99
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
1010

11-
## [Unreleased API changing release]
11+
## [0.9.0] - unreleased
12+
### Distributions
13+
- `{Uniform, UniformSampler}::{new, new_inclusive}` return a `Result` (instead of potentially panicking) (#1229)
14+
- `Uniform` implements `TryFrom` instead of `From` for ranges (#1229)
1215

1316
### Other
1417
- Simpler and faster implementation of Floyd's F2 (#1277). This

benches/distributions.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -131,36 +131,36 @@ macro_rules! distr {
131131
}
132132

133133
// uniform
134-
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
135-
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
136-
distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000));
137-
distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123));
138-
distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789));
139-
distr_int!(distr_uniform_usize16, usize, Uniform::new(0usize, 0xb9d7));
140-
distr_int!(distr_uniform_usize32, usize, Uniform::new(0usize, 0x548c0f43));
134+
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100).unwrap());
135+
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000).unwrap());
136+
distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000).unwrap());
137+
distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123).unwrap());
138+
distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789).unwrap());
139+
distr_int!(distr_uniform_usize16, usize, Uniform::new(0usize, 0xb9d7).unwrap());
140+
distr_int!(distr_uniform_usize32, usize, Uniform::new(0usize, 0x548c0f43).unwrap());
141141
#[cfg(target_pointer_width = "64")]
142-
distr_int!(distr_uniform_usize64, usize, Uniform::new(0usize, 0x3a42714f2bf927a8));
143-
distr_int!(distr_uniform_isize, isize, Uniform::new(-1060478432isize, 1858574057));
142+
distr_int!(distr_uniform_usize64, usize, Uniform::new(0usize, 0x3a42714f2bf927a8).unwrap());
143+
distr_int!(distr_uniform_isize, isize, Uniform::new(-1060478432isize, 1858574057).unwrap());
144144

145-
distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319));
146-
distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319));
145+
distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319).unwrap());
146+
distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319).unwrap());
147147

148148
const LARGE_SEC: u64 = u64::max_value() / 1000;
149149

150150
distr_duration!(distr_uniform_duration_largest,
151-
Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))
151+
Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999)).unwrap()
152152
);
153153
distr_duration!(distr_uniform_duration_large,
154-
Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2))
154+
Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2)).unwrap()
155155
);
156156
distr_duration!(distr_uniform_duration_one,
157-
Uniform::new(Duration::new(0, 0), Duration::new(1, 0))
157+
Uniform::new(Duration::new(0, 0), Duration::new(1, 0)).unwrap()
158158
);
159159
distr_duration!(distr_uniform_duration_variety,
160-
Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954))
160+
Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954)).unwrap()
161161
);
162162
distr_duration!(distr_uniform_duration_edge,
163-
Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1))
163+
Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1)).unwrap()
164164
);
165165

166166
// standard
@@ -272,7 +272,7 @@ macro_rules! uniform_sample {
272272
let high = black_box($high);
273273
b.iter(|| {
274274
for _ in 0..10 {
275-
let dist = UniformInt::<$type>::new(low, high);
275+
let dist = UniformInt::<$type>::new(low, high).unwrap();
276276
for _ in 0..$count {
277277
black_box(dist.sample(&mut rng));
278278
}
@@ -291,7 +291,7 @@ macro_rules! uniform_inclusive {
291291
let high = black_box($high);
292292
b.iter(|| {
293293
for _ in 0..10 {
294-
let dist = UniformInt::<$type>::new_inclusive(low, high);
294+
let dist = UniformInt::<$type>::new_inclusive(low, high).unwrap();
295295
for _ in 0..$count {
296296
black_box(dist.sample(&mut rng));
297297
}
@@ -311,7 +311,7 @@ macro_rules! uniform_single {
311311
let high = black_box($high);
312312
b.iter(|| {
313313
for _ in 0..(10 * $count) {
314-
black_box(UniformInt::<$type>::sample_single(low, high, &mut rng));
314+
black_box(UniformInt::<$type>::sample_single(low, high, &mut rng).unwrap());
315315
}
316316
});
317317
}

examples/monte-carlo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
use rand::distributions::{Distribution, Uniform};
3030

3131
fn main() {
32-
let range = Uniform::new(-1.0f64, 1.0);
32+
let range = Uniform::new(-1.0f64, 1.0).unwrap();
3333
let mut rng = rand::thread_rng();
3434

3535
let total = 1_000_000;

examples/monty-hall.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ fn main() {
8080
let num_simulations = 10000;
8181

8282
let mut rng = rand::thread_rng();
83-
let random_door = Uniform::new(0u32, 3);
83+
let random_door = Uniform::new(0u32, 3).unwrap();
8484

8585
let (mut switch_wins, mut switch_losses) = (0, 0);
8686
let (mut keep_wins, mut keep_losses) = (0, 0);

examples/rayon-monte-carlo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static BATCH_SIZE: u64 = 10_000;
4949
static BATCHES: u64 = 1000;
5050

5151
fn main() {
52-
let range = Uniform::new(-1.0f64, 1.0);
52+
let range = Uniform::new(-1.0f64, 1.0).unwrap();
5353

5454
let in_circle = (0..BATCHES)
5555
.into_par_iter()

rand_chacha/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
1414
html_root_url = "https://rust-random.github.io/rand/"
1515
)]
16+
#![forbid(unsafe_code)]
1617
#![deny(missing_docs)]
1718
#![deny(missing_debug_implementations)]
1819
#![doc(test(attr(allow(unused_variables), deny(warnings))))]

rand_distr/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [0.5.0] - unreleased
88
- Remove unused fields from `Gamma`, `NormalInverseGaussian` and `Zipf` distributions (#1184)
99
This breaks serialization compatibility with older versions.
10+
- Upgrade Rand
1011

1112
## [0.4.3] - 2021-12-30
1213
- Fix `no_std` build (#1208)

rand_distr/src/binomial.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ impl Distribution<u64> for Binomial {
163163
// return value
164164
let mut y: i64;
165165

166-
let gen_u = Uniform::new(0., p4);
167-
let gen_v = Uniform::new(0., 1.);
166+
let gen_u = Uniform::new(0., p4).unwrap();
167+
let gen_v = Uniform::new(0., 1.).unwrap();
168168

169169
loop {
170170
// Step 1: Generate `u` for selecting the region. If region 1 is

rand_distr/src/hypergeometric.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ impl Distribution<u64> for Hypergeometric {
251251
x
252252
},
253253
RejectionAcceptance { m, a, lambda_l, lambda_r, x_l, x_r, p1, p2, p3 } => {
254-
let distr_region_select = Uniform::new(0.0, p3);
254+
let distr_region_select = Uniform::new(0.0, p3).unwrap();
255255
loop {
256256
let (y, v) = loop {
257257
let u = distr_region_select.sample(rng);

rand_distr/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
1212
html_root_url = "https://rust-random.github.io/rand/"
1313
)]
14+
#![forbid(unsafe_code)]
1415
#![deny(missing_docs)]
1516
#![deny(missing_debug_implementations)]
1617
#![allow(

rand_distr/src/unit_ball.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct UnitBall;
3131
impl<F: Float + SampleUniform> Distribution<[F; 3]> for UnitBall {
3232
#[inline]
3333
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [F; 3] {
34-
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap());
34+
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap()).unwrap();
3535
let mut x1;
3636
let mut x2;
3737
let mut x3;

rand_distr/src/unit_circle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct UnitCircle;
3535
impl<F: Float + SampleUniform> Distribution<[F; 2]> for UnitCircle {
3636
#[inline]
3737
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [F; 2] {
38-
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap());
38+
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap()).unwrap();
3939
let mut x1;
4040
let mut x2;
4141
let mut sum;

rand_distr/src/unit_disc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct UnitDisc;
3030
impl<F: Float + SampleUniform> Distribution<[F; 2]> for UnitDisc {
3131
#[inline]
3232
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [F; 2] {
33-
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap());
33+
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap()).unwrap();
3434
let mut x1;
3535
let mut x2;
3636
loop {

rand_distr/src/unit_sphere.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct UnitSphere;
3434
impl<F: Float + SampleUniform> Distribution<[F; 3]> for UnitSphere {
3535
#[inline]
3636
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [F; 3] {
37-
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap());
37+
let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap()).unwrap();
3838
loop {
3939
let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));
4040
let sum = x1 * x1 + x2 * x2;

rand_distr/src/weighted_alias.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ impl<W: AliasableWeight> WeightedAliasIndex<W> {
221221

222222
// Prepare distributions for sampling. Creating them beforehand improves
223223
// sampling performance.
224-
let uniform_index = Uniform::new(0, n);
225-
let uniform_within_weight_sum = Uniform::new(W::ZERO, weight_sum);
224+
let uniform_index = Uniform::new(0, n).unwrap();
225+
let uniform_within_weight_sum = Uniform::new(W::ZERO, weight_sum).unwrap();
226226

227227
Ok(Self {
228228
aliases: aliases.aliases,
@@ -458,7 +458,7 @@ mod test {
458458
let random_weight_distribution = Uniform::new_inclusive(
459459
W::ZERO,
460460
W::MAX / W::try_from_u32_lossy(NUM_WEIGHTS).unwrap(),
461-
);
461+
).unwrap();
462462
for _ in 0..NUM_WEIGHTS {
463463
weights.push(rng.sample(&random_weight_distribution));
464464
}

rand_pcg/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
3434
html_root_url = "https://rust-random.github.io/rand/"
3535
)]
36+
#![forbid(unsafe_code)]
3637
#![deny(missing_docs)]
3738
#![deny(missing_debug_implementations)]
3839
#![no_std]

src/distributions/distribution.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub trait Distribution<T> {
6464
/// .collect();
6565
///
6666
/// // Dice-rolling:
67-
/// let die_range = Uniform::new_inclusive(1, 6);
67+
/// let die_range = Uniform::new_inclusive(1, 6).unwrap();
6868
/// let mut roll_die = die_range.sample_iter(&mut rng);
6969
/// while roll_die.next().unwrap() != 6 {
7070
/// println!("Not a 6; rolling again!");
@@ -93,7 +93,7 @@ pub trait Distribution<T> {
9393
///
9494
/// let mut rng = thread_rng();
9595
///
96-
/// let die = Uniform::new_inclusive(1, 6);
96+
/// let die = Uniform::new_inclusive(1, 6).unwrap();
9797
/// let even_number = die.map(|num| num % 2 == 0);
9898
/// while !even_number.sample(&mut rng) {
9999
/// println!("Still odd; rolling again!");
@@ -227,7 +227,7 @@ mod tests {
227227

228228
#[test]
229229
fn test_distributions_map() {
230-
let dist = Uniform::new_inclusive(0, 5).map(|val| val + 15);
230+
let dist = Uniform::new_inclusive(0, 5).unwrap().map(|val| val + 15);
231231

232232
let mut rng = crate::test::rng(212);
233233
let val = dist.sample(&mut rng);
@@ -240,6 +240,7 @@ mod tests {
240240
rng: &mut R,
241241
) -> impl Iterator<Item = i32> + '_ {
242242
Uniform::new_inclusive(1, 6)
243+
.unwrap()
243244
.sample_iter(rng)
244245
.filter(|x| *x != 5)
245246
.take(10)

src/distributions/other.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ impl Distribution<char> for Standard {
8181
// reserved for surrogates. This is the size of that gap.
8282
const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;
8383

84-
// Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
84+
// Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used, but it
8585
// seemed slower.
86-
let range = Uniform::new(GAP_SIZE, 0x11_0000);
86+
let range = Uniform::new(GAP_SIZE, 0x11_0000).unwrap();
8787

8888
let mut n = range.sample(rng);
8989
if n <= 0xDFFF {

src/distributions/slice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<'a, T> Slice<'a, T> {
7575
0 => Err(EmptySlice),
7676
len => Ok(Self {
7777
slice,
78-
range: Uniform::new(0, len),
78+
range: Uniform::new(0, len).unwrap(),
7979
}),
8080
}
8181
}

0 commit comments

Comments
 (0)