commit aa03cb6dfc0299e75ee223137786234784e70ec3
parent e7a5f63a2da5414958e8d0cc03dee483e22639b7
Author: Yuval Langer <yuvallangerontheroad@gmail.com>
Date: Tue, 6 Sep 2022 22:57:45 +0000
Merge branch 'feature/macros' into 'master'
Implement generators using a macro
See merge request yuvallanger/rusty-diceware!3
Diffstat:
M | src/lib.rs | | | 121 | ++++++++++++++++++++++--------------------------------------------------------- |
M | tests/tests.rs | | | 78 | +++++++++++++++++++++++++++++++++--------------------------------------------- |
2 files changed, 66 insertions(+), 133 deletions(-)
diff --git a/src/lib.rs b/src/lib.rs
@@ -3,19 +3,9 @@ extern crate rand;
use rand::rngs::ThreadRng;
use rand::seq::SliceRandom;
use rand::Rng;
-use std::fmt;
include!(concat!(env!("OUT_DIR"), "/diceware.rs"));
-#[derive(Debug, Clone, Eq, PartialEq, Copy)]
-pub struct BealeWord(&'static str);
-
-#[derive(Debug, Clone, Eq, PartialEq, Copy)]
-pub struct ReinholdWord(&'static str);
-
-#[derive(Debug, Clone, Eq, PartialEq, Copy)]
-pub struct MiniLockWord(&'static str);
-
pub trait Word {
fn new(word: &'static str) -> Self;
@@ -26,86 +16,41 @@ pub trait Word {
}
}
-impl Word for BealeWord {
- fn new(word: &'static str) -> Self {
- Self(word)
- }
-
- fn entropy() -> f64 {
- (BEALE_WORDLIST.len() as f64).log2()
- }
-
- fn entropyn(n: u64) -> f64 {
- Self::entropy() * (n as f64)
- }
+macro_rules! create_generator {
+ ( $gen_name:ident, $wordlist: expr ) => {
+ #[derive(Debug, Clone, Eq, PartialEq, Copy)]
+ pub struct $gen_name(&'static str);
+ impl Word for $gen_name {
+ fn new(word: &'static str) -> Self {
+ $gen_name(word)
+ }
+
+ fn entropy() -> f64 {
+ ($wordlist.len() as f64).log2()
+ }
+
+ fn entropyn(n: u64) -> f64 {
+ Self::entropy() * (n as f64)
+ }
+ }
+
+ impl std::fmt::Display for $gen_name {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+ }
+
+ impl rand::distributions::Distribution<$gen_name> for rand::distributions::Standard {
+ fn sample<R: rand::Rng + ?Sized>(&self, mut rng: &mut R) -> $gen_name {
+ *$wordlist.choose(&mut rng).unwrap()
+ }
+ }
+ };
}
-impl Word for ReinholdWord {
- fn new(word: &'static str) -> Self {
- Self(word)
- }
-
- fn entropy() -> f64 {
- (REINHOLD_WORDLIST.len() as f64).log2()
- }
-
- fn entropyn(n: u64) -> f64 {
- Self::entropy() * (n as f64)
- }
-}
-
-impl Word for MiniLockWord {
- fn new(word: &'static str) -> Self {
- Self(word)
- }
-
- fn entropy() -> f64 {
- (MINILOCK_WORDLIST.len() as f64).log2()
- }
-
- fn entropyn(n: u64) -> f64 {
- Self::entropy() * (n as f64)
- }
-}
-
-impl rand::distributions::Distribution<BealeWord> for rand::distributions::Standard {
- fn sample<R: rand::Rng + ?Sized>(&self, mut rng: &mut R) -> BealeWord {
- *BEALE_WORDLIST.choose(&mut rng).unwrap()
- }
-}
-
-impl fmt::Display for BealeWord {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let Self(w) = self;
- write!(f, "{}", w)
- }
-}
-
-impl rand::distributions::Distribution<ReinholdWord> for rand::distributions::Standard {
- fn sample<R: rand::Rng + ?Sized>(&self, mut rng: &mut R) -> ReinholdWord {
- *REINHOLD_WORDLIST.choose(&mut rng).unwrap()
- }
-}
-
-impl fmt::Display for ReinholdWord {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let Self(w) = self;
- write!(f, "{}", w)
- }
-}
-
-impl rand::distributions::Distribution<MiniLockWord> for rand::distributions::Standard {
- fn sample<R: rand::Rng + ?Sized>(&self, mut rng: &mut R) -> MiniLockWord {
- *MINILOCK_WORDLIST.choose(&mut rng).unwrap()
- }
-}
-
-impl fmt::Display for MiniLockWord {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let Self(w) = self;
- write!(f, "{}", w)
- }
-}
+create_generator!(BealeWord, BEALE_WORDLIST);
+create_generator!(ReinholdWord, REINHOLD_WORDLIST);
+create_generator!(MiniLockWord, MINILOCK_WORDLIST);
pub fn print_words<T: Word + std::fmt::Display>(
word_num: &u64,
diff --git a/tests/tests.rs b/tests/tests.rs
@@ -8,50 +8,38 @@ use diceware::BealeWord;
use diceware::ReinholdWord;
use diceware::Word;
-fn make_beale_vector() -> Vec<BealeWord> {
- let seed: [u8; 32] = [0; 32];
- let mut rng: StdRng = SeedableRng::from_seed(seed);
-
- let mut beale_vector: Vec<BealeWord> = vec![];
- for _ in 0..4 {
- let word: BealeWord = rng.gen();
- beale_vector.push(word);
- }
- beale_vector
+macro_rules! create_test {
+ ( $gen_name: ident, $test_name: ident, $expected: expr ) => {
+ #[test]
+ fn $test_name() {
+ fn make_vektor() -> Vec<$gen_name> {
+ let seed: [u8; 32] = [0; 32];
+ let mut rng: StdRng = SeedableRng::from_seed(seed);
+
+ let mut vector: Vec<$gen_name> = vec![];
+ for _ in 0..4 {
+ let word: $gen_name = rng.gen();
+ vector.push(word);
+ }
+ vector
+ }
+ let wanted: Vec<$gen_name> = $expected.into_iter().map($gen_name::new).collect();
+
+ let got = make_vektor();
+
+ assert_eq!(got, wanted);
+ }
+ };
}
-fn make_reinhold_vector() -> Vec<ReinholdWord> {
- let seed: [u8; 32] = [0; 32];
- let mut rng: StdRng = SeedableRng::from_seed(seed);
-
- let mut reinhold_vector: Vec<ReinholdWord> = vec![];
- for _ in 0..4 {
- let word: ReinholdWord = rng.gen();
- reinhold_vector.push(word);
- }
- reinhold_vector
-}
-
-#[test]
-fn beale_rng_test() {
- let wanted: Vec<BealeWord> = vec!["io", "gavel", "beam", "time"]
- .into_iter()
- .map(BealeWord::new)
- .collect();
-
- let got = make_beale_vector();
-
- assert_eq!(got, wanted);
-}
-
-#[test]
-fn reinhold_rng_test() {
- let wanted: Vec<ReinholdWord> = vec!["india", "gamma", "bcd", "theme"]
- .into_iter()
- .map(ReinholdWord::new)
- .collect();
-
- let got = make_reinhold_vector();
-
- assert_eq!(got, wanted);
-}
+create_test!(
+ BealeWord,
+ beale_rng_test,
+ vec!["io", "gavel", "beam", "time"]
+);
+
+create_test!(
+ ReinholdWord,
+ reinhold_rng_test,
+ vec!["india", "gamma", "bcd", "theme"]
+);