]>
Commit | Line | Data |
---|---|---|
0731742a XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // https://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! The implementations of the `Standard` distribution for other built-in types. | |
12 | ||
13 | use core::char; | |
14 | use core::num::Wrapping; | |
15 | ||
16 | use {Rng}; | |
17 | use distributions::{Distribution, Standard, Uniform}; | |
18 | ||
19 | // ----- Sampling distributions ----- | |
20 | ||
21 | /// Sample a `char`, uniformly distributed over ASCII letters and numbers: | |
22 | /// a-z, A-Z and 0-9. | |
23 | /// | |
24 | /// # Example | |
25 | /// | |
26 | /// ``` | |
27 | /// use std::iter; | |
28 | /// use rand::{Rng, thread_rng}; | |
29 | /// use rand::distributions::Alphanumeric; | |
30 | /// | |
31 | /// let mut rng = thread_rng(); | |
32 | /// let chars: String = iter::repeat(()) | |
33 | /// .map(|()| rng.sample(Alphanumeric)) | |
34 | /// .take(7) | |
35 | /// .collect(); | |
36 | /// println!("Random chars: {}", chars); | |
37 | /// ``` | |
38 | #[derive(Debug)] | |
39 | pub struct Alphanumeric; | |
40 | ||
41 | ||
42 | // ----- Implementations of distributions ----- | |
43 | ||
44 | impl Distribution<char> for Standard { | |
45 | #[inline] | |
46 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { | |
47 | let range = Uniform::new(0u32, 0x11_0000); | |
48 | loop { | |
49 | match char::from_u32(range.sample(rng)) { | |
50 | Some(c) => return c, | |
51 | // About 0.2% of numbers in the range 0..0x110000 are invalid | |
52 | // codepoints (surrogates). | |
53 | None => {} | |
54 | } | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
59 | impl Distribution<char> for Alphanumeric { | |
60 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { | |
61 | const RANGE: u32 = 26 + 26 + 10; | |
62 | const GEN_ASCII_STR_CHARSET: &[u8] = | |
63 | b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ | |
64 | abcdefghijklmnopqrstuvwxyz\ | |
65 | 0123456789"; | |
66 | // We can pick from 62 characters. This is so close to a power of 2, 64, | |
67 | // that we can do better than `Uniform`. Use a simple bitshift and | |
68 | // rejection sampling. We do not use a bitmask, because for small RNGs | |
69 | // the most significant bits are usually of higher quality. | |
70 | loop { | |
71 | let var = rng.next_u32() >> (32 - 6); | |
72 | if var < RANGE { | |
73 | return GEN_ASCII_STR_CHARSET[var as usize] as char | |
74 | } | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | impl Distribution<bool> for Standard { | |
80 | #[inline] | |
81 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { | |
82 | // We can compare against an arbitrary bit of an u32 to get a bool. | |
83 | // Because the least significant bits of a lower quality RNG can have | |
84 | // simple patterns, we compare against the most significant bit. This is | |
85 | // easiest done using a sign test. | |
86 | (rng.next_u32() as i32) < 0 | |
87 | } | |
88 | } | |
89 | ||
90 | macro_rules! tuple_impl { | |
91 | // use variables to indicate the arity of the tuple | |
92 | ($($tyvar:ident),* ) => { | |
93 | // the trailing commas are for the 1 tuple | |
94 | impl< $( $tyvar ),* > | |
95 | Distribution<( $( $tyvar ),* , )> | |
96 | for Standard | |
97 | where $( Standard: Distribution<$tyvar> ),* | |
98 | { | |
99 | #[inline] | |
100 | fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) { | |
101 | ( | |
102 | // use the $tyvar's to get the appropriate number of | |
103 | // repeats (they're not actually needed) | |
104 | $( | |
105 | _rng.gen::<$tyvar>() | |
106 | ),* | |
107 | , | |
108 | ) | |
109 | } | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | impl Distribution<()> for Standard { | |
115 | #[inline] | |
116 | fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () } | |
117 | } | |
118 | tuple_impl!{A} | |
119 | tuple_impl!{A, B} | |
120 | tuple_impl!{A, B, C} | |
121 | tuple_impl!{A, B, C, D} | |
122 | tuple_impl!{A, B, C, D, E} | |
123 | tuple_impl!{A, B, C, D, E, F} | |
124 | tuple_impl!{A, B, C, D, E, F, G} | |
125 | tuple_impl!{A, B, C, D, E, F, G, H} | |
126 | tuple_impl!{A, B, C, D, E, F, G, H, I} | |
127 | tuple_impl!{A, B, C, D, E, F, G, H, I, J} | |
128 | tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} | |
129 | tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} | |
130 | ||
131 | macro_rules! array_impl { | |
132 | // recursive, given at least one type parameter: | |
133 | {$n:expr, $t:ident, $($ts:ident,)*} => { | |
134 | array_impl!{($n - 1), $($ts,)*} | |
135 | ||
136 | impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> { | |
137 | #[inline] | |
138 | fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { | |
139 | [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*] | |
140 | } | |
141 | } | |
142 | }; | |
143 | // empty case: | |
144 | {$n:expr,} => { | |
145 | impl<T> Distribution<[T; $n]> for Standard { | |
146 | fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] } | |
147 | } | |
148 | }; | |
149 | } | |
150 | ||
151 | array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,} | |
152 | ||
153 | impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> { | |
154 | #[inline] | |
155 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> { | |
156 | // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066 | |
157 | if rng.gen::<bool>() { | |
158 | Some(rng.gen()) | |
159 | } else { | |
160 | None | |
161 | } | |
162 | } | |
163 | } | |
164 | ||
165 | impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> { | |
166 | #[inline] | |
167 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> { | |
168 | Wrapping(rng.gen()) | |
169 | } | |
170 | } | |
171 | ||
172 | ||
173 | #[cfg(test)] | |
174 | mod tests { | |
175 | use {Rng, RngCore, Standard}; | |
176 | use distributions::Alphanumeric; | |
177 | #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String; | |
178 | ||
179 | #[test] | |
180 | fn test_misc() { | |
181 | let rng: &mut RngCore = &mut ::test::rng(820); | |
182 | ||
183 | rng.sample::<char, _>(Standard); | |
184 | rng.sample::<bool, _>(Standard); | |
185 | } | |
186 | ||
187 | #[cfg(feature="alloc")] | |
188 | #[test] | |
189 | fn test_chars() { | |
190 | use core::iter; | |
191 | let mut rng = ::test::rng(805); | |
192 | ||
193 | // Test by generating a relatively large number of chars, so we also | |
194 | // take the rejection sampling path. | |
195 | let word: String = iter::repeat(()) | |
196 | .map(|()| rng.gen::<char>()).take(1000).collect(); | |
197 | assert!(word.len() != 0); | |
198 | } | |
199 | ||
200 | #[test] | |
201 | fn test_alphanumeric() { | |
202 | let mut rng = ::test::rng(806); | |
203 | ||
204 | // Test by generating a relatively large number of chars, so we also | |
205 | // take the rejection sampling path. | |
206 | let mut incorrect = false; | |
207 | for _ in 0..100 { | |
208 | let c = rng.sample(Alphanumeric); | |
209 | incorrect |= !((c >= '0' && c <= '9') || | |
210 | (c >= 'A' && c <= 'Z') || | |
211 | (c >= 'a' && c <= 'z') ); | |
212 | } | |
213 | assert!(incorrect == false); | |
214 | } | |
215 | } |