Merge pull request #5 from StratusFearMe21/main

pull/8/head
Hamothy 3 years ago committed by GitHub
commit a3ede681c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,7 +15,7 @@ exclude = [
"examples/tokyo-2020-olympics-tweets.csv",
"examples/uwu/**",
".github/**",
"scripts/**"
"scripts/**",
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -31,11 +31,19 @@ linkify = "0.8.0"
rand_xoshiro = "0.6.0"
ahash = "0.7.6"
memmap = "0.7.0"
kaomoji-ru = "1.0.1"
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
[profile.dev]
overflow-checks = false
[profile.bench]
lto = "fat"
codegen-units = 1
[features]
bench = []

@ -1,4 +1,4 @@
pub const FACES_SIZE: usize = 14;
pub const FACES_SIZE: usize = 106;
pub const FACES: [&[u8]; FACES_SIZE] = [
b"OwO",
b"UwU",
@ -14,8 +14,241 @@ pub const FACES: [&[u8]; FACES_SIZE] = [
b"^.^",
b":33",
b"uWu",
// (* ^ ω ^)
kaomoji_ru::positive_emotions::JOY[0],
// (´ ∀ ` *)
kaomoji_ru::positive_emotions::JOY[1],
// (o^▽^o)
kaomoji_ru::positive_emotions::JOY[4],
// (⌒▽⌒)☆
kaomoji_ru::positive_emotions::JOY[5],
// <( ̄︶ ̄)>
kaomoji_ru::positive_emotions::JOY[6],
// ヽ(・∀・)ノ
kaomoji_ru::positive_emotions::JOY[8],
// (´。• ω •。`)
kaomoji_ru::positive_emotions::JOY[9],
// ( ̄ω ̄)
kaomoji_ru::positive_emotions::JOY[10],
// (o・ω・o)
kaomoji_ru::positive_emotions::JOY[12],
// ヽ(*・ω・)ノ
kaomoji_ru::positive_emotions::JOY[14],
// (^人^)
kaomoji_ru::positive_emotions::JOY[16],
// (*´▽`*)
kaomoji_ru::positive_emotions::JOY[18],
// ( ´ ω ` )
kaomoji_ru::positive_emotions::JOY[20],
// (≧◡≦)
kaomoji_ru::positive_emotions::JOY[22],
// (o´∀`o)
kaomoji_ru::positive_emotions::JOY[23],
// (´• ω •`)
kaomoji_ru::positive_emotions::JOY[24],
// (^▽^)
kaomoji_ru::positive_emotions::JOY[25],
// (⌒ω⌒)
kaomoji_ru::positive_emotions::JOY[26],
// ╰(▔∀▔)╯
kaomoji_ru::positive_emotions::JOY[28],
// (*^‿^*)
kaomoji_ru::positive_emotions::JOY[30],
// (✯◡✯)
kaomoji_ru::positive_emotions::JOY[32],
// (*≧ω≦*)
kaomoji_ru::positive_emotions::JOY[34],
// (☆▽☆)
kaomoji_ru::positive_emotions::JOY[35],
// (≧▽≦)
kaomoji_ru::positive_emotions::JOY[37],
// ヽ(oo)
kaomoji_ru::positive_emotions::JOY[38],
// (*°▽°*)
kaomoji_ru::positive_emotions::JOY[40],
// (✧ω✧)
kaomoji_ru::positive_emotions::JOY[42],
// ヽ(*⌒▽⌒*)ノ
kaomoji_ru::positive_emotions::JOY[43],
// ヽ(>∀<☆)
kaomoji_ru::positive_emotions::JOY[48],
// o(≧▽≦)o
kaomoji_ru::positive_emotions::JOY[49],
// (☆ω☆)
kaomoji_ru::positive_emotions::JOY[50],
// (っ˘ω˘ς )
kaomoji_ru::positive_emotions::JOY[51],
// \(★ω★)/
kaomoji_ru::positive_emotions::JOY[57],
// (╯✧▽✧)╯
kaomoji_ru::positive_emotions::JOY[60],
// o(>ω<)o
kaomoji_ru::positive_emotions::JOY[61],
// (´・ᴗ・ ` )
kaomoji_ru::positive_emotions::JOY[72],
// (¬‿¬ )
kaomoji_ru::positive_emotions::JOY[77],
// („• ᴗ •„)
kaomoji_ru::positive_emotions::JOY[84],
// (´ ω `♡)
kaomoji_ru::positive_emotions::LOVE[12],
// (♡°▽°♡)
kaomoji_ru::positive_emotions::LOVE[17],
// ♡(。- ω -)
kaomoji_ru::positive_emotions::LOVE[18],
// (´。• ω •。`) ♡
kaomoji_ru::positive_emotions::LOVE[22],
// (❤ω❤)
kaomoji_ru::positive_emotions::LOVE[39],
// (´,,•ω•,,)♡
kaomoji_ru::positive_emotions::LOVE[45],
// (*ノωノ)
kaomoji_ru::positive_emotions::EMBARRESMENT[5],
// ( ⁄•⁄ω⁄•⁄ )
kaomoji_ru::positive_emotions::EMBARRESMENT[17],
// (# ̄ω ̄)
kaomoji_ru::negative_emotions::DISSATISFACTION[7],
// ()
kaomoji_ru::negative_emotions::DISSATISFACTION[9],
// (」°ロ°)」
kaomoji_ru::negative_emotions::DISSATISFACTION[10],
// (ᗒᗣᗕ)՞
kaomoji_ru::negative_emotions::DISSATISFACTION[24],
// (`Д´)
kaomoji_ru::negative_emotions::ANGER[0],
// (・`ω´・)
kaomoji_ru::negative_emotions::ANGER[4],
// (°ㅂ°╬)
kaomoji_ru::negative_emotions::ANGER[17],
// (╬ Ò﹏Ó)
kaomoji_ru::negative_emotions::ANGER[25],
// (´-ω-`)
kaomoji_ru::negative_emotions::SADNESS[2],
// (-ω-、)
kaomoji_ru::negative_emotions::SADNESS[6],
// ( ; ω ; )
kaomoji_ru::negative_emotions::SADNESS[9],
// ( ╥ω╥ )
kaomoji_ru::negative_emotions::SADNESS[16],
// (ノωヽ)
kaomoji_ru::negative_emotions::FEAR[0],
// (・_・ヾ
kaomoji_ru::neutral_emotions::CONFUSSION[5],
// ╮( ̄ω ̄;)╭
kaomoji_ru::neutral_emotions::CONFUSSION[10],
// (*・ω・)ノ
kaomoji_ru::various_actions::GREETING[0],
// (✧∀✧)/
kaomoji_ru::various_actions::GREETING[25],
// (つ≧▽≦)つ
kaomoji_ru::various_actions::HUGGING[1],
// (つ✧ω✧)つ
kaomoji_ru::various_actions::HUGGING[2],
// ⊂(´• ω •`⊂)
kaomoji_ru::various_actions::HUGGING[8],
// ⊂(・ω・*⊂)
kaomoji_ru::various_actions::HUGGING[9],
// (^ω~)
kaomoji_ru::various_actions::WINKING[3],
// |・ω・)
kaomoji_ru::various_actions::HIDING[0],
// ☆ミ(o*・ω・)ノ
kaomoji_ru::various_actions::RUNNING[0],
// C= C= C= C= C=┌(;・ω・)┘
kaomoji_ru::various_actions::RUNNING[1],
// ε===(っ≧ω≦)っ
kaomoji_ru::various_actions::RUNNING[6],
// (-ω-) zzZ
kaomoji_ru::various_actions::SLEEPING[3],
// (=^・ω・^=)
kaomoji_ru::animals::CAT[0],
// (=^・ェ・^=)
kaomoji_ru::animals::CAT[1],
// (=①ω①=)
kaomoji_ru::animals::CAT[2],
// ( =ω=)..nyaa
kaomoji_ru::animals::CAT[3],
// (= ; ェ ; =)
kaomoji_ru::animals::CAT[4],
// (=`ω´=)
kaomoji_ru::animals::CAT[5],
// (=^‥^=)
kaomoji_ru::animals::CAT[6],
// ( =ノωヽ=)
kaomoji_ru::animals::CAT[9],
// (=^ ◡ ^=)
kaomoji_ru::animals::CAT[11],
// (=^-ω-^=)
kaomoji_ru::animals::CAT[12],
// ヾ(=`ω´=)ノ”
kaomoji_ru::animals::CAT[13],
// (^• ω •^)
kaomoji_ru::animals::CAT[14],
// (/ =ω=)/
kaomoji_ru::animals::CAT[15],
// ฅ(•ㅅ•❀)ฅ
kaomoji_ru::animals::CAT[16],
// ଲ(ⓛ ω ⓛ)ଲ
kaomoji_ru::animals::CAT[18],
// (^=◕ᴥ◕=^)
kaomoji_ru::animals::CAT[19],
// ( =ω= )
kaomoji_ru::animals::CAT[20],
// (^◔ᴥ◔^)
kaomoji_ru::animals::CAT[25],
// ( ・ω・)☞
kaomoji_ru::special::POINTING,
];
pub const ASCII_SIZE: usize = ascii_len(&FACES);
pub const ASCII: [&[u8]; ASCII_SIZE] = ascii_array(&FACES);
pub const fn ascii_len(array: &[&[u8]]) -> usize {
let mut result = 0;
let len = array.len();
let mut head = 0;
while head != len {
let mut ascii_head = 0;
let ascii_len = array[head].len();
let mut ascii_res = 0;
while ascii_head != ascii_len {
if array[head][ascii_head].is_ascii() {
ascii_res += 1;
}
ascii_head += 1;
}
if ascii_res == array[head].len() {
result += 1;
}
head += 1;
}
result
}
pub const fn ascii_array(array: &'static [&'static [u8]]) -> [&'static [u8]; ASCII_SIZE] {
let mut ascii_array: [&'static [u8]; ASCII_SIZE] = [&[]; ASCII_SIZE];
let mut result_head = 0;
let len = array.len();
let mut head = 0;
while head != len {
let mut ascii_head = 0;
let ascii_len = array[head].len();
let mut ascii_res = 0;
while ascii_head != ascii_len {
if array[head][ascii_head].is_ascii() {
ascii_res += 1;
}
ascii_head += 1;
}
if ascii_res == array[head].len() {
ascii_array[result_head] = array[head];
result_head += 1;
}
head += 1;
}
ascii_array
}
pub const ACTIONS_SIZE: usize = 17;
pub const ACTIONS: [&[u8]; ACTIONS_SIZE] = [
b"*notices bulge* ",

@ -1,35 +1,55 @@
#![cfg_attr(all(feature = "bench", test), feature(test))]
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::str::from_utf8_unchecked;
use indicatif::{ProgressBar, ProgressStyle};
use ahash::RandomState;
use linkify::{LinkFinder, LinkKind};
use memmap::Mmap;
use constants::ACTIONS;
use constants::ACTIONS_SIZE;
use constants::FACES;
use constants::FACES_SIZE;
use seeder::UwUSeeder;
use constants::{ACTIONS, ASCII, ASCII_SIZE};
mod constants;
mod seeder;
macro_rules! progress_bar {
($bytes:expr) => {{
let progress_bar = ProgressBar::new($bytes);
progress_bar.set_style(
ProgressStyle::default_spinner()
() => {{
let progress_bar = indicatif::ProgressBar::new_spinner()
.with_style(
indicatif::ProgressStyle::default_spinner()
.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
}};
}
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)]
pub struct UwUify<'a> {
text: &'a str,
@ -39,7 +59,8 @@ pub struct UwUify<'a> {
faces: f64,
actions: f64,
stutters: f64,
random: bool,
random: RandomState,
ascii: bool,
is_runtime: bool,
linkify: LinkFinder,
}
@ -54,8 +75,9 @@ impl<'a> Default for UwUify<'a> {
faces: 0.05,
actions: 0.125,
stutters: 0.225,
random: false,
random: RandomState::with_seeds(69, 420, 96, 84),
is_runtime: false,
ascii: false,
linkify: LinkFinder::new(),
}
}
@ -70,6 +92,7 @@ impl<'a> UwUify<'a> {
faces: Option<&'a str>,
actions: Option<&'a str>,
stutters: Option<&'a str>,
ascii: bool,
random: bool,
is_runtime: bool,
) -> UwUify<'a> {
@ -81,12 +104,16 @@ impl<'a> UwUify<'a> {
text: text.unwrap_or_default(),
input: infile.unwrap_or_default(),
output: outfile.unwrap_or_default(),
random,
ascii,
is_runtime,
linkify,
..Default::default()
};
if random {
uwuify.random = RandomState::new();
}
if let Some(words) = words {
uwuify.words = words.parse::<f64>().unwrap();
}
@ -103,7 +130,7 @@ impl<'a> UwUify<'a> {
uwuify
}
pub fn uwuify(&mut self) -> Result<(), Error> {
pub fn uwuify(&self) -> Result<(), Error> {
// Handle Text
if !self.text.is_empty() {
// 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)?))?;
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
} 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 {
// Handle File I/O
@ -130,10 +160,9 @@ impl<'a> UwUify<'a> {
));
}
let infile = File::open(&self.input)?;
let uwu_progress_bar = progress_bar!(infile.metadata()?.len());
let uwu_progress_bar = progress_bar!();
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)?),
)?;
uwu_progress_bar.finish_with_message("UwU'ifying Complete!");
@ -142,19 +171,24 @@ impl<'a> UwUify<'a> {
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| {
line.split_whitespace()
.map(|word_str| word_str.as_bytes())
.try_for_each(|word| {
let mut seeder = UwUSeeder::new(word, self.random);
let random_value = seeder.random_float();
let mut seeder = new_seeder!(word, &self.random);
let random_value = random_float!(&mut seeder);
if !self.is_runtime {
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 {
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 {
match word[0] {
b'L' | b'R' => out.write_all(b"W"),
@ -165,10 +199,15 @@ impl<'a> UwUify<'a> {
}
} else {
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 {
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 {
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());
}
}

@ -25,6 +25,12 @@ macro_rules! app {
.required_unless_present_all(["infile", "outfile"])
.display_order(1),
)
.arg(
Arg::new("ascii-only")
.help("The output file will not use UTF-8 charecters")
.long("ascii-only")
.display_order(2),
)
.arg(
Arg::new("infile")
.help("The file to uwu'ify")
@ -34,7 +40,7 @@ macro_rules! app {
.requires("outfile")
.value_name("FILE")
.value_hint(clap::ValueHint::FilePath)
.display_order(2),
.display_order(3),
)
.arg(
Arg::new("outfile")
@ -43,7 +49,7 @@ macro_rules! app {
.long("outfile")
.value_name("FILE")
.value_hint(clap::ValueHint::FilePath)
.display_order(3),
.display_order(4),
)
.arg(
Arg::new("words")
@ -53,7 +59,7 @@ macro_rules! app {
.value_name("VALUE")
.default_value("1")
.validator(is_between_zero_and_one)
.display_order(4),
.display_order(5),
)
.arg(
Arg::new("faces")
@ -63,7 +69,7 @@ macro_rules! app {
.value_name("VALUE")
.default_value("0.05")
.validator(is_between_zero_and_one)
.display_order(5),
.display_order(6),
)
.arg(
Arg::new("actions")
@ -73,7 +79,7 @@ macro_rules! app {
.value_name("VALUE")
.default_value("0.125")
.validator(is_between_zero_and_one)
.display_order(6),
.display_order(7),
)
.arg(
Arg::new("stutters")
@ -83,14 +89,14 @@ macro_rules! app {
.value_name("VALUE")
.default_value("0.225")
.validator(is_between_zero_and_one)
.display_order(7),
.display_order(8),
)
.arg(
Arg::new("random")
.help("Flag to enable/disable random uwu'ifying")
.short('r')
.long("random")
.display_order(8),
.display_order(9),
)
};
}
@ -119,6 +125,7 @@ fn main() {
matches.value_of("faces"),
matches.value_of("actions"),
matches.value_of("stutters"),
matches.is_present("ascii-only"),
matches.is_present("random"),
is_runtime!(
matches.occurrences_of("faces"),

@ -1,34 +0,0 @@
use std::hash::Hasher;
use ahash::AHasher;
use rand::distributions::uniform::{SampleRange, SampleUniform};
use rand::{Rng, RngCore, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
pub struct UwUSeeder {
rng: Xoshiro256Plus,
}
impl UwUSeeder {
pub fn new(word: &[u8], random: bool) -> UwUSeeder {
let rand_u64 = if !random {
let mut hasher = AHasher::new_with_keys(0, 0);
hasher.write(word);
hasher.finish()
} else {
rand::rngs::OsRng::default().next_u64()
};
UwUSeeder {
rng: Xoshiro256Plus::seed_from_u64(rand_u64),
}
}
pub fn random_float(&mut self) -> f64 {
self.rng.gen_range(0.0..1.0)
}
pub fn random_int<T: SampleUniform, R: SampleRange<T>>(&mut self, range: R) -> T {
self.rng.gen_range(range)
}
}

@ -0,0 +1,14 @@
From fairest creatures we desire increase,
That thereby beauty's rose might never die,
But as the riper should by time decease,
His tender heir might bear his memory:
But thou contracted to thine own bright eyes,
Feed'st thy light's flame with self-substantial fuel,
Making a famine where abundance lies,
Thy self thy foe, to thy sweet self too cruel:
Thou that art now the world's fresh ornament,
And only herald to the gaudy spring,
Within thine own bud buriest thy content,
And tender churl mak'st waste in niggarding:
Pity the world, or else this glutton be,
To eat the world's due, by the grave and thee.
Loading…
Cancel
Save