use rand::{distributions::Slice, Rng};
use super::{NumStr, StringExtT, StringT};
use crate::random::fast_random;
#[macro_export]
macro_rules! random_str {
($range:expr, $charset:expr) => {{
$crate::string::rand::RandStr::<$range>::with_charset($charset)
}};
(HEX) => {{
$crate::string::rand::RandHexStr::new_default()
}};
(HEX: $l:expr) => {{
$crate::string::rand::RandHexStr::<$l>::new()
}};
(HEX: $l:expr, $rp:expr) => {{
$crate::string::rand::RandHexStr::<$l, $rp>::new()
}};
(HEX: $l:expr, $rp:expr, $lp:expr) => {{
$crate::string::rand::RandHexStr::<$l, $rp, $lp>::new()
}};
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RandHexStr<const L: usize = 16, const RP: usize = 1, const LP: usize = 0>;
impl<const L: usize, const RP: usize, const LP: usize> StringT for RandHexStr<L, RP, LP> {
#[inline]
fn encode_to_buf(self, string: &mut Vec<u8>) {
match L {
1..=16 => {
for _ in 0..RP {
NumStr::hex_default(fast_random())
.set_resize_len::<L>()
.encode_to_buf(string);
}
if LP > 0 {
debug_assert!(LP <= 16, "LP should be 0..=16");
NumStr::hex_default(fast_random())
.set_resize_len::<LP>()
.encode_to_buf(string);
}
}
0 => {}
_ => {
#[cfg(any(debug_assertions, test))]
unreachable!("L should be 0..=16");
#[cfg(not(any(debug_assertions, test)))]
string.extend(
rand::thread_rng()
.sample_iter(&Slice::new(b"0123456789abcdef").unwrap())
.take(L * RP + LP),
);
}
}
}
#[inline]
fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
self.encode_to_buf(string);
string.extend(separator.as_bytes());
}
#[inline]
fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
match L {
1..=16 => {
for _ in 0..RP {
NumStr::hex_default(fast_random())
.set_resize_len::<L>()
.encode_to_bytes_buf(string);
}
if LP > 0 {
debug_assert!(LP <= 16, "LP should be 0..=16");
NumStr::hex_default(fast_random())
.set_resize_len::<LP>()
.encode_to_bytes_buf(string);
}
}
0 => {}
_ => {
#[cfg(any(debug_assertions, test))]
unreachable!("L should be 0..=16");
#[cfg(not(any(debug_assertions, test)))]
string.extend(
rand::thread_rng()
.sample_iter(&Slice::new(b"0123456789abcdef").unwrap())
.take(L * RP + LP),
);
}
}
}
#[inline]
fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
self.encode_to_bytes_buf(string);
string.extend(separator.as_bytes());
}
}
impl<const L: usize, const RP: usize, const LP: usize> StringExtT for RandHexStr<L, RP, LP> {}
impl RandHexStr {
#[inline]
pub const fn new_default() -> Self {
Self
}
}
impl<const L: usize, const RP: usize, const LP: usize> RandHexStr<L, RP, LP> {
#[inline]
pub const fn new() -> Self {
RandHexStr
}
#[inline]
pub const fn with_l<const NL: usize>(self) -> RandHexStr<NL, RP, LP> {
RandHexStr
}
#[inline]
pub const fn with_rp<const NRP: usize>(self) -> RandHexStr<L, NRP, LP> {
RandHexStr
}
#[inline]
pub const fn with_lp<const NLP: usize>(self) -> RandHexStr<L, RP, NLP> {
RandHexStr
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct RandStr<'r, const L: usize = 32>(&'r [u8]);
impl<const L: usize> StringT for RandStr<'_, L> {
#[inline]
fn encode_to_buf(self, string: &mut Vec<u8>) {
if self.0.is_empty() {
return;
}
string.extend(
rand::thread_rng()
.sample_iter(Slice::new(self.0).unwrap())
.take(L),
);
}
#[inline]
fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
if self.0.is_empty() {
return;
}
string.extend(
rand::thread_rng()
.sample_iter(Slice::new(self.0).unwrap())
.take(L),
);
string.extend(separator.as_bytes());
}
#[inline]
fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
if self.0.is_empty() {
return;
}
string.extend(
rand::thread_rng()
.sample_iter(Slice::new(self.0).unwrap())
.take(L),
);
}
#[inline]
fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
if self.0.is_empty() {
return;
}
string.extend(
rand::thread_rng()
.sample_iter(Slice::new(self.0).unwrap())
.take(L),
);
string.extend(separator.as_bytes());
}
}
impl<const L: usize> StringExtT for RandStr<'_, L> {}
impl<'r> RandStr<'r> {
#[inline]
pub const fn with_charset_default(charset: &'r [u8]) -> Self {
Self(charset)
}
}
impl<'r, const L: usize> RandStr<'r, L> {
#[inline]
pub const fn with_charset(charset: &'r [u8]) -> Self {
Self(charset)
}
#[inline]
pub const fn with_l<const NL: usize>(self) -> RandStr<'r, NL> {
RandStr(self.0)
}
}