#![deny(missing_docs)]
extern crate rand;
pub static ZALGO_UP: [char; 50] = [
'̍', '̎', '̄', '̅', '̿', '̑', '̆', '̐', '͒', '͗', '͑', '̇', '̈', '̊',
'͂', '̓', '̈́', '͊', '͋', '͌', '̃', '̂', '̌', '͐', '̀', '́', '̋', '̏',
'̒', '̓', '̔', '̽', '̉', 'ͣ', 'ͤ', 'ͥ', 'ͦ', 'ͧ', 'ͨ', 'ͩ', 'ͪ', 'ͫ',
'ͬ', 'ͭ', 'ͮ', 'ͯ', '̾', '͛', '͆', '̚',
];
pub static ZALGO_MIDDLE: [char; 23] = [
'̕', '̛', '̀', '́', '͘', '̡', '̢', '̧', '̨', '̴', '̵', '̶', '͏', '͜',
'͝', '͞', '͟', '͠', '͢', '̸', '̷', '͡', '҉',
];
pub static ZALGO_DOWN: [char; 40] = [
'̖', '̗', '̘', '̙', '̜', '̝', '̞', '̟', '̠', '̤', '̥', '̦', '̩', '̪',
'̫', '̬', '̭', '̮', '̯', '̰', '̱', '̲', '̳', '̹', '̺', '̻', '̼', 'ͅ',
'͇', '͈', '͉', '͍', '͎', '͓', '͔', '͕', '͖', '͙', '͚', '̣',
];
const ZALGO_UP_LEN: u8 = 50;
const ZALGO_MIDDLE_LEN: u8 = 23;
const ZALGO_DOWN_LEN: u8 = 40;
use rand::{Rng, ThreadRng};
#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub enum ZalgoKind {
Up,
Middle,
Down,
}
#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub enum ZalgoSize {
Maxi,
Mini,
None,
}
pub fn all() -> Vec<char> {
let mut v = vec![];
v.extend(ZALGO_UP.iter());
v.extend(ZALGO_MIDDLE.iter());
v.extend(ZALGO_DOWN.iter());
v
}
#[derive(Clone, Debug, Default)]
pub struct GeneratorArgs {
pub down: Option<bool>,
pub middle: Option<bool>,
pub size: Option<ZalgoSize>,
pub up: Option<bool>,
}
impl GeneratorArgs {
pub fn new(up: bool, middle: bool, down: bool, size: ZalgoSize) -> Self {
Self {
down: Some(down),
middle: Some(middle),
size: Some(size),
up: Some(up),
}
}
}
pub struct Generator {
rng: ThreadRng,
}
impl Generator {
pub fn new() -> Self {
Self {
rng: rand::thread_rng(),
}
}
pub fn gen<T: AsRef<str>>(
&mut self,
text: T,
buf: &mut String,
args: &GeneratorArgs,
) {
self._gen(text.as_ref(), buf, args)
}
fn _gen(
&mut self,
text: &str,
buf: &mut String,
args: &GeneratorArgs,
) {
let GeneratorArgs { up, middle, down, size } = args;
for ch in text.chars() {
if is_zalgo(ch) {
continue;
}
buf.push(ch);
if up.unwrap_or(false) {
let count = self.rng.gen_range(0, ZALGO_UP_LEN) as usize;
self.gen_iter(count, &ZALGO_UP, buf);
}
if middle.unwrap_or(false) {
let count = match size {
Some(ZalgoSize::None) => self.rng.gen_range(0, ZALGO_MIDDLE_LEN) / 2,
_ => self.rng.gen_range(0, ZALGO_MIDDLE_LEN),
} as usize;
self.gen_iter(count, &ZALGO_MIDDLE, buf);
}
if down.unwrap_or(false) {
let count = self.rng.gen_range(0, ZALGO_DOWN_LEN) as usize;
self.gen_iter(count, &ZALGO_DOWN, buf);
}
}
}
pub fn gen_simple<T: AsRef<str>>(&mut self, text: T, buf: &mut String) {
self.gen(text.as_ref(), buf, &GeneratorArgs {
down: Some(true),
middle: Some(true),
size: Some(ZalgoSize::Mini),
up: Some(true),
})
}
fn gen_iter(&mut self, count: usize, zalgo: &[char], buf: &mut String) {
(0..count).for_each(|_| {
let get = self.rng.gen_range(0, count);
buf.push(zalgo[get]);
});
}
}
pub fn is_zalgo(ch: char) -> bool {
all().contains(&ch)
}