random username function (for later)

This commit is contained in:
Brandon Thomas committed 2024-09-16 20:27:11 -04:00
1 parent ec4fc294a9
commit 3a3f1aef14
8 files changed
+125 -53

No files matched your search

@@ -2,20 +2,12 @@
/// Read lines from a file in an iterator.
/// Remove comment lines prefixed with `#`.
pub fn iterate_trimmed_lines_without_comments<'a>(iterator: impl Iterator<Item=&'a str>)
-> impl Iterator<Item=String>
//-> impl Iterator<Item = &'a str>
pub fn iterate_trimmed_lines_without_comments<'a>(iterator: impl IntoIterator<Item=&'a str>)
-> impl Iterator<Item = &'a str>
{
let f = iterator
.into_iter()
.map(|line| line.trim().to_string())
.collect::<Vec<_>>();
let f = f.into_iter()
iterator.into_iter()
.map(|line| line.trim())
.filter(|line| !(line.starts_with("#") || line.is_empty()))
.collect::<Vec<_>>();
f.into_iter()
}
#[cfg(test)]
@@ -40,13 +32,11 @@ mod tests {
let lines = contents.lines();
let lines = iterate_trimmed_lines_without_comments(lines);
let lines: Vec<String> = lines.collect();
assert_eq!(
lines,
lines.collect::<Vec<_>>(),
vec![
"127.0.0.0/24".to_string(),
"192.168.0.0/24".to_string(),
"127.0.0.0/24",
"192.168.0.0/24",
]);
}
}
+1
View File
@@ -23,6 +23,7 @@ pub mod iterators;
pub mod lazy_any_option_true;
pub mod numerics;
pub mod optional_false_to_none;
pub mod str;
pub mod str_to_bool;
pub mod traits;
pub mod trim_or_empty;
@@ -0,0 +1,37 @@
/// Converts the first letter of a string to uppercase.
/// eg, "foobar" is converted to "Foobar".
/// From https://stackoverflow.com/a/53570840
pub fn first_letter_uppercase(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
}
#[cfg(test)]
mod tests {
use crate::str::first_letter_uppercase::first_letter_uppercase;
#[test]
fn empty() {
assert_eq!(first_letter_uppercase(""), "");
}
#[test]
fn lowercase() {
assert_eq!(first_letter_uppercase("f"), "F");
assert_eq!(first_letter_uppercase("foo"), "Foo");
assert_eq!(first_letter_uppercase("fOO"), "FOO");
assert_eq!(first_letter_uppercase("asdf"), "Asdf");
}
#[test]
fn uppercase() {
assert_eq!(first_letter_uppercase("F"), "F");
assert_eq!(first_letter_uppercase("Foo"), "Foo");
assert_eq!(first_letter_uppercase("FOO"), "FOO");
assert_eq!(first_letter_uppercase("ASDF"), "ASDF");
}
}
@@ -0,0 +1 @@
pub mod first_letter_uppercase;
@@ -1,35 +1,39 @@
use filesys::file_lines::iterate_trimmed_file_lines_without_comments::iterate_trimmed_file_lines_without_comments;
use once_cell::sync::Lazy;
use std::collections::HashSet;
use collections::random_from_array::random_from_array;
use primitives::iterators::iterate_trimmed_lines_without_comments::iterate_trimmed_lines_without_comments;
use crate::http_server::validations::validate_username::USERNAME_MAX_LENGTH;
use collections::random_from_array::random_from_array;
use once_cell::sync::Lazy;
use primitives::iterators::iterate_trimmed_lines_without_comments::iterate_trimmed_lines_without_comments;
use primitives::str::first_letter_uppercase::first_letter_uppercase;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use std::collections::HashSet;
pub const ADJECTIVES : &str = include_str!("../../../../../../includes/binary_includes/usernames/atoms/username_adjectives.txt");
pub const NOUNS : &str = include_str!("../../../../../../includes/binary_includes/usernames/atoms/username_nouns.txt");
pub const NOUNS_ANIMALS: &str = include_str!("../../../../../../includes/binary_includes/usernames/atoms/username_nouns_animals.txt");
fn lines_without_comments() {
}
static ALL_NOUNS : Lazy<Vec<String>> = Lazy::new(|| {
static ALL_NOUNS : Lazy<Vec<&'static str>> = Lazy::new(|| {
iterate_trimmed_lines_without_comments(NOUNS.lines())
.chain(iterate_trimmed_lines_without_comments(NOUNS_ANIMALS.lines()))
.collect::<HashSet<String>>()
.collect::<HashSet<&'static str>>()
.into_iter()
.collect()
});
static ALL_ADJECTIVES : Lazy<Vec<String>> = Lazy::new(|| {
static ALL_ADJECTIVES : Lazy<Vec<&'static str>> = Lazy::new(|| {
iterate_trimmed_lines_without_comments(ADJECTIVES.lines())
.collect::<HashSet<String>>()
.collect::<HashSet<&'static str>>()
.into_iter()
.collect::<Vec<String>>()
.collect::<Vec<&'static str>>()
});
/// Generate a random username for onboarding purposes.
/// This function is infallible and will always return a possible username.
pub fn generate_random_username() -> String {
for _ in 0..100 {
if let Some(username) = generate_candidate_username() {
if username.len() > USERNAME_MAX_LENGTH {
continue;
}
return username;
}
}
@@ -37,20 +41,59 @@ pub fn generate_random_username() -> String {
"random_username".to_string()
}
fn generate_candidate_username() -> Option<String> {
let maybe_adjective = random_from_array::<String>(&ALL_ADJECTIVES);
let maybe_noun = random_from_array::<String>(&ALL_NOUNS);
enum UsernameFormat {
CamelCase,
KebabCase,
SnakeCase,
CamelKebabCase,
CamelSnakeCase,
}
match (maybe_adjective, maybe_noun) {
(Some(adjective), Some(noun)) => {
let maybe_username = format!("{}{}", adjective, noun);
if maybe_username.len() > USERNAME_MAX_LENGTH {
println!("too long: {}", maybe_username);
return None;
}
Some(maybe_username)
},
_ => None
impl Distribution<UsernameFormat> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UsernameFormat {
match rng.gen_range(0..=4) {
0 => UsernameFormat::CamelCase,
1 => UsernameFormat::KebabCase,
2 => UsernameFormat::SnakeCase,
3 => UsernameFormat::CamelKebabCase,
_ => UsernameFormat::CamelSnakeCase,
}
}
}
fn generate_candidate_username() -> Option<String> {
let adjective = random_from_array(&ALL_ADJECTIVES)?;
let noun = random_from_array(&ALL_NOUNS)?;
let format : UsernameFormat = rand::random();
let mut candidate_username = match format {
UsernameFormat::CamelCase => format!("{}{}", first_letter_uppercase(adjective), first_letter_uppercase(noun)),
UsernameFormat::KebabCase => format!("{}-{}", adjective, noun),
UsernameFormat::SnakeCase => format!("{}_{}", adjective, noun),
UsernameFormat::CamelKebabCase => format!("{}-{}", first_letter_uppercase(adjective), first_letter_uppercase(noun)),
UsernameFormat::CamelSnakeCase => format!("{}_{}", first_letter_uppercase(adjective), first_letter_uppercase(noun)),
};
if let Some(digit) = random_digit() {
candidate_username = match format {
UsernameFormat::CamelCase => format!("{}{}", candidate_username, digit),
UsernameFormat::KebabCase | UsernameFormat::CamelKebabCase => format!("{}-{}", candidate_username, digit),
UsernameFormat::SnakeCase | UsernameFormat::CamelSnakeCase => format!("{}_{}", candidate_username, digit),
};
}
Some(candidate_username)
}
fn random_digit() -> Option<u32> {
// Give uniform probability for the number of digits
let num_digits = rand::thread_rng().gen_range(0..5u8);
match num_digits {
0 => None,
1 => Some(rand::thread_rng().gen_range(0..10)),
2 => Some(rand::thread_rng().gen_range(10..100)),
3 => Some(rand::thread_rng().gen_range(100..1000)),
4 => Some(rand::thread_rng().gen_range(1000..10000)),
_ => Some(rand::thread_rng().gen_range(10000..100000)),
}
}
@@ -59,7 +102,7 @@ mod tests {
use crate::util::generate_random_username::generate_random_username;
#[test]
fn test() {
assert_eq!(generate_random_username(), "asdf".to_string());
fn test_base_case_success() {
assert!(generate_random_username().len() > 0);
}
}
@@ -1,5 +1,5 @@
-- From https://gist.github.com/hugsy/8910dc78d208e40de42deb29e62df913#file-english-adjectives-txt
-- This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
# From https://gist.github.com/hugsy/8910dc78d208e40de42deb29e62df913#file-english-adjectives-txt
# This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
able
absolute
@@ -1,6 +1,6 @@
-- From https://gist.github.com/hugsy/8910dc78d208e40de42deb29e62df913
-- https://gist.githubusercontent.com/hugsy/8910dc78d208e40de42deb29e62df913/raw/eec99c5597a73f6a9240cab26965a8609fa0f6ea/english-nouns.txt
-- This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
# From https://gist.github.com/hugsy/8910dc78d208e40de42deb29e62df913
# https://gist.githubusercontent.com/hugsy/8910dc78d208e40de42deb29e62df913/raw/eec99c5597a73f6a9240cab26965a8609fa0f6ea/english-nouns.txt
# This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
ability
account
@@ -1,6 +1,6 @@
-- From: https://github.com/jneidel/animal-names
-- https://github.com/jneidel/animal-names/blob/master/animals-common.txt
-- This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
# From: https://github.com/jneidel/animal-names
# https://github.com/jneidel/animal-names/blob/master/animals-common.txt
# This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices
alligator
alpaca