#![doc = include_str!("../README.md")]
#![allow(unknown_lints)]
#![deny(
clippy::expect_used,
clippy::explicit_deref_methods,
clippy::option_if_let_else,
clippy::await_holding_lock,
clippy::cloned_instead_of_copied,
clippy::explicit_into_iter_loop,
clippy::flat_map_option,
clippy::fn_params_excessive_bools,
clippy::implicit_clone,
clippy::inefficient_to_string,
clippy::large_types_passed_by_value,
clippy::manual_ok_or,
clippy::map_flatten,
clippy::map_unwrap_or,
clippy::must_use_candidate,
clippy::needless_for_each,
clippy::needless_pass_by_value,
clippy::option_option,
clippy::redundant_else,
clippy::semicolon_if_nothing_returned,
clippy::too_many_lines,
clippy::trivially_copy_pass_by_ref,
clippy::unnested_or_patterns,
clippy::future_not_send,
clippy::useless_let_if_seq,
clippy::str_to_string,
clippy::inherent_to_string,
clippy::let_and_return,
clippy::string_to_string,
clippy::try_err,
clippy::unused_async,
clippy::missing_enforced_import_renames,
clippy::nonstandard_macro_braces,
clippy::rc_mutex,
clippy::unwrap_or_else_default,
clippy::manual_split_once,
clippy::derivable_impls,
clippy::needless_option_as_deref,
clippy::iter_not_returning_iterator,
clippy::same_name_method,
clippy::manual_assert,
clippy::non_send_fields_in_send_ty,
clippy::equatable_if_let,
bad_style,
clashing_extern_declarations,
dead_code,
deprecated,
explicit_outlives_requirements,
improper_ctypes,
invalid_value,
missing_copy_implementations,
missing_debug_implementations,
mutable_transmutes,
no_mangle_generic_items,
non_shorthand_field_patterns,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
trivial_bounds,
trivial_casts,
trivial_numeric_casts,
type_alias_bounds,
unconditional_recursion,
unreachable_pub,
unsafe_code,
unstable_features,
unused,
unused_allocation,
unused_comparisons,
unused_import_braces,
unused_parens,
unused_qualifications,
while_true,
missing_docs
)]
#![allow(unused_attributes, clippy::derive_partial_eq_without_eq, clippy::box_default)]
#![allow(clippy::must_use_candidate)]
use std::sync::Arc;
use parking_lot::RwLock;
use rand::distributions::{Alphanumeric, Standard};
use rand::prelude::Distribution;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha12Rng;
use uuid::Uuid;
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Seed(u64);
impl Seed {
pub fn unsafe_new(seed: u64) -> Self {
Self(seed)
}
pub fn rng(self) -> Random {
Random::from_seed(self)
}
}
impl std::fmt::Display for Seed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug)]
#[must_use]
pub struct Random {
rng: Arc<RwLock<ChaCha12Rng>>,
}
#[must_use]
pub(crate) fn new_seed() -> Seed {
let mut rng = rand::thread_rng();
Seed(rng.gen())
}
impl Random {
pub fn new() -> Self {
Self::from_seed(new_seed())
}
pub fn seed(&self) -> Seed {
Seed(self.gen())
}
#[must_use]
pub fn gen<T>(&self) -> T
where
Standard: Distribution<T>,
{
let mut rng = self.rng.write();
rng.gen()
}
#[allow(clippy::needless_pass_by_value)]
pub fn from_seed(seed: Seed) -> Self {
let rng = ChaCha12Rng::seed_from_u64(seed.0);
Self {
rng: Arc::new(RwLock::new(rng)),
}
}
pub fn u32(&self) -> u32 {
self.gen()
}
pub fn i32(&self) -> i32 {
self.gen()
}
pub fn bytes(&self, length: usize) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::with_capacity(length);
let mut rng = self.rng.write();
for _ in 0..length {
bytes.push(rng.gen());
}
bytes
}
pub fn string(&self, length: usize) -> String {
let mut string: String = String::with_capacity(length);
let mut rng = self.rng.write();
for _ in 0..length {
string.push(rng.gen());
}
string
}
pub fn alphanumeric(&self, length: usize) -> String {
let mut rng = self.rng.write();
let chars: String = std::iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(length)
.collect();
chars
}
pub fn uuid(&self) -> Uuid {
let mut raw_bytes: [u8; 16] = [0; 16];
let mut rng = self.rng.write();
rng.fill(&mut raw_bytes);
let bytes: uuid::Bytes = raw_bytes;
let builder = uuid::Builder::from_bytes(bytes);
builder.into_uuid()
}
pub fn range(&self, min: u32, max: u32) -> u32 {
let mut rng = self.rng.write();
rng.gen_range(min..max)
}
}
impl Default for Random {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bytes() {
let rng = Random::from_seed(Seed(100000));
let bytes1 = rng.bytes(10);
let bytes2 = rng.bytes(10);
assert_ne!(bytes1, bytes2);
let rng = Random::from_seed(Seed(100000));
let bytes2 = rng.bytes(10);
assert_eq!(bytes1, bytes2);
}
#[test]
fn string() {
let rng = Random::from_seed(Seed(100000));
let v1 = rng.string(10);
let v2 = rng.string(10);
assert_ne!(v1, v2);
let rng = Random::from_seed(Seed(100000));
let v2 = rng.string(10);
assert_eq!(v1, v2);
}
#[test]
fn alphanum() {
let rng = Random::from_seed(Seed(100000));
let v1 = rng.alphanumeric(10);
let v2 = rng.alphanumeric(10);
assert_ne!(v1, v2);
let rng = Random::from_seed(Seed(100000));
let v2 = rng.alphanumeric(10);
assert_eq!(v1, v2);
}
#[test]
fn uuid() {
let rng = Random::from_seed(Seed(100000));
let v1 = rng.uuid();
let v2 = rng.uuid();
assert_ne!(v1, v2);
let rng = Random::from_seed(Seed(100000));
let v2 = rng.uuid();
assert_eq!(v1, v2);
}
}