mod words;
pub const WORDS: &[&str] = words::LIST;
pub const JAVASCRIPT: &str = include_str!("../memorable-wordlist.js");
const NUM_BITS: usize = 14;
fn words_for_bits(bits: usize) -> impl Iterator<Item=&'static str> {
use rand::seq::SliceRandom;
let num_words = if bits % NUM_BITS == 0 { bits/NUM_BITS } else { bits/NUM_BITS + 1 };
let number_per_word = (bits as f64/num_words as f64).exp2() as usize;
let mut words = Vec::with_capacity(num_words);
let mut rng = rand::thread_rng();
for _ in 0..num_words {
words.push(WORDS[0..number_per_word].choose(&mut rng).unwrap());
}
words.into_iter().map(|&x| x)
}
pub fn space_delimited(bits: usize) -> String {
let mut code = String::new();
for w in words_for_bits(bits) {
code.push_str(w);
code.push(' ');
}
code.pop();
code
}
pub fn snake_case(bits: usize) -> String {
let mut code = String::new();
for w in words_for_bits(bits) {
code.push_str(w);
code.push('_');
}
code.pop();
code
}
pub fn kebab_case(bits: usize) -> String {
let mut code = String::new();
for w in words_for_bits(bits) {
code.push_str(w);
code.push('-');
}
code.pop();
code
}
pub fn camel_case(bits: usize) -> String {
let mut code = String::new();
for w in words_for_bits(bits) {
let mut c = w.chars();
code.push(c.next().unwrap().to_uppercase().next().unwrap());
code.push_str(c.as_str());
}
code
}
#[test]
fn has_length() {
assert!(space_delimited(41).len() > 4);
assert!(snake_case(40).len() > 4);
assert!(camel_case(40).len() > 4);
assert!(kebab_case(40).len() > 4);
}
#[test]
fn num_bits_correct() {
assert!(1 << NUM_BITS <= WORDS.len());
}