commit e4b4eaeedf6fe783e583d36685943a00e8e1b340
parent a0e2eb496e425865322875462c4cd8be5b31c0c5
Author: Yuval Langer <yuval.langer@gmail.com>
Date: Wed, 6 Nov 2024 20:21:53 +0200
Convert both word generating methods - RNG and die casting - into two Iterator types.
Diffstat:
M | src/main.rs | | | 164 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
1 file changed, 81 insertions(+), 83 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -66,42 +66,30 @@ fn unknown_wordlist(wordlist_name: &str) -> ! {
exit(-1)
}
-fn print_words(
- words: &Vec<String>,
- delimiter: char,
-) {
- for word in 0..(words.len() - 1) {
- print!("{}{}", words[word], delimiter);
- }
- print!("{}", words[words.len() - 1]);
+struct ReadWordDieCasts<'a, T> {
+ bytes_iter: &'a mut std::io::Bytes<T>,
+ wordlist: &'a Vec<&'a str>,
+}
- println!();
+impl<T> ReadWordDieCasts<'_, T> {
+ fn new<'a, D>(
+ bytes_iter: &'a mut std::io::Bytes<T>,
+ wordlist: &'a Vec<&'a str>,
+ ) -> ReadWordDieCasts<'a, T> {
+ ReadWordDieCasts {
+ bytes_iter,
+ wordlist,
+ }
+ }
}
-// struct ReadWords<'a, T: std::iter::Iterator> {
-// bytes_iter: &'a mut std::io::Bytes<T>,
-// wordlist: &'a Vec<&'a str>
-// }
-
-// impl<'a, T: std::iter::Iterator> ReadWords<'a, T> {
-// fn new(
-// bytes_iter: &'a mut std::io::Bytes<T>,
-// wordlist: &'a Vec<&'a str>
-// ) -> ReadWords<'a, T> {
-// ReadWords {
-// bytes_iter,
-// wordlist,
-// }
-// }
-// }
-
-// impl<'a, T: std::iter::Iterator<Item = Result<u8, std::io::Error>> + std::fmt::Display + std::io::Read> Iterator for ReadWords<'a, T> {
-// type Item = String;
-
-// fn next(&mut self) -> Option<<Self as Iterator>::Item> {
-// return read_single_word::<T, T>(self.bytes_iter, self.wordlist);
-// }
-// }
+impl<T: std::io::Read> Iterator for ReadWordDieCasts<'_, T> {
+ type Item = String;
+
+ fn next(&mut self) -> Option<<ReadWordDieCasts<T> as Iterator>::Item> {
+ return read_single_word(self.bytes_iter, self.wordlist);
+ }
+}
fn read_single_word<T>(
bytes_iter: &mut std::io::Bytes<T>,
@@ -196,28 +184,6 @@ fn read_single_word<T>(
return Some(wordlist[word_index].to_string());
}
-fn read_words_from_rolls(
- wordlist: &Vec<&str>,
-) -> Vec<String> {
- let stdin = std::io::stdin();
- let mut words = Vec::new();
- let mut bytes_iter = stdin.bytes();
-
- loop {
- match read_single_word(&mut bytes_iter, wordlist) {
- Some(word) => words.push(word),
- None => break,
- };
- };
-
- // TODO: Maybe use an iterator?
- // for word in ReadWords::new(&mut bytes_iter, wordlist) {
- // words.push(word)
- // };
-
- words
-}
-
fn entropy(wordlist: &[&str]) -> f64 {
(wordlist.len() as f64).log2()
}
@@ -226,23 +192,29 @@ fn entropyn(wordlist: Vec<&str>, n: u64) -> f64 {
entropy(&wordlist) * (n as f64)
}
-fn read_rng_rolls(
- rng: &mut ThreadRng,
- wordlist: &Vec<&str>,
- word_num: u64,
-) -> Vec<String> {
- /*
- From base 6 conversion:
- (0..6).pow(1) = (0, 1, ..6)
- (0..6).pow(2) = (0, 6, ..36)
- (0..6).pow(3) = (0, 36, ..216)
- */
-
- return (0..word_num)
- .collect::<Vec<_>>()
- .iter()
- .map(|_| wordlist[rng.gen_range(0..wordlist.len())].to_string())
- .collect();
+struct ReadRngWord<'a> {
+ rng: &'a mut ThreadRng,
+ wordlist: &'a Vec<&'a str>,
+}
+
+impl<'a> ReadRngWord<'a> {
+ fn new(
+ rng: &'a mut ThreadRng,
+ wordlist: &'a Vec<&'a str>,
+ ) -> ReadRngWord<'a> {
+ ReadRngWord {
+ rng,
+ wordlist,
+ }
+ }
+}
+
+impl<'a> Iterator for ReadRngWord<'a> {
+ type Item = String;
+
+ fn next(&mut self) -> Option<String> {
+ Some(self.wordlist[self.rng.gen_range(0..self.wordlist.len())].to_string())
+ }
}
fn load_wordlist_file(filepath: &str) -> String {
@@ -315,23 +287,49 @@ fn main() {
wordlist_name.get_list().to_vec()
};
- let words = if is_physical_rolls {
- read_words_from_rolls(&wordlist)
+ if is_physical_rolls {
+ let stdin = std::io::stdin();
+ let mut bytes_iter = stdin.bytes();
+
+ let mut words = ReadWordDieCasts::new::<std::io::Bytes<std::io::Stdin>>(&mut bytes_iter, &wordlist);
+
+ if let Some(word) = words.next() {
+ print!("{}", word);
+
+ let words_count = 1;
+
+ for word in words {
+ print!("{}{}", delimiter, word);
+ }
+ println!();
+
+ if is_entropy_printed {
+ println!("{}", entropyn(wordlist, words_count));
+ }
+ };
} else if word_num != 0 {
let mut rng = thread_rng();
- read_rng_rolls(&mut rng, &wordlist, word_num)
+
+ let mut words = ReadRngWord::new(&mut rng, &wordlist);
+
+ print!("{}", words.next().unwrap());
+
+ let mut words_count = 1;
+
+ for _ in 1..word_num {
+ print!("{}{}", delimiter, words.next().unwrap());
+ words_count += 1;
+ };
+
+ println!();
+
+ if is_entropy_printed {
+ println!("{}", entropyn(wordlist, words_count));
+ }
} else {
print_usage(program, opts);
exit(-1);
};
-
- if words.len() > 0 {
- print_words(&words, delimiter);
- }
-
- if is_entropy_printed {
- println!("{}", entropyn(wordlist, words.len() as u64));
- }
}
#[cfg(test)]