mirror of https://github.com/smol-rs/fastrand
Merge pull request #25 from BartMassey-upstream/char
added char() implementations and tests
This commit is contained in:
commit
20bfa8ddd1
62
src/lib.rs
62
src/lib.rs
|
@ -516,6 +516,67 @@ impl Rng {
|
|||
let i = self.u8(..len);
|
||||
CHARS[i as usize] as char
|
||||
}
|
||||
|
||||
/// Generates a random `char` in the given range.
|
||||
///
|
||||
/// Panics if the range is empty.
|
||||
#[inline]
|
||||
pub fn char(&self, range: impl RangeBounds<char>) -> char {
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
let panic_empty_range = || {
|
||||
panic!(
|
||||
"empty range: {:?}..{:?}",
|
||||
range.start_bound(),
|
||||
range.end_bound()
|
||||
)
|
||||
};
|
||||
|
||||
let surrogate_start = 0xd800u32;
|
||||
let surrogate_len = 0x800u32;
|
||||
|
||||
let low = match range.start_bound() {
|
||||
Bound::Unbounded => 0u8 as char,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => {
|
||||
let scalar = if x as u32 == surrogate_start - 1 {
|
||||
surrogate_start + surrogate_len
|
||||
} else {
|
||||
x as u32 + 1
|
||||
};
|
||||
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
|
||||
}
|
||||
};
|
||||
|
||||
let high = match range.end_bound() {
|
||||
Bound::Unbounded => std::char::MAX,
|
||||
Bound::Included(&x) => x,
|
||||
Bound::Excluded(&x) => {
|
||||
let scalar = if x as u32 == surrogate_start + surrogate_len {
|
||||
surrogate_start - 1
|
||||
} else {
|
||||
(x as u32).wrapping_sub(1)
|
||||
};
|
||||
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
|
||||
}
|
||||
};
|
||||
|
||||
if low > high {
|
||||
panic_empty_range();
|
||||
}
|
||||
|
||||
let gap = if (low as u32) < surrogate_start && (high as u32) >= surrogate_start {
|
||||
surrogate_len
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let range = high as u32 - low as u32 - gap;
|
||||
let mut val = self.u32(0..=range) + low as u32;
|
||||
if val >= surrogate_start {
|
||||
val += gap;
|
||||
}
|
||||
val.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the thread-local generator with the given seed.
|
||||
|
@ -594,6 +655,7 @@ integer!(u128, "Generates a random `u128` in the given range.");
|
|||
integer!(i128, "Generates a random `i128` in the given range.");
|
||||
integer!(usize, "Generates a random `usize` in the given range.");
|
||||
integer!(isize, "Generates a random `isize` in the given range.");
|
||||
integer!(char, "Generates a random `char` in the given range.");
|
||||
|
||||
/// Generates a random `f32` in range `0..1`.
|
||||
pub fn f32() -> f32 {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
fn test_char_coverage<R>(n: usize, range: R)
|
||||
where
|
||||
R: Iterator<Item = char> + RangeBounds<char> + Clone,
|
||||
{
|
||||
use std::collections::HashSet;
|
||||
|
||||
let all: HashSet<char> = range.clone().collect();
|
||||
let mut covered = HashSet::new();
|
||||
for _ in 0..n {
|
||||
let c = fastrand::char(range.clone());
|
||||
assert!(all.contains(&c));
|
||||
covered.insert(c);
|
||||
}
|
||||
assert_eq!(covered, all);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char() {
|
||||
// ASCII control chars.
|
||||
let nul = 0u8 as char;
|
||||
let soh = 1u8 as char;
|
||||
let stx = 2u8 as char;
|
||||
// Some undefined Hangul Jamo codepoints just before
|
||||
// the surrogate area.
|
||||
let last_jamo = char::try_from(0xd7ffu32).unwrap();
|
||||
let penultimate_jamo = char::try_from(last_jamo as u32 - 1).unwrap();
|
||||
// Private-use codepoints just after the surrogate area.
|
||||
let first_private = char::try_from(0xe000u32).unwrap();
|
||||
let second_private = char::try_from(first_private as u32 + 1).unwrap();
|
||||
// Private-use codepoints at the end of Unicode space.
|
||||
let last_private = std::char::MAX;
|
||||
let penultimate_private = char::try_from(last_private as u32 - 1).unwrap();
|
||||
|
||||
test_char_coverage(100, nul..stx);
|
||||
test_char_coverage(100, nul..=soh);
|
||||
|
||||
test_char_coverage(400, penultimate_jamo..second_private);
|
||||
test_char_coverage(400, penultimate_jamo..=second_private);
|
||||
|
||||
test_char_coverage(100, penultimate_private..=last_private);
|
||||
}
|
Loading…
Reference in New Issue