random_number/
random_functions.rs

1use std::{
2    cmp::Ordering,
3    ops::{Bound, RangeBounds},
4};
5
6use crate::{
7    rand::{
8        distributions::{
9            uniform::{SampleBorrow, SampleUniform, Uniform},
10            Distribution,
11        },
12        thread_rng, Rng,
13    },
14    Bounded,
15};
16
17/// Generate a random value in the range [`min`, `max_exclusive`) with a new lazily-initialized thread-local random number generator.
18///
19/// Panics if `min >= max_exclusive`.
20#[inline]
21pub fn random_exclusively<X: SampleUniform, B1: SampleBorrow<X>, B2: SampleBorrow<X>>(
22    min: B1,
23    max_exclusive: B2,
24) -> X {
25    random_exclusively_with_rng(min, max_exclusive, &mut thread_rng())
26}
27
28/// Generate a random value in the range [`min`, `max_exclusive`) with an existing random number generator.
29///
30/// Panics if `min >= max_exclusive`.
31#[inline]
32pub fn random_exclusively_with_rng<
33    X: SampleUniform,
34    B1: SampleBorrow<X>,
35    B2: SampleBorrow<X>,
36    T: Rng,
37>(
38    min: B1,
39    max_exclusive: B2,
40    rng: &mut T,
41) -> X {
42    let uniform = Uniform::new(min, max_exclusive);
43
44    uniform.sample(rng)
45}
46
47/// Generate a random value in the range [`min`, `max_inclusive`] with a new lazily-initialized thread-local random number generator.
48///
49/// Panics if `min > max_inclusive`.
50#[inline]
51pub fn random_inclusively<X: SampleUniform, B1: SampleBorrow<X>, B2: SampleBorrow<X>>(
52    min: B1,
53    max_inclusive: B2,
54) -> X {
55    random_inclusively_with_rng(min, max_inclusive, &mut thread_rng())
56}
57
58/// Generate a random value in the range [`min`, `max_inclusive`] with an existing random number generator.
59///
60/// Panics if `min > max_inclusive`.
61#[inline]
62pub fn random_inclusively_with_rng<
63    X: SampleUniform,
64    B1: SampleBorrow<X>,
65    B2: SampleBorrow<X>,
66    T: Rng,
67>(
68    min: B1,
69    max_inclusive: B2,
70    rng: &mut T,
71) -> X {
72    Uniform::new_inclusive(min, max_inclusive).sample(rng)
73}
74
75/// Generate a random value in the range [`a`, `b`] or [`b`, `a`] with a new lazily-initialized thread-local random number generator.
76///
77/// Panics if a and b can not be compared.
78#[inline]
79pub fn random_inclusively_cmp<X: SampleUniform + Ord + Clone, B: SampleBorrow<X>>(a: B, b: B) -> X {
80    random_inclusively_cmp_with_rng(a, b, &mut thread_rng())
81}
82
83/// Generate a random value in the range [`a`, `b`] or [`b`, `a`] with an existing random number generator.
84#[inline]
85pub fn random_inclusively_cmp_with_rng<
86    X: SampleUniform + Ord + Clone,
87    B: SampleBorrow<X>,
88    T: Rng,
89>(
90    a: B,
91    b: B,
92    rng: &mut T,
93) -> X {
94    match a.borrow().cmp(b.borrow()) {
95        Ordering::Greater => random_inclusively_with_rng(b, a, rng),
96        Ordering::Equal => a.borrow().clone(),
97        Ordering::Less => random_inclusively_with_rng(a, b, rng),
98    }
99}
100
101/// Generate a random value in the range of the output type with a new lazily-initialized thread-local random number generator.
102#[inline]
103pub fn random<X: SampleUniform + Bounded>() -> X {
104    random_with_rng(&mut thread_rng())
105}
106
107/// Generate a random value in the range of the output type with an existing random number generator.
108#[inline]
109pub fn random_with_rng<X: SampleUniform + Bounded, T: Rng>(rng: &mut T) -> X {
110    random_inclusively_with_rng(X::min_value(), X::max_value(), rng)
111}
112
113/// Generate a random value in the range [`min`, `Bounded::max_value()`] with a new lazily-initialized thread-local random number generator.
114#[inline]
115pub fn random_at_least<X: SampleUniform + Bounded, B: SampleBorrow<X>>(min: B) -> X {
116    random_at_least_with_rng(min, &mut thread_rng())
117}
118
119/// Generate a random value in the range [`min`, `X::max_value()`] with an existing random number generator.
120#[inline]
121pub fn random_at_least_with_rng<X: SampleUniform + Bounded, B: SampleBorrow<X>, T: Rng>(
122    min: B,
123    rng: &mut T,
124) -> X {
125    random_inclusively_with_rng(min, X::max_value(), rng)
126}
127
128/// Generate a random value in the range [`X::min_value()`, `max_inclusive`] with a new lazily-initialized thread-local random number generator.
129#[inline]
130pub fn random_at_most<X: SampleUniform + Bounded, B: SampleBorrow<X>>(max_inclusive: B) -> X {
131    random_at_most_with_rng(max_inclusive, &mut thread_rng())
132}
133
134/// Generate a random value in the range [`X::min_value()`, `max_inclusive`] with an existing random number generator.
135#[inline]
136pub fn random_at_most_with_rng<X: SampleUniform + Bounded, B: SampleBorrow<X>, T: Rng>(
137    max_inclusive: B,
138    rng: &mut T,
139) -> X {
140    random_inclusively_with_rng(X::min_value(), max_inclusive, rng)
141}
142
143/// Generate a random value in the range [`X::min_value()`, `max_exclusive`) with a new lazily-initialized thread-local random number generator.
144///
145/// Panics if X::min_value() == max_exclusive.
146#[inline]
147pub fn random_at_most_exclusively<X: SampleUniform + Bounded, B: SampleBorrow<X>>(
148    max_exclusive: B,
149) -> X {
150    random_at_most_exclusively_with_rng(max_exclusive, &mut thread_rng())
151}
152
153/// Generate a random value in the range [`X::min_value()`, `max_exclusive`) with an existing random number generator.
154///
155/// Panics if X::min_value() == max_exclusive.
156#[inline]
157pub fn random_at_most_exclusively_with_rng<
158    X: SampleUniform + Bounded,
159    B: SampleBorrow<X>,
160    T: Rng,
161>(
162    max_exclusive: B,
163    rng: &mut T,
164) -> X {
165    random_exclusively_with_rng(X::min_value(), max_exclusive, rng)
166}
167
168/// Generate a random value in a specific range with a new lazily-initialized thread-local random number generator.
169///
170/// Panics if the start bound is exclusive.
171#[inline]
172pub fn random_ranged<X: SampleUniform + Bounded, R: RangeBounds<X>>(range: R) -> X {
173    random_ranged_with_rng(range, &mut thread_rng())
174}
175
176/// Generate a random value in a specific range with an existing random number generator.
177///
178/// Panics if the start bound is exclusive.
179#[inline]
180pub fn random_ranged_with_rng<X: SampleUniform + Bounded, R: RangeBounds<X>, T: Rng>(
181    range: R,
182    rng: &mut T,
183) -> X {
184    let start = range.start_bound();
185    let end = range.end_bound();
186
187    match start {
188        Bound::Excluded(_) => {
189            panic!("random_ranged_with_rng called with a start bound which is exclusive")
190        },
191        Bound::Included(min) => match end {
192            Bound::Excluded(max_exclusive) => random_exclusively_with_rng(min, max_exclusive, rng),
193            Bound::Included(max_inclusive) => random_inclusively_with_rng(min, max_inclusive, rng),
194            Bound::Unbounded => random_at_least_with_rng(min, rng),
195        },
196        Bound::Unbounded => match end {
197            Bound::Excluded(max_exclusive) => {
198                random_at_most_exclusively_with_rng(max_exclusive, rng)
199            },
200            Bound::Included(max_inclusive) => random_at_most_with_rng(max_inclusive, rng),
201            Bound::Unbounded => random_with_rng(rng),
202        },
203    }
204}