entroll 0.1.2

Generate random passwords and print entropy in bits.
Documentation
use entroll_core::Faces;
use entroll_dictionaries::{AsciiDictionary, AsciiDictionaryWrapper, WordList};
use itertools::Itertools;
use rand::distributions::Distribution;

pub trait Mkpasswd<S>: Faces + rand::distributions::Distribution<S>
where
    Self: Sized,
    S: core::fmt::Display,
{
    fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
        &self,
        len: usize,
        rng: &mut Rng,
    ) -> String {
        self.sample_iter(rng).take(len).join("")
    }

    fn mkpasswd_entropy_bits<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
        &self,
        bits: f64,
        rng: &mut Rng,
    ) -> String {
        let len = self.needs_faces(bits);
        self.mkpasswd(len, rng)
    }
}

fn camel_case(mut s: String) -> String {
    let last = s.split_off(1);
    s.to_uppercase() + &last
}

impl<const N: usize> Mkpasswd<String> for WordList<N> {
    fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
        &self,
        len: usize,
        rng: &mut Rng,
    ) -> String {
        self.sample_iter(rng).take(len).map(camel_case).join("")
    }
}
impl<T> Mkpasswd<u8> for AsciiDictionaryWrapper<T>
where
    T: AsciiDictionary,
{
    fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
        &self,
        len: usize,
        rng: &mut Rng,
    ) -> String {
        self.sample_iter(rng).take(len).map(|c| c as char).collect()
    }
}

pub trait ErasedMkpasswd {
    fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String;
    fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String;
}

impl<const N: usize> ErasedMkpasswd for WordList<N> {
    fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String {
        Mkpasswd::<String>::mkpasswd(self, len, rng)
    }
    fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String {
        Mkpasswd::<String>::mkpasswd_entropy_bits(self, bits, rng)
    }
}

impl<T> ErasedMkpasswd for AsciiDictionaryWrapper<T>
where
    T: AsciiDictionary,
{
    fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String {
        Mkpasswd::<u8>::mkpasswd(self, len, rng)
    }
    fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String {
        Mkpasswd::<u8>::mkpasswd_entropy_bits(self, bits, rng)
    }
}