passgen-cli 0.2.0

Password generator with a regular-expression-like syntax
Documentation
use clap::{Args, Parser, ValueEnum};
use passgen::{
    pattern::Pattern,
    random::{Random, RandomSource},
    Config, DataStore,
};
use passgen_cli::*;
use std::{path::PathBuf, str::FromStr};

fn main() {
    let options = Options::parse();
    let mut config = Config::default();

    for wordlist in &options.wordlist {
        config.wordlist_add(&wordlist.name, &wordlist.path);
    }

    // get randomness source
    let random = options.random();

    // parse pattern
    let pattern = Pattern::parse(&options.pattern.unwrap()).unwrap();

    // optimize pattern and get dependencies
    let (pattern, dependencies) = pattern.optimize();

    // resolve dependencies and load in data store
    let mut data = DataStore::default();
    for dependency in &dependencies {
        data.resolve(&config, dependency).unwrap();
    }

    let pattern = pattern.prepare(&data).unwrap();

    if let Some(threads) = options.threads {
        use std::sync::{atomic::*, *};
        let pattern = Arc::new(pattern);
        let counter = Arc::new(AtomicUsize::new(0));
        let amount = options.amount;

        let (sender, receiver) = mpsc::sync_channel(1024);
        let threads = (0..threads)
            .map(move |_index| {
                let random = random.clone();
                let counter = counter.clone();
                let pattern = pattern.clone();
                let sender = sender.clone();
                std::thread::spawn(move || {
                    loop {
                        let index = counter.fetch_add(1, Ordering::SeqCst);
                        if index >= options.amount {
                            break;
                        }

                        let mut rng = random.get_rng_boxed(index);
                        let output = pattern.generate(&mut rng).unwrap();
                        sender.send(output);
                    }
                    drop(sender);
                })
            })
            .collect::<Vec<_>>();

        while let Ok(message) = receiver.recv() {
            println!("{message}");
        }

        for thread in threads {
            thread.join().unwrap();
        }
    } else {
        for index in 0..options.amount {
            let mut rng = random.get_rng_boxed(index);
            let output = pattern.generate(&mut rng).unwrap();
            println!("{output}");
        }
    }
}