use crate::uuid::UUID;
use rand::Rng;
pub const NUMBERS: &str = "0123456789";
pub const LETTERS: &str = "abcdefghijklmnopqrstuvwxyz";
pub const HEX_LETTERS: &str = "abcdef";
pub const SAFE_SP_CHARS: &str = "-_.()~@";
pub const UNSAFE_SP_CHARS: &str = r#"#%&*+={}\/<>?!$:'"`|"#;
#[derive(Debug, Copy, Clone)]
pub struct GenCharOpts {
pub nums: bool,
pub letters: bool,
pub upper: bool,
pub safe_sp_chars: bool,
pub unsafe_sp_chars: bool,
}
fn gen_uuid_nonstandard_char() -> char {
let opts = GenCharOpts {
nums: true,
letters: true,
upper: false,
safe_sp_chars: false,
unsafe_sp_chars: false,
};
char(opts)
}
fn gen_uuid_v4_char() -> char {
let mut charset = String::from("");
charset.push_str(NUMBERS);
charset.push_str(HEX_LETTERS);
get_char_from_set(&charset)
}
fn get_char_from_set(charset: &str) -> char {
let mut rng = rand::thread_rng();
let idx = rng.gen_range(0..charset.len());
let c = charset
.chars()
.nth(idx)
.expect("Could not get value of char.");
c
}
pub fn get_charset_from_opts(opts: GenCharOpts) -> String {
let mut charset = String::from("");
if opts.nums {
charset.push_str(NUMBERS);
}
if opts.letters {
charset.push_str(LETTERS);
if opts.upper {
charset.push_str(&LETTERS.to_uppercase());
}
}
if opts.safe_sp_chars {
charset.push_str(SAFE_SP_CHARS);
}
if opts.unsafe_sp_chars {
charset.push_str(UNSAFE_SP_CHARS);
}
charset
}
pub fn char(opts: GenCharOpts) -> char {
let charset = get_charset_from_opts(opts);
get_char_from_set(&charset)
}
pub fn char_uuid(version: UUID) -> char {
match version {
UUID::V4 => gen_uuid_v4_char(),
UUID::Nonstandard => gen_uuid_nonstandard_char(),
}
}
pub fn char_custom(charset: &str) -> char {
get_char_from_set(charset)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{test_correct_chars, test_correct_uuid_chars};
#[test]
fn test_get_char_from_set() {
let charset = "abc123";
let mut success = true;
for _i in 1..=10 {
if !success {
break;
}
let char = get_char_from_set(charset);
success = test_correct_chars(String::from(char), charset)
}
if !success {
panic!("get_char_from_set() generated an invalid character.");
}
}
#[test]
fn test_char() {
let opts = GenCharOpts {
nums: true,
letters: true,
upper: true,
safe_sp_chars: false,
unsafe_sp_chars: false,
};
let charset = get_charset_from_opts(opts);
let mut success = true;
for _i in 1..=10 {
if !success {
break;
}
let char = char(opts);
success = test_correct_chars(String::from(char), &charset)
}
if !success {
panic!("char() generated an invalid character.");
}
}
fn test_uuid_char(version: UUID) -> bool {
let mut success = true;
for _i in 1..=10 {
if !success {
break;
}
let chunk = match version {
UUID::V4 => String::from(gen_uuid_v4_char()),
UUID::Nonstandard => String::from(gen_uuid_nonstandard_char()),
};
success = test_correct_uuid_chars(version, chunk);
}
success
}
#[test]
fn test_uuid4_char() {
let version = UUID::V4;
let success = test_uuid_char(version);
if !success {
panic!("gen_uuid_v4_char() generated an invalid character.");
}
}
#[test]
fn test_uuidn_char() {
let version = UUID::Nonstandard;
let success = test_uuid_char(version);
if !success {
panic!(
"gen_uuid_nonstandard_char() generated an invalid character."
);
}
}
}