#![allow(non_camel_case_types)]
use crate::Iter;
use std::{
fmt::Display,
mem,
ops::{Add, AddAssign, BitOr, BitOrAssign, Mul, MulAssign},
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Generator {
AlphaLower,
AlphaUpper,
Digit,
AlphaNumLower,
AlphaNumUpper,
HexUpper,
HexLower,
Char(char),
Str(String),
OneOf {
v: Vec<Generator>,
is_optional: bool,
},
RepeatedN(Box<Generator>, usize),
RepeatedMN(Box<Generator>, usize, usize),
Sequence(Vec<Generator>),
}
impl Generator {
const ASCII_LOWER_A: u8 = 97;
const ASCII_UPPER_A: u8 = 65;
const ASCII_0: u8 = 48;
pub fn regex(&self) -> String {
use Generator::*;
match self {
AlphaLower => "[a-z]".into(),
AlphaUpper => "[A-Z]".into(),
Digit => "\\d".into(),
AlphaNumUpper => "[A-Z\\d]".into(),
AlphaNumLower => "[a-z\\d]".into(),
HexUpper => "[\\dA-F]".into(),
HexLower => "[\\da-f]".into(),
Char(c) => match c {
&'.' => "\\.".into(),
c => String::from(*c),
},
Str(s) => s.replace(".", "\\."),
OneOf { v, is_optional } => {
let regexes = v.iter().map(|a| a.regex()).collect::<Vec<_>>();
let mut grp = format!("({})", regexes.join("|"));
if *is_optional {
grp.push('?');
}
grp
}
RepeatedN(a, n) => a.regex() + &"{" + &n.to_string() + &"}",
RepeatedMN(a, m, n) => a.regex() + &"{" + &m.to_string() + &"," + &n.to_string() + &"}",
Sequence(v) => {
let regexes = v.iter().map(|a| a.regex()).collect::<Vec<_>>();
regexes.join("")
}
}
}
pub fn len(&self) -> u128 {
use Generator::*;
match self {
AlphaLower | AlphaUpper => 26,
Digit => 10,
AlphaNumUpper | AlphaNumLower => 36,
HexUpper | HexLower => 16,
Char(_) | Str(_) => 1,
OneOf { v, is_optional } => {
v.iter().map(|a| a.len()).sum::<u128>() + if *is_optional { 1 } else { 0 }
}
RepeatedN(a, n) => a.len().pow(*n as u32),
RepeatedMN(a, m, n) => {
let base = a.len();
(*m..=*n).map(|i| base.pow(i as u32)).sum()
}
Sequence(v) => v.iter().map(|a| a.len()).fold(1, |acc, n| acc * n),
}
}
fn generate_on_top_of(&self, num: &mut u128, result: &mut String) {
use Generator::*;
match self {
AlphaLower => {
let i = (*num % 26) as u8;
*num /= 26;
let c: char = (Self::ASCII_LOWER_A + i).into();
result.push(c);
}
AlphaUpper => {
let i = (*num % 26) as u8;
*num /= 26;
let c: char = (Self::ASCII_UPPER_A + i).into();
result.push(c);
}
Digit => {
let i = (*num % 10) as u8;
*num /= 10;
let c: char = (Self::ASCII_0 + i).into();
result.push(c);
}
AlphaNumUpper => {
let i = (*num % 36) as u8;
*num /= 36;
let c: char = if i < 26 {
Self::ASCII_UPPER_A + i
} else {
Self::ASCII_0 + i - 26
}
.into();
result.push(c);
}
AlphaNumLower => {
let i = (*num % 36) as u8;
*num /= 36;
let c: char = if i < 26 {
Self::ASCII_LOWER_A + i
} else {
Self::ASCII_0 + i - 26
}
.into();
result.push(c);
}
HexUpper => {
let i = (*num % 16) as u8;
*num /= 16;
let c: char = if i < 10 {
Self::ASCII_0 + i
} else {
Self::ASCII_UPPER_A + i - 10
}
.into();
result.push(c);
}
HexLower => {
let i = (*num % 16) as u8;
*num /= 16;
let c: char = if i < 10 {
Self::ASCII_0 + i
} else {
Self::ASCII_LOWER_A + i - 10
}
.into();
result.push(c);
}
Char(c) => {
result.push(*c);
}
Str(s) => {
result.push_str(s);
}
OneOf { v, is_optional } => {
let v_len = self.len();
let new_num = *num / v_len;
*num %= v_len;
if *is_optional && *num == 0 {
} else {
if *is_optional {
*num -= 1;
}
for a in v {
let a_len = a.len() as u128;
if *num < a_len {
a.generate_on_top_of(num, result);
break;
} else {
*num -= a_len;
}
}
}
*num = new_num;
}
RepeatedN(a, n) => {
let mut parts = Vec::with_capacity(*n);
for _ in 0..*n {
let mut r = String::new();
a.generate_on_top_of(num, &mut r);
parts.push(r);
}
parts.reverse();
result.push_str(&parts.join(""));
}
RepeatedMN(a, m, n) => {
let mut parts = Vec::with_capacity(n - m + 1);
for _ in *m..=*n {
let mut r = String::new();
a.generate_on_top_of(num, &mut r);
parts.push(r);
}
parts.reverse();
result.push_str(&parts.join(""));
}
Sequence(v) => {
for a in v {
a.generate_on_top_of(num, result);
}
}
}
}
pub fn generate_exact(&self, num: u128) -> String {
let range = self.len();
assert!(num < range);
let mut num = num;
let mut result = String::new();
self.generate_on_top_of(&mut num, &mut result);
result
}
pub fn optional(self) -> Self {
use Generator::OneOf;
match self {
OneOf {
v,
is_optional: true,
} => OneOf {
v,
is_optional: true,
},
OneOf {
v,
is_optional: false,
} => OneOf {
v,
is_optional: true,
},
_ => OneOf {
v: vec![self],
is_optional: true,
},
}
}
pub fn values(&self) -> Iter {
Iter {
c: self,
n: self.len(),
i: 0,
}
}
}
impl From<char> for Generator {
fn from(c: char) -> Self {
Generator::Char(c)
}
}
impl From<&str> for Generator {
fn from(s: &str) -> Self {
Generator::Str(s.to_string())
}
}
impl<T> From<&[T]> for Generator
where
T: AsRef<str> + Display,
{
fn from(values: &[T]) -> Self {
let is_optional = false;
let v = values
.iter()
.map(|value| Generator::Str(value.to_string()))
.collect();
Generator::OneOf { v, is_optional }
}
}
impl BitOr for Generator {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
use Generator::*;
match (self, rhs) {
(
OneOf {
v: mut v1,
is_optional: opt1,
},
OneOf {
v: v2,
is_optional: opt2,
},
) => {
v1.extend(v2);
let is_optional = opt1 || opt2;
OneOf { v: v1, is_optional }
}
(OneOf { mut v, is_optional }, rhs) => {
v.push(rhs);
OneOf { v, is_optional }
}
(lhs, OneOf { mut v, is_optional }) => {
v.insert(0, lhs);
OneOf { v, is_optional }
}
(lhs, rhs) => {
let v = vec![lhs, rhs];
OneOf {
v,
is_optional: false,
}
}
}
}
}
impl Mul<usize> for Generator {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
let lhs = Box::new(self);
Generator::RepeatedN(lhs, rhs)
}
}
impl MulAssign<usize> for Generator {
fn mul_assign(&mut self, rhs: usize) {
let repeat = self.clone() * rhs;
*self = repeat;
}
}
impl Mul<(usize, usize)> for Generator {
type Output = Self;
fn mul(self, rhs: (usize, usize)) -> Self::Output {
let (m, n) = rhs;
assert!(m <= n);
let lhs = Box::new(self);
Generator::RepeatedMN(lhs, m, n)
}
}
impl MulAssign<(usize, usize)> for Generator {
fn mul_assign(&mut self, rhs: (usize, usize)) {
let (m, n) = rhs;
assert!(m <= n);
let lhs = mem::replace(self, Generator::Digit);
*self = Generator::RepeatedMN(Box::new(lhs), m, n);
}
}
impl Add for Generator {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
use Generator::*;
match (self, rhs) {
(Sequence(mut v1), Sequence(v2)) => {
for c in v2 {
v1.push(c);
}
Sequence(v1)
}
(Sequence(mut v1), rhs) => {
v1.push(rhs);
Sequence(v1)
}
(lhs, Sequence(v2)) => {
let mut v = vec![lhs];
for c in v2 {
v.push(c);
}
Sequence(v)
}
(lhs, rhs) => {
let v = vec![lhs, rhs];
Sequence(v)
}
}
}
}
impl AddAssign for Generator {
fn add_assign(&mut self, rhs: Self) {
use Generator::*;
match (self, rhs) {
(Sequence(v1), Sequence(v2)) => {
for c in v2 {
v1.push(c);
}
}
(Sequence(v1), rhs) => {
v1.push(rhs);
}
(lhs, Sequence(mut v2)) => {
let left = mem::replace(lhs, Generator::Digit);
v2.insert(0, left);
*lhs = Sequence(v2);
}
(lhs, rhs) => {
let left = mem::replace(lhs, Generator::Digit);
let v = vec![left, rhs];
*lhs = Sequence(v)
}
}
}
}
impl BitOrAssign for Generator {
fn bitor_assign(&mut self, rhs: Self) {
use Generator::*;
match (self, rhs) {
(
OneOf {
v: v1,
is_optional: opt1,
},
OneOf {
v: v2,
is_optional: opt2,
},
) => {
v1.push(Digit);
v1.extend(v2);
if opt2 {
*opt1 = true;
}
}
(OneOf { v, is_optional: _ }, rhs) => {
v.push(rhs);
}
(lhs, OneOf { mut v, is_optional }) => {
let left = mem::replace(lhs, Generator::Digit);
v.insert(0, left);
*lhs = OneOf { v, is_optional };
}
(lhs, rhs) => {
let left = mem::replace(lhs, Generator::Digit);
let v = vec![left, rhs];
*lhs = OneOf {
v,
is_optional: false,
};
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{gen, oneof};
#[test]
fn combinations_consts() {
let eight_alphas = Generator::AlphaLower * 8;
assert_eq!(26u128.pow(8), eight_alphas.len());
let eight_alphas = Generator::AlphaLower * (8, 8);
assert_eq!(26u128.pow(8), eight_alphas.len());
let expected = 26u128.pow(7) + 26u128.pow(8);
let seven_or_eight_alphas = Generator::AlphaLower * (7, 8);
assert_eq!(expected, seven_or_eight_alphas.len());
}
#[test]
fn combinations_mn() {
let ab23 = (Generator::from("a") | Generator::from("b")) * (2, 3);
assert_eq!(12, ab23.len());
}
#[test]
fn combinations_str() {
let foo = Generator::from("foo");
assert_eq!(1, foo.len());
}
#[test]
fn combinations_oneof() {
let foo = Generator::from("foo");
let bar = Generator::from("bar");
assert_eq!(1, foo.len());
assert_eq!(1, bar.len());
let foo_bar = foo | bar;
assert_eq!(2, foo_bar.len());
let baz = Generator::from("baz");
assert_eq!(1, baz.len());
let foo_bar_baz = foo_bar | baz;
assert_eq!(3, foo_bar_baz.len());
}
#[test]
fn combinations_optional() {
let foo = Generator::from("foo");
let bar = Generator::from("bar");
let opt_foo = Generator::OneOf {
v: vec![foo.clone()],
is_optional: true,
};
assert_eq!(2, opt_foo.len());
let opt_foo_bar = Generator::OneOf {
v: vec![foo.clone(), bar.clone()],
is_optional: true,
};
assert_eq!(3, opt_foo_bar.len());
let mut v = opt_foo_bar.values();
assert_eq!(Some("".into()), v.next());
assert_eq!(Some("foo".into()), v.next());
assert_eq!(Some("bar".into()), v.next());
assert_eq!(None, v.next());
}
#[test]
fn combinations_email() {
use Generator::Char;
let username = Generator::AlphaLower * (6, 8);
let user_combos = 26u128.pow(6) + 26u128.pow(7) + 26u128.pow(8);
assert_eq!(username.len(), user_combos);
let tld = Generator::from("com")
| Generator::from("net")
| Generator::from("org")
| Generator::from("edu")
| Generator::from("gov");
let tld_combos = 5;
assert_eq!(tld.len(), tld_combos);
let domain = Generator::AlphaLower * (1, 8) + Char('.') + tld;
let domain_combos = (1..=8).map(|i| 26u128.pow(i)).sum::<u128>() * tld_combos;
assert_eq!(domain.len(), domain_combos);
let email = username + Char('@') + domain;
assert_eq!(email.len(), domain_combos * user_combos);
}
#[test]
fn generate_alpha1() {
let alphas2 = Generator::AlphaLower * 2;
let aa = alphas2.generate_exact(0);
assert_eq!(aa, "aa");
let onetwothree = (Generator::Digit * 10).generate_exact(123);
assert_eq!(onetwothree, "0000000123");
}
#[test]
fn generate_hex() {
let hex = Generator::from("0x") + Generator::HexUpper * 8;
assert_eq!(4_294_967_296, hex.len());
assert_eq!(hex.generate_exact(3_735_928_559), "0xDEADBEEF");
assert_eq!(hex.generate_exact(464_375_821), "0x1BADD00D");
}
#[test]
fn simplify() {
let foo_opt1 = gen!("foo").optional();
let foo_opt1 = foo_opt1.optional();
let foo_opt2 = gen!("foo").optional();
assert_eq!(foo_opt1, foo_opt2);
}
#[test]
fn equality() {
let foo1 = Generator::from("foo");
let foo2 = gen!("foo");
assert_eq!(foo1, foo2);
let foo2 = oneof!("foo");
assert_eq!(foo1, foo2);
let foobar1 = oneof!("foo", "bar");
let mut foobar2 = gen!("foo");
foobar2 |= gen!("bar");
assert_eq!(foobar1, foobar2);
let foobar1 = gen!("foo") + gen!("bar");
let mut foobar2 = gen!("foo");
foobar2 += gen!("bar");
assert_eq!(foobar1, foobar2);
let foo1 = gen!("foo") * 2;
let mut foo2 = gen!("foo");
foo2 *= 2;
assert_eq!(foo1, foo2);
let foo1 = gen!("foo") * (2, 3);
let mut foo2 = gen!("foo");
foo2 *= (2, 3);
assert_eq!(foo1, foo2);
}
#[test]
fn test_reduce_optionals() {
let foo = gen!("foo").optional();
let bar = gen!("bar").optional();
let baz = gen!("baz").optional();
let foobarbaz1 = foo | bar | baz;
let foobarbaz2 = gen!("foo").optional() | oneof!("bar", "baz");
assert_eq!(foobarbaz1, foobarbaz2);
}
}