use super::pattern::*;
use rand::{Rng, RngCore};
use std::fmt::Write;
type Pattern = super::pattern::Pattern<Prepared>;
type Group = super::pattern::Group<Prepared>;
type Set = super::pattern::Set<Prepared>;
type Segment = super::pattern::Segment<Prepared>;
type Item = super::pattern::Item<Prepared>;
type Special = super::pattern::Special<Prepared>;
type Literal = super::pattern::Literal<Prepared>;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("abc")]
Write(#[from] std::fmt::Error),
}
pub trait Generate {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error>;
}
impl Pattern {
pub fn generate(&self, rng: &mut dyn RngCore) -> Result<String, Error> {
let mut output = String::new();
Generate::generate(self, rng, &mut output)?;
Ok(output)
}
}
impl Generate for Pattern {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
match self {
Pattern::Group(group) => group.generate(rand, output),
Pattern::Set(set) => set.generate(rand, output),
Pattern::Literal(literal) => literal.generate(rand, output),
Pattern::Special(special) => special.generate(rand, output),
}
}
}
impl Generate for Group {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
let index = rand.gen_range(0..self.segments.len());
self.segments[index].generate(rand, output)
}
}
impl Generate for Segment {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
let mut entropy = 1.0;
for item in &self.items {
entropy *= item.generate(rand, output)?;
}
Ok(entropy)
}
}
impl Generate for Item {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
if self.optional && rand.gen::<bool>() {
return Ok(1.0);
}
let amount = rand.gen_range(self.repeat.clone());
let mut entropy = 1.0;
for _ in 0..amount {
entropy *= Generate::generate(&self.pattern, rand, output)?;
}
Ok(entropy)
}
}
impl Generate for Literal {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
output.write_str(&self.value)?;
Ok(1.0)
}
}
impl Generate for Special {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
match self {
Self::Wordlist(list) => {
let mut index = rand.gen_range(0..list.total());
for (word, count) in list.iter() {
if index < count {
output.write_str(word)?;
return Ok(list.total() as f64 / count as f64);
}
index -= count;
}
unreachable!()
}
Self::Markov(markov) => {
let mut window = markov.window();
let mut total_entropy = 1f64;
while let (Some(character), entropy) = markov.generate(rand, &mut window) {
output.write_char(character)?;
total_entropy *= entropy;
}
Ok(total_entropy)
}
_ => todo!(),
}
}
}
impl Generate for Set {
fn generate(&self, rand: &mut dyn RngCore, output: &mut dyn Write) -> Result<f64, Error> {
let mut index = rand.gen_range(0..self.total());
for (c, count) in self
.characters()
.flat_map(|(range, count)| range.map(move |c| (c, count)))
{
if index < count {
output.write_char(c)?;
return Ok(self.total() as f64 / count as f64);
}
index -= count;
}
unreachable!()
}
}