Skip to content

Commit b4c1d66

Browse files
committed
Add DistString
1 parent 1947c89 commit b4c1d66

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/distributions/distribution.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
1212
use crate::Rng;
1313
use core::iter;
14+
#[cfg(feature = "alloc")]
15+
use alloc::string::String;
1416

1517
/// Types (distributions) that can be used to create a random instance of `T`.
1618
///
@@ -187,9 +189,27 @@ where
187189
}
188190
}
189191

192+
/// `String` sampler
193+
///
194+
/// Sampling a `String` of random characters is not quite the same as collecting
195+
/// a sequence of chars. This trait contains some helpers.
196+
#[cfg(feature = "alloc")]
197+
pub trait DistString {
198+
/// Append `len` random chars to `string`
199+
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize);
200+
201+
/// Generate a `String` of `len` random chars
202+
#[inline]
203+
fn sample_string<R: Rng + ?Sized>(&self, rng: &mut R, len: usize) -> String {
204+
let mut s = String::new();
205+
self.append_string(rng, &mut s, len);
206+
s
207+
}
208+
}
209+
190210
#[cfg(test)]
191211
mod tests {
192-
use crate::distributions::{Distribution, Uniform};
212+
use crate::distributions::{Alphanumeric, Distribution, Standard, Uniform};
193213
use crate::Rng;
194214

195215
#[test]
@@ -233,4 +253,20 @@ mod tests {
233253
}
234254
assert_eq!(count, 10);
235255
}
256+
257+
#[test]
258+
#[cfg(feature = "alloc")]
259+
fn test_dist_string() {
260+
use core::str;
261+
use crate::distributions::DistString;
262+
let mut rng = crate::test::rng(213);
263+
264+
let s1 = Alphanumeric.sample_string(&mut rng, 20);
265+
assert_eq!(s1.len(), 20);
266+
assert_eq!(str::from_utf8(s1.as_bytes()), Ok(s1.as_str()));
267+
268+
let s2 = Standard.sample_string(&mut rng, 20);
269+
assert_eq!(s2.chars().count(), 20);
270+
assert_eq!(str::from_utf8(s2.as_bytes()), Ok(s2.as_str()));
271+
}
236272
}

src/distributions/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ pub mod weighted;
118118

119119
pub use self::bernoulli::{Bernoulli, BernoulliError};
120120
pub use self::distribution::{Distribution, DistIter, DistMap};
121+
#[cfg(feature = "alloc")]
122+
pub use self::distribution::DistString;
121123
pub use self::float::{Open01, OpenClosed01};
122124
pub use self::other::Alphanumeric;
123125
pub use self::slice::Slice;

src/distributions/other.rs

+25
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010
1111
use core::char;
1212
use core::num::Wrapping;
13+
#[cfg(feature = "alloc")]
14+
use alloc::string::String;
1315

1416
use crate::distributions::{Distribution, Standard, Uniform};
17+
#[cfg(feature = "alloc")]
18+
use crate::distributions::DistString;
1519
use crate::Rng;
1620

1721
#[cfg(feature = "serde1")]
@@ -85,6 +89,16 @@ impl Distribution<char> for Standard {
8589
}
8690
}
8791

92+
/// Note: the `String` is potentially left with excess capacity; optionally the
93+
/// user may call `string.shrink_to_fit()` afterwards.
94+
#[cfg(feature = "alloc")]
95+
impl DistString for Standard {
96+
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) {
97+
s.reserve(s.len() + 4 * len);
98+
s.extend(Distribution::<char>::sample_iter(self, rng).take(len));
99+
}
100+
}
101+
88102
impl Distribution<u8> for Alphanumeric {
89103
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
90104
const RANGE: u32 = 26 + 26 + 10;
@@ -104,6 +118,17 @@ impl Distribution<u8> for Alphanumeric {
104118
}
105119
}
106120

121+
#[cfg(feature = "alloc")]
122+
impl DistString for Alphanumeric {
123+
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
124+
unsafe {
125+
let v = string.as_mut_vec();
126+
v.reserve(v.len() + len);
127+
v.extend(self.sample_iter(rng).take(len));
128+
}
129+
}
130+
}
131+
107132
impl Distribution<bool> for Standard {
108133
#[inline]
109134
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {

0 commit comments

Comments
 (0)