use crate::{Markov, Wordlist};
use rangemap::RangeInclusiveMap;
use std::{fmt::Debug, ops::RangeInclusive, sync::Arc};
pub trait State {
type Wordlist: Clone + Debug + PartialEq;
type Markov: Clone + Debug + PartialEq;
type Preset: Clone + Debug + PartialEq;
type Literal: Clone + Debug + PartialEq;
type Characters: Clone + Debug + PartialEq;
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct Parsed;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Optimized;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Prepared;
impl State for Parsed {
type Wordlist = String;
type Markov = String;
type Preset = String;
type Literal = char;
type Characters = RangeInclusiveMap<u32, usize>;
}
impl State for Optimized {
type Wordlist = String;
type Markov = String;
type Preset = String;
type Literal = String;
type Characters = RangeInclusiveMap<u32, usize>;
}
impl State for Prepared {
type Wordlist = Arc<Wordlist>;
type Markov = Arc<Markov>;
type Preset = String;
type Literal = String;
type Characters = RangeInclusiveMap<u32, usize>;
}
#[derive(Debug, Clone, PartialEq)]
pub enum Pattern<S: State = Parsed> {
Group(Group<S>),
Set(Set<S>),
Special(Special<S>),
Literal(Literal<S>),
}
macro_rules! impl_from {
($type:ident) => {
impl<S: State> From<$type<S>> for Pattern<S> {
fn from(group: $type<S>) -> Self {
Self::$type(group)
}
}
};
}
impl_from!(Group);
impl_from!(Literal);
impl_from!(Set);
impl_from!(Special);
#[derive(Debug, Clone, PartialEq)]
pub struct Literal<S: State = Parsed> {
pub value: S::Literal,
}
impl Literal {
pub fn new(value: char) -> Self {
Self { value }
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Item<S: State = Parsed> {
pub pattern: Pattern<S>,
pub repeat: RangeInclusive<usize>,
pub optional: bool,
}
impl Item {
pub fn new<T: Into<Pattern>>(pattern: T) -> Self {
Self {
pattern: pattern.into(),
repeat: 1..=1,
optional: false,
}
}
pub fn optional(mut self, optional: bool) -> Self {
self.optional = optional;
self
}
pub fn repeat(mut self, repeat: RangeInclusive<usize>) -> Self {
self.repeat = repeat;
self
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Segment<S: State = Parsed> {
pub items: Vec<Item<S>>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Group<S: State = Parsed> {
pub segments: Vec<Segment<S>>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Set<S: State = Parsed> {
characters: S::Characters,
total: usize,
}
impl From<Set<Parsed>> for Set<Optimized> {
fn from(set: Set<Parsed>) -> Self {
Self {
characters: set.characters,
total: set.total,
}
}
}
impl From<Set<Optimized>> for Set<Prepared> {
fn from(set: Set<Optimized>) -> Self {
Self {
characters: set.characters,
total: set.total,
}
}
}
impl Set {
pub fn insert(&mut self, range: RangeInclusive<char>, count: usize) {
let range = (*range.start() as u32)..=(*range.end() as u32);
let length = range.end() + 1 - range.start();
let overlapping = self
.characters
.overlapping(&range)
.map(|(range, value)| (range.clone(), *value))
.collect::<Vec<_>>();
for (subrange, previous) in overlapping.into_iter() {
let subrange =
(*subrange.start().max(range.start()))..=(*subrange.end().min(range.end()));
self.characters.insert(subrange, previous + 1);
}
let gaps = self.characters.gaps(&range).collect::<Vec<_>>();
for range in gaps.into_iter() {
self.characters.insert(range, 1);
}
self.total += length as usize * count;
}
}
impl Set<Prepared> {
pub fn total(&self) -> usize {
self.total
}
pub fn characters(&self) -> impl Iterator<Item = (RangeInclusive<char>, usize)> + '_ {
self.characters.iter().map(|(range, count)| {
let start = char::from_u32(*range.start()).unwrap();
let end = char::from_u32(*range.end()).unwrap();
(start..=end, *count)
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Special<S: State = Parsed> {
Wordlist(S::Wordlist),
Markov(S::Markov),
Preset(S::Preset),
}
#[cfg(test)]
mod tests {
use super::*;
use test_strategy::*;
#[proptest]
fn test_set_total(ranges: Vec<(RangeInclusive<char>, u32)>) {
let total = ranges
.iter()
.map(|(r, count)| *count as usize * (*r.end() as usize + 1 - *r.start() as usize))
.sum();
let mut set = Set::<Parsed>::default();
ranges
.into_iter()
.for_each(|(range, count)| set.insert(range, count as usize));
assert_eq!(set.total, total);
}
#[proptest]
fn test_set_counts(ranges: Vec<(RangeInclusive<char>, u32)>) {
let total = ranges
.iter()
.map(|(r, count)| *count as usize * (*r.end() as usize + 1 - *r.start() as usize))
.sum();
let mut set = Set::<Parsed>::default();
ranges
.into_iter()
.for_each(|(range, count)| set.insert(range, count as usize));
assert_eq!(set.total, total);
}
}