Speewd *UwU*

pull/2/head
Isaac Mills 3 years ago
parent 6be7aea531
commit 29292bd1c9
No known key found for this signature in database
GPG Key ID: B67D7410F33A0F61

@ -24,7 +24,12 @@ name = "uwuify"
[dependencies]
clap = { version = "3.0.10", features = ["derive"] }
rand = "0.8.4"
rand_seeder = "0.2.2"
rand_pcg = "0.3.1"
indicatif = "0.16.2"
linkify = "0.8.0"
ahash = "0.7.6"
rand_xoshiro = "0.6.0"
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"

File diff suppressed because it is too large Load Diff

@ -1,24 +1,11 @@
pub const FACES_SIZE: i32 = 15;
pub const FACES: [&str; FACES_SIZE as usize] = [
"OwO",
"UwU",
">w<",
"^w^",
"ÚwÚ",
"^-^",
":3",
"x3",
"xDD",
";;w;;",
">_<",
">_>",
"^.^",
":33",
"uWu",
pub const FACES_SIZE: usize = 15;
pub const FACES: [&str; FACES_SIZE] = [
"OwO", "UwU", ">w<", "^w^", "ÚwÚ", "^-^", ":3", "x3", "xDD", ";;w;;", ">_<", ">_>", "^.^",
":33", "uWu",
];
pub const ACTIONS_SIZE: i32 = 17;
pub const ACTIONS: [&str; ACTIONS_SIZE as usize] = [
pub const ACTIONS_SIZE: usize = 17;
pub const ACTIONS: [&str; ACTIONS_SIZE] = [
"*notices bulge*",
"*cries*",
"*hugs tightly*",

@ -5,80 +5,57 @@ use std::path::Path;
pub struct UwUInFile {
file_bytes: u64,
reader: BufReader<File>,
buffer: Vec<u8>,
pub buffer: String,
}
pub struct UwUOutFile {
writer: BufWriter<File>,
#[repr(transparent)]
pub struct UwUOutFile<T: Write> {
writer: BufWriter<T>,
}
impl UwUInFile {
#[inline]
pub fn new(path: &Path) -> Result<UwUInFile, Error> {
let file = match File::open(path) {
Ok(file) => file,
Err(err) => return Err(err),
};
let file_metadata = match file.metadata() {
Ok(file_metadata) => file_metadata,
Err(err) => return Err(err),
};
let file_bytes = file_metadata.len();
let reader = BufReader::new(file);
let buffer = Vec::new();
let file = File::open(path)?;
Ok(UwUInFile {
file_bytes,
reader,
buffer,
file_bytes: file.metadata()?.len(),
reader: BufReader::new(file),
buffer: String::new(),
})
}
#[inline]
pub fn read_until_newline(&mut self) -> Result<usize, Error> {
match self.reader.read_until(b'\n', &mut self.buffer) {
Ok(byte_vec) => Ok(byte_vec),
Err(err) => Err(err),
}
}
pub fn get_buffer_as_utf8_str(&self) -> String {
String::from_utf8_lossy(&self.buffer).to_string()
self.reader.read_line(&mut self.buffer)
}
#[inline]
pub fn clear_buffer(&mut self) {
self.buffer.clear();
}
#[inline]
pub fn get_file_bytes(&self) -> u64 {
self.file_bytes
}
}
impl UwUOutFile {
pub fn new(path: &str) -> Result<UwUOutFile, Error> {
let file = match File::create(path) {
Ok(file) => file,
Err(err) => return Err(err),
};
let writer = BufWriter::new(file);
Ok(UwUOutFile { writer })
impl<T: Write> UwUOutFile<T> {
#[inline]
pub fn new(writer: T) -> UwUOutFile<T> {
UwUOutFile {
writer: BufWriter::new(writer),
}
pub fn exists(path: &str) -> bool {
Path::new(path).exists()
}
pub fn write_string_with_newline(&mut self, write_str: &str) -> Result<(), Error> {
match self.writer.write_all(format!("{}\n", write_str).as_bytes()) {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
#[inline]
pub fn write_newline(&mut self) -> Result<(), Error> {
self.writer.write_all(b"\n")
}
#[inline]
pub fn write_string(&mut self, write_str: &str) -> Result<(), Error> {
match self.writer.write_all(write_str.as_bytes()) {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
self.writer.write_all(write_str.as_bytes())
}
}

@ -1,5 +1,7 @@
use linkify::{LinkFinder, LinkKind};
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use constants::ACTIONS;
@ -18,10 +20,10 @@ mod seeder;
#[derive(Debug)]
struct Modifiers {
supplied_at_runtime: bool,
words: f32,
faces: f32,
actions: f32,
stutters: f32,
words: f64,
faces: f64,
actions: f64,
stutters: f64,
}
#[derive(Debug)]
@ -40,10 +42,10 @@ impl UwUify {
infile: Option<PathBuf>,
outfile: Option<String>,
supplied_at_runtime: bool,
words: f32,
faces: f32,
actions: f32,
stutters: f32,
words: f64,
faces: f64,
actions: f64,
stutters: f64,
random: bool,
) -> UwUify {
// I dislike this
@ -71,11 +73,9 @@ impl UwUify {
pub fn uwuify(&self) -> Result<(), Box<dyn Error>> {
// Handle Text
if !self.text.is_empty() {
let uwu_text = self.uwuify_sentence(&self.text);
// Handle Text Output
if !self.output.is_empty() {
if UwUOutFile::exists(&self.output) {
if std::path::Path::new(&self.output).exists() {
return Err(format!(
"File '{}' already exists, aborting operation",
&self.output
@ -83,78 +83,67 @@ impl UwUify {
.into());
}
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
Ok(uwu_out_file) => uwu_out_file,
Err(err) => return Err(err.into()),
};
let mut uwu_progress_bar = UwUProgressBar::new(uwu_text.len() as u64);
let mut uwu_out_file = UwUOutFile::new(File::create(&self.output)?);
self.uwuify_sentence(&self.text, &mut uwu_out_file)?;
match uwu_out_file.write_string(&uwu_text) {
Ok(_) => (),
Err(err) => return Err(err.into()),
};
let mut uwu_progress_bar = UwUProgressBar::new(self.text.len() as u64);
uwu_progress_bar.update_progess(uwu_text.len());
uwu_progress_bar.update_progess(self.text.len());
uwu_progress_bar.finish("UwU'ifying Complete!");
Ok(())
} else {
println!("{}", uwu_text);
let stdout = std::io::stdout();
let mut out = UwUOutFile::new(stdout.lock());
self.uwuify_sentence(&self.text, &mut out)?;
out.write_newline()?;
Ok(())
}
} else {
// Handle File I/O
if UwUOutFile::exists(&self.output) {
if std::path::Path::new(&self.output).exists() {
return Err(
format!("File '{}' already exists, aborting operation", &self.output).into(),
);
};
let mut uwu_in_file = match UwUInFile::new(&self.input) {
Ok(uwu_in_file) => uwu_in_file,
Err(err) => return Err(err.into()),
};
let mut uwu_out_file = match UwUOutFile::new(&self.output) {
Ok(uwu_out_file) => uwu_out_file,
Err(err) => return Err(err.into()),
};
}
let mut uwu_in_file = UwUInFile::new(&self.input)?;
let mut uwu_out_file = UwUOutFile::new(File::create(&self.output)?);
let mut uwu_progress_bar = UwUProgressBar::new(uwu_in_file.get_file_bytes());
loop {
let bytes_read_in = match uwu_in_file.read_until_newline() {
Ok(bytes_read_in) => bytes_read_in,
Err(err) => return Err(err.into()),
};
if bytes_read_in == 0 {
break;
}
let utf8_str = uwu_in_file.get_buffer_as_utf8_str();
let uwu_sentence = self.uwuify_sentence(&utf8_str);
match uwu_out_file.write_string_with_newline(&uwu_sentence) {
Ok(_) => (),
Err(err) => return Err(err.into()),
};
let bytes_read_in = uwu_in_file.read_until_newline()?;
if bytes_read_in != 0 {
self.uwuify_sentence(&uwu_in_file.buffer, &mut uwu_out_file)?;
uwu_out_file.write_newline()?;
uwu_progress_bar.update_progess(bytes_read_in);
uwu_in_file.clear_buffer();
}
} else {
uwu_progress_bar.finish("UwU'ifying Complete!");
return Ok(());
}
}
}
Ok(())
}
fn uwuify_sentence(&self, text: &str) -> String {
fn uwuify_sentence<T: Write>(
&self,
text: &str,
out: &mut UwUOutFile<T>,
) -> Result<(), std::io::Error> {
text.split_whitespace()
.map(|word| {
let uwu_word = self.uwuify_word(word.to_string());
self.uwuify_spaces(uwu_word)
})
.collect::<Vec<String>>()
.join(" ")
.try_for_each(|f| {
out.write_string(&f)?;
out.write_string(" ")
})
}
fn uwuify_word(&self, word: String) -> String {
use std::fmt::Write;
if self.linkify.links(&word).count() > 0 {
return word;
}
@ -179,7 +168,9 @@ impl UwUify {
'L' | 'R' => uwu_text.push('W'),
'l' | 'r' => uwu_text.push('w'),
'E' | 'e' => match previous_char {
'N' | 'n' => uwu_text.push_str(format!("y{}", current_char).as_str()),
'N' | 'n' => uwu_text
.write_fmt(format_args!("y{}", current_char))
.unwrap(),
'v' => match previous_previous_char {
'o' => {
uwu_text.pop();
@ -191,7 +182,9 @@ impl UwUify {
_ => uwu_text.push(current_char),
},
'A' | 'I' | 'O' | 'U' | 'a' | 'i' | 'o' | 'u' => match previous_char {
'N' | 'n' => uwu_text.push_str(format!("y{}", current_char).as_str()),
'N' | 'n' => uwu_text
.write_fmt(format_args!("y{}", current_char))
.unwrap(),
_ => uwu_text.push(current_char),
},
_ => uwu_text.push(current_char),
@ -207,14 +200,14 @@ impl UwUify {
if !self.modifiers.supplied_at_runtime {
if random_value <= self.modifiers.faces {
word = format!("{} {}", FACES[seeder.random_int(0, FACES_SIZE)], word);
word = format!("{} {}", FACES[seeder.random_int(0..FACES_SIZE)], word);
} else if random_value <= self.modifiers.actions {
word = format!("{} {}", ACTIONS[seeder.random_int(0, ACTIONS_SIZE)], word);
word = format!("{} {}", ACTIONS[seeder.random_int(0..ACTIONS_SIZE)], word);
} else if random_value <= self.modifiers.stutters {
let first_char_stutter = format!("{}-", word.chars().next().unwrap());
word = format!(
"{}{}",
first_char_stutter.repeat(seeder.random_int(1, 2)),
first_char_stutter.repeat(seeder.random_int(1..2)),
word
);
}
@ -223,15 +216,15 @@ impl UwUify {
let first_char_stutter = format!("{}-", word.chars().next().unwrap());
word = format!(
"{}{}",
first_char_stutter.repeat(seeder.random_int(1, 2)),
first_char_stutter.repeat(seeder.random_int(1..2)),
word
);
}
if random_value <= self.modifiers.faces {
word = format!("{} {}", FACES[seeder.random_int(0, FACES_SIZE)], word);
word = format!("{} {}", FACES[seeder.random_int(0..FACES_SIZE)], word);
}
if random_value <= self.modifiers.actions {
word = format!("{} {}", ACTIONS[seeder.random_int(0, ACTIONS_SIZE)], word);
word = format!("{} {}", ACTIONS[seeder.random_int(0..ACTIONS_SIZE)], word);
}
}

@ -20,19 +20,19 @@ struct Args {
/// The modifier to determine how many words to be uwu'ified
#[clap(short, long, value_name = "VALUE", default_value = "1", validator = is_between_zero_and_one, display_order = 4)]
words: f32,
words: f64,
/// The modifier for uwu faces e.g hello -> hewwo
#[clap(short, long, value_name = "VALUE", default_value = "0.05", validator = is_between_zero_and_one, display_order = 5)]
faces: f32,
faces: f64,
/// The modifier for actions e.g *shuffles over*
#[clap(short, long, value_name = "VALUE", default_value = "0.125", validator = is_between_zero_and_one, display_order = 6)]
actions: f32,
actions: f64,
/// The modifier for stutters e.g b-baka!
#[clap(short, long, value_name = "VALUE", default_value = "0.225", validator = is_between_zero_and_one, display_order = 7)]
stutters: f32,
stutters: f64,
/// Flag to enable/disable random uwu'ifying
#[clap(short, long, display_order = 8)]
@ -68,16 +68,16 @@ fn main() {
}
}
fn is_between_zero_and_one(input: &str) -> Result<(), String> {
fn is_between_zero_and_one(input: &str) -> Result<(), &'static str> {
let value = match input.parse::<f32>() {
Ok(value) => value,
Err(_) => return Err(String::from("The value must be a decimal number")),
Err(_) => return Err("The value must be a decimal number"),
};
if (0.0..=1.0).contains(&value) {
return Ok(());
}
Err(String::from("The value must be between 0.0 and 1.0"))
Err("The value must be between 0.0 and 1.0")
}
fn modifiers_supplied_at_runtime(

@ -1,29 +1,26 @@
use indicatif::{ProgressBar, ProgressStyle};
pub struct UwUProgressBar {
downloaded_bytes: u64,
progress_bar: ProgressBar,
}
#[repr(transparent)]
pub struct UwUProgressBar(ProgressBar);
impl UwUProgressBar {
#[inline]
pub fn new(file_total_bytes: u64) -> UwUProgressBar {
let progress_bar = ProgressBar::new(file_total_bytes);
progress_bar.set_style(ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] [{bar:60.cyan/blue}] {bytes}/{total_bytes} ({eta}) {msg}")
.progress_chars("#>-"));
UwUProgressBar {
downloaded_bytes: 0,
progress_bar,
}
UwUProgressBar(progress_bar)
}
#[inline]
pub fn update_progess(&mut self, bytes_read_in: usize) {
self.downloaded_bytes += bytes_read_in as u64;
self.progress_bar.set_position(self.downloaded_bytes);
self.0.inc(bytes_read_in as u64);
}
#[inline]
pub fn finish(&self, message: &'static str) {
self.progress_bar.finish_with_message(message);
self.0.finish_with_message(message);
}
}

@ -1,35 +1,41 @@
use rand::{Rng, rngs::ThreadRng, thread_rng};
use rand_pcg::Pcg32;
use rand_seeder::Seeder;
use std::hash::Hasher;
use rand::{
distributions::uniform::{SampleRange, SampleUniform},
Rng, RngCore, SeedableRng,
};
use rand_xoshiro::{Xoshiro256Plus, Xoshiro256PlusPlus};
pub struct UwUSeeder {
seeder: Pcg32,
rng: ThreadRng,
random: bool,
floating: Xoshiro256Plus,
int: Xoshiro256PlusPlus,
}
impl UwUSeeder {
#[inline]
pub fn new(word: &str, random: bool) -> UwUSeeder {
UwUSeeder {
seeder: Seeder::from(word).make_rng(),
rng: thread_rng(),
random,
}
let entropy = match random {
true => rand::rngs::OsRng.next_u64(),
false => {
let mut hasher = ahash::AHasher::default();
hasher.write(word.as_bytes());
hasher.finish()
}
};
pub fn random(&mut self) -> f32 {
if self.random {
self.rng.gen_range(0.0..1.0)
} else {
self.seeder.gen_range(0.0..1.0)
UwUSeeder {
floating: Xoshiro256Plus::seed_from_u64(entropy),
int: Xoshiro256PlusPlus::seed_from_u64(entropy),
}
}
pub fn random_int(&mut self, min: i32, max: i32) -> usize {
if self.random {
self.rng.gen_range(min..max) as usize
} else {
self.seeder.gen_range(min..max) as usize
#[inline]
pub fn random(&mut self) -> f64 {
f64::from_ne_bytes(self.floating.next_u64().to_ne_bytes())
}
#[inline]
pub fn random_int<T: SampleUniform, R: SampleRange<T>>(&mut self, range: R) -> T {
self.int.gen_range(range)
}
}
Loading…
Cancel
Save