|
|
@ -1,35 +1,55 @@
|
|
|
|
|
|
|
|
#![cfg_attr(all(feature = "bench", test), feature(test))]
|
|
|
|
|
|
|
|
|
|
|
|
use std::fs::File;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{stdout, BufWriter, Error, ErrorKind, Write};
|
|
|
|
use std::io::{BufWriter, Error, ErrorKind, Write};
|
|
|
|
use std::path::Path;
|
|
|
|
use std::path::Path;
|
|
|
|
use std::str::from_utf8_unchecked;
|
|
|
|
use std::str::from_utf8_unchecked;
|
|
|
|
|
|
|
|
|
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
|
|
|
use ahash::RandomState;
|
|
|
|
use linkify::{LinkFinder, LinkKind};
|
|
|
|
use linkify::{LinkFinder, LinkKind};
|
|
|
|
use memmap::Mmap;
|
|
|
|
use memmap::Mmap;
|
|
|
|
|
|
|
|
|
|
|
|
use constants::ACTIONS;
|
|
|
|
|
|
|
|
use constants::ACTIONS_SIZE;
|
|
|
|
use constants::ACTIONS_SIZE;
|
|
|
|
use constants::FACES;
|
|
|
|
use constants::FACES;
|
|
|
|
use constants::FACES_SIZE;
|
|
|
|
use constants::FACES_SIZE;
|
|
|
|
use seeder::UwUSeeder;
|
|
|
|
use constants::{ACTIONS, ASCII, ASCII_SIZE};
|
|
|
|
|
|
|
|
|
|
|
|
mod constants;
|
|
|
|
mod constants;
|
|
|
|
mod seeder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! progress_bar {
|
|
|
|
macro_rules! progress_bar {
|
|
|
|
($bytes:expr) => {{
|
|
|
|
() => {{
|
|
|
|
let progress_bar = ProgressBar::new($bytes);
|
|
|
|
let progress_bar = indicatif::ProgressBar::new_spinner()
|
|
|
|
progress_bar.set_style(
|
|
|
|
.with_style(
|
|
|
|
ProgressStyle::default_spinner()
|
|
|
|
indicatif::ProgressStyle::default_spinner()
|
|
|
|
.template("{spinner:.magenta} [{elapsed_precise:.bold}] {msg:.green.bold}"),
|
|
|
|
.template("{spinner:.magenta} [{elapsed_precise:.bold}] {msg:.green.bold}"),
|
|
|
|
);
|
|
|
|
)
|
|
|
|
progress_bar.set_message("UwU'ifying In Progress...");
|
|
|
|
.with_message("UwU'ifying In Progress...");
|
|
|
|
progress_bar.enable_steady_tick(30);
|
|
|
|
progress_bar.enable_steady_tick(30);
|
|
|
|
|
|
|
|
|
|
|
|
progress_bar
|
|
|
|
progress_bar
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! new_seeder {
|
|
|
|
|
|
|
|
($word:expr,$seeder:expr) => {
|
|
|
|
|
|
|
|
<rand_xoshiro::Xoshiro256Plus as rand::SeedableRng>::seed_from_u64(
|
|
|
|
|
|
|
|
<[u8] as ahash::CallHasher>::get_hash($word, $seeder),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! random_float {
|
|
|
|
|
|
|
|
($seeder:expr) => {
|
|
|
|
|
|
|
|
rand::Rng::gen_range($seeder, 0.0..1.0)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! random_int {
|
|
|
|
|
|
|
|
($seeder:expr, $range:expr) => {
|
|
|
|
|
|
|
|
rand::Rng::gen_range($seeder, $range)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct UwUify<'a> {
|
|
|
|
pub struct UwUify<'a> {
|
|
|
|
text: &'a str,
|
|
|
|
text: &'a str,
|
|
|
@ -39,7 +59,8 @@ pub struct UwUify<'a> {
|
|
|
|
faces: f64,
|
|
|
|
faces: f64,
|
|
|
|
actions: f64,
|
|
|
|
actions: f64,
|
|
|
|
stutters: f64,
|
|
|
|
stutters: f64,
|
|
|
|
random: bool,
|
|
|
|
random: RandomState,
|
|
|
|
|
|
|
|
ascii: bool,
|
|
|
|
is_runtime: bool,
|
|
|
|
is_runtime: bool,
|
|
|
|
linkify: LinkFinder,
|
|
|
|
linkify: LinkFinder,
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -54,8 +75,9 @@ impl<'a> Default for UwUify<'a> {
|
|
|
|
faces: 0.05,
|
|
|
|
faces: 0.05,
|
|
|
|
actions: 0.125,
|
|
|
|
actions: 0.125,
|
|
|
|
stutters: 0.225,
|
|
|
|
stutters: 0.225,
|
|
|
|
random: false,
|
|
|
|
random: RandomState::with_seeds(69, 420, 96, 84),
|
|
|
|
is_runtime: false,
|
|
|
|
is_runtime: false,
|
|
|
|
|
|
|
|
ascii: false,
|
|
|
|
linkify: LinkFinder::new(),
|
|
|
|
linkify: LinkFinder::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -70,6 +92,7 @@ impl<'a> UwUify<'a> {
|
|
|
|
faces: Option<&'a str>,
|
|
|
|
faces: Option<&'a str>,
|
|
|
|
actions: Option<&'a str>,
|
|
|
|
actions: Option<&'a str>,
|
|
|
|
stutters: Option<&'a str>,
|
|
|
|
stutters: Option<&'a str>,
|
|
|
|
|
|
|
|
ascii: bool,
|
|
|
|
random: bool,
|
|
|
|
random: bool,
|
|
|
|
is_runtime: bool,
|
|
|
|
is_runtime: bool,
|
|
|
|
) -> UwUify<'a> {
|
|
|
|
) -> UwUify<'a> {
|
|
|
@ -81,12 +104,16 @@ impl<'a> UwUify<'a> {
|
|
|
|
text: text.unwrap_or_default(),
|
|
|
|
text: text.unwrap_or_default(),
|
|
|
|
input: infile.unwrap_or_default(),
|
|
|
|
input: infile.unwrap_or_default(),
|
|
|
|
output: outfile.unwrap_or_default(),
|
|
|
|
output: outfile.unwrap_or_default(),
|
|
|
|
random,
|
|
|
|
ascii,
|
|
|
|
is_runtime,
|
|
|
|
is_runtime,
|
|
|
|
linkify,
|
|
|
|
linkify,
|
|
|
|
..Default::default()
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if random {
|
|
|
|
|
|
|
|
uwuify.random = RandomState::new();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(words) = words {
|
|
|
|
if let Some(words) = words {
|
|
|
|
uwuify.words = words.parse::<f64>().unwrap();
|
|
|
|
uwuify.words = words.parse::<f64>().unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -103,7 +130,7 @@ impl<'a> UwUify<'a> {
|
|
|
|
uwuify
|
|
|
|
uwuify
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn uwuify(&mut self) -> Result<(), Error> {
|
|
|
|
pub fn uwuify(&self) -> Result<(), Error> {
|
|
|
|
// Handle Text
|
|
|
|
// Handle Text
|
|
|
|
if !self.text.is_empty() {
|
|
|
|
if !self.text.is_empty() {
|
|
|
|
// Handle Text Output
|
|
|
|
// Handle Text Output
|
|
|
@ -115,11 +142,14 @@ impl<'a> UwUify<'a> {
|
|
|
|
));
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let uwu_progress_bar = progress_bar!(self.text.len() as u64);
|
|
|
|
let uwu_progress_bar = progress_bar!();
|
|
|
|
self.uwuify_sentence(self.text, &mut BufWriter::new(File::create(&self.output)?))?;
|
|
|
|
self.uwuify_sentence(self.text, &mut BufWriter::new(File::create(&self.output)?))?;
|
|
|
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
|
|
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
self.uwuify_sentence(self.text, &mut BufWriter::new(stdout().lock()))?;
|
|
|
|
#[cfg(not(test))]
|
|
|
|
|
|
|
|
self.uwuify_sentence(self.text, &mut BufWriter::new(std::io::stdout().lock()))?;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
|
|
self.uwuify_sentence(self.text, &mut std::io::sink())?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Handle File I/O
|
|
|
|
// Handle File I/O
|
|
|
@ -130,10 +160,9 @@ impl<'a> UwUify<'a> {
|
|
|
|
));
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let infile = File::open(&self.input)?;
|
|
|
|
let uwu_progress_bar = progress_bar!();
|
|
|
|
let uwu_progress_bar = progress_bar!(infile.metadata()?.len());
|
|
|
|
|
|
|
|
self.uwuify_sentence(
|
|
|
|
self.uwuify_sentence(
|
|
|
|
unsafe { from_utf8_unchecked(Mmap::map(&infile)?.as_ref()) },
|
|
|
|
unsafe { from_utf8_unchecked(Mmap::map(&File::open(&self.input)?)?.as_ref()) },
|
|
|
|
&mut BufWriter::new(File::create(&self.output)?),
|
|
|
|
&mut BufWriter::new(File::create(&self.output)?),
|
|
|
|
)?;
|
|
|
|
)?;
|
|
|
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
|
|
|
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
|
|
|
@ -142,19 +171,24 @@ impl<'a> UwUify<'a> {
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn uwuify_sentence<T: Write>(&mut self, text: &str, out: &mut T) -> Result<(), Error> {
|
|
|
|
pub fn uwuify_sentence<T: Write>(&self, text: &str, out: &mut T) -> Result<(), Error> {
|
|
|
|
text.lines().try_for_each(|line| {
|
|
|
|
text.lines().try_for_each(|line| {
|
|
|
|
line.split_whitespace()
|
|
|
|
line.split_whitespace()
|
|
|
|
.map(|word_str| word_str.as_bytes())
|
|
|
|
.map(|word_str| word_str.as_bytes())
|
|
|
|
.try_for_each(|word| {
|
|
|
|
.try_for_each(|word| {
|
|
|
|
let mut seeder = UwUSeeder::new(word, self.random);
|
|
|
|
let mut seeder = new_seeder!(word, &self.random);
|
|
|
|
let random_value = seeder.random_float();
|
|
|
|
let random_value = random_float!(&mut seeder);
|
|
|
|
|
|
|
|
|
|
|
|
if !self.is_runtime {
|
|
|
|
if !self.is_runtime {
|
|
|
|
if random_value <= self.faces {
|
|
|
|
if random_value <= self.faces {
|
|
|
|
out.write_all(FACES[seeder.random_int(0..FACES_SIZE)])?;
|
|
|
|
if self.ascii {
|
|
|
|
|
|
|
|
out.write_all(ASCII[random_int!(&mut seeder, 0..ASCII_SIZE)])?;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
out.write_all(FACES[random_int!(&mut seeder, 0..FACES_SIZE)])?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
out.write_all(b" ")?;
|
|
|
|
} else if random_value <= self.actions {
|
|
|
|
} else if random_value <= self.actions {
|
|
|
|
out.write_all(ACTIONS[seeder.random_int(0..ACTIONS_SIZE)])?;
|
|
|
|
out.write_all(ACTIONS[random_int!(&mut seeder, 0..ACTIONS_SIZE)])?;
|
|
|
|
} else if random_value <= self.stutters {
|
|
|
|
} else if random_value <= self.stutters {
|
|
|
|
match word[0] {
|
|
|
|
match word[0] {
|
|
|
|
b'L' | b'R' => out.write_all(b"W"),
|
|
|
|
b'L' | b'R' => out.write_all(b"W"),
|
|
|
@ -165,10 +199,15 @@ impl<'a> UwUify<'a> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if random_value <= self.faces {
|
|
|
|
if random_value <= self.faces {
|
|
|
|
out.write_all(FACES[seeder.random_int(0..FACES_SIZE)])?;
|
|
|
|
if self.ascii {
|
|
|
|
|
|
|
|
out.write_all(ASCII[random_int!(&mut seeder, 0..ASCII_SIZE)])?;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
out.write_all(FACES[random_int!(&mut seeder, 0..FACES_SIZE)])?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
out.write_all(b" ")?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if random_value <= self.actions {
|
|
|
|
if random_value <= self.actions {
|
|
|
|
out.write_all(ACTIONS[seeder.random_int(0..ACTIONS_SIZE)])?;
|
|
|
|
out.write_all(ACTIONS[random_int!(&mut seeder, 0..ACTIONS_SIZE)])?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if random_value <= self.stutters {
|
|
|
|
if random_value <= self.stutters {
|
|
|
|
match word[0] {
|
|
|
|
match word[0] {
|
|
|
@ -207,3 +246,26 @@ impl<'a> UwUify<'a> {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
#[cfg(feature = "bench")]
|
|
|
|
|
|
|
|
extern crate test;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "bench")]
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
|
|
|
|
fn uwu_bench(b: &mut test::Bencher) {
|
|
|
|
|
|
|
|
let uwuify = super::UwUify::new(
|
|
|
|
|
|
|
|
Some(include_str!("test.txt")),
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
b.iter(|| uwuify.uwuify());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|