use std::num::Wrapping;
pub fn translate(english: &[u8], pig_latin_string: &mut Vec::<u8>) {
translate_way(english, pig_latin_string);
}
pub fn translate_way(english: &[u8], pig_latin_string: &mut Vec::<u8>) {
translate_with_style_lower_and_upper_suffixes(english, b"ay", b"way", b"AY", b"WAY", pig_latin_string);
}
pub fn translate_yay(english: &[u8], pig_latin_string: &mut Vec::<u8>) {
translate_with_style_lower_and_upper_suffixes(english, b"ay", b"yay", b"AY", b"WAY", pig_latin_string);
}
pub fn translate_hay(english: &[u8], pig_latin_string: &mut Vec::<u8>) {
translate_with_style_lower_and_upper_suffixes(english, b"ay", b"hay", b"AY", b"HAY", pig_latin_string);
}
pub fn translate_ferb(english: &[u8], pig_latin_string: &mut Vec::<u8>) {
translate_with_style_lower_and_upper_suffixes(english, b"erb", b"ferb", b"ERB", b"FERB", pig_latin_string);
}
pub fn translate_with_style(english: &[u8], suffix_lower: &[u8], special_case_suffix_lower: &[u8], pig_latin_string: &mut Vec::<u8>) {
let mut suffix_upper = Vec::<u8>::with_capacity(suffix_lower.len());
for letter in suffix_lower.iter() {
suffix_upper.push(letter.to_ascii_uppercase()); }
let mut special_case_suffix_upper = Vec::<u8>::with_capacity(special_case_suffix_lower.len());
for letter in special_case_suffix_lower.iter() {
special_case_suffix_upper.push(letter.to_ascii_uppercase()); }
translate_with_style_lower_and_upper_suffixes(english, suffix_lower, special_case_suffix_lower, &suffix_upper, &special_case_suffix_upper, pig_latin_string);
}
pub(crate) fn translate_with_style_lower_and_upper_suffixes (
english: &[u8],
suffix_lower: &[u8], special_case_suffix_lower: &[u8], suffix_upper: &[u8], special_case_suffix_upper: &[u8],
pig_latin_string: &mut Vec::<u8>
) {
if english.is_empty() {
return;
}
let mut in_word: bool = false;
let mut in_contraction_suffix: bool = false;
let mut slice_start_index: usize = 0; let mut slice_end_index: usize = 0;
for character in english.iter() {
if in_word {
if in_contraction_suffix {
if character.is_ascii_alphabetic() {
} else {
in_contraction_suffix = false;
in_word = false;
}
pig_latin_string.push(*character); slice_start_index += 1; } else {
if character.is_ascii_alphabetic() {
slice_end_index += 1;
} else {
let word_slice: &[u8] = &english[slice_start_index..slice_end_index];
translate_word_with_style_reuse_buffers (
word_slice,
suffix_lower, special_case_suffix_lower, suffix_upper, special_case_suffix_upper,
pig_latin_string
);
slice_start_index = slice_end_index + 1;
pig_latin_string.push(*character);
if *character == b'\'' {
in_contraction_suffix = true;
} else {
in_word = false; }
}
}
} else {
if character.is_ascii_alphabetic() {
in_word = true;
slice_end_index = slice_start_index + 1;
} else {
pig_latin_string.push(*character);
slice_start_index += 1;
}
}
}
if in_word && !in_contraction_suffix {
let word_slice: &[u8] = &english[slice_start_index..slice_end_index];
translate_word_with_style_reuse_buffers (
word_slice,
suffix_lower, special_case_suffix_lower, suffix_upper, special_case_suffix_upper,
pig_latin_string
);
}
}
#[inline(always)]fn translate_word_with_style_reuse_buffers (
english_word: &[u8], suffix_lower: &[u8], special_case_suffix_lower: &[u8], suffix_upper: &[u8], special_case_suffix_upper: &[u8],
buffer_to_append_to: &mut Vec<u8>
) {
debug_assert!(english_word.len() != 0);
if english_word.len() == 0 {
unsafe {
std::hint::unreachable_unchecked();
}
}
if english_word.len() == 1 { buffer_to_append_to.extend_from_slice(english_word);
buffer_to_append_to.extend_from_slice(special_case_suffix_lower);
return;
}
let word_uppercase = word_is_uppercase(english_word);
if is_vowel(english_word[0]) { buffer_to_append_to.extend_from_slice(english_word);
if word_uppercase {
buffer_to_append_to.extend_from_slice(special_case_suffix_upper);
} else {
buffer_to_append_to.extend_from_slice(special_case_suffix_lower);
}
return;
}
let mut index_of_first_vowel: usize = 1;
while index_of_first_vowel < english_word.len() {
let character: u8 = english_word[index_of_first_vowel];
if is_vowel(character) || is_y(character) { break;
}
index_of_first_vowel += 1;
}
if index_of_first_vowel < english_word.len() { if fast_is_ascii_uppercase(english_word[0]) {
buffer_to_append_to.push(fast_to_ascii_uppercase(english_word[index_of_first_vowel]));
} else {
buffer_to_append_to.push(english_word[index_of_first_vowel]);
}
buffer_to_append_to.extend_from_slice(&english_word[(index_of_first_vowel + 1)..]);
buffer_to_append_to.push(if word_uppercase { english_word[0] } else { fast_to_ascii_lowercase(english_word[0]) });
buffer_to_append_to.extend_from_slice(&english_word[1..index_of_first_vowel]);
} else { buffer_to_append_to.extend_from_slice(english_word);
}
if word_uppercase { buffer_to_append_to.extend_from_slice(suffix_upper);
} else {
buffer_to_append_to.extend_from_slice(suffix_lower);
}
}
#[inline(always)]fn is_vowel(letter: u8) -> bool {
match letter {
b'a' | b'e' | b'i' | b'o' | b'u' | b'A' | b'E' | b'I' | b'O' | b'U' => { return true; }
_ => { return false; }
}
}
#[inline(always)]fn is_y(letter: u8) -> bool {
return (letter == b'y') || (letter == b'Y');
}
#[inline(always)]fn word_is_uppercase(english_word: &[u8]) -> bool {
debug_assert!(english_word.len() != 0);
if english_word.len() == 0 {
unsafe {
std::hint::unreachable_unchecked();
}
}
return fast_is_ascii_uppercase(english_word[english_word.len() - 1]);
}
#[inline(always)]fn fast_is_ascii_uppercase(letter: u8) -> bool {
return letter <= b'Z';
}
#[inline(always)]fn fast_to_ascii_uppercase(letter: u8) -> u8 {
return if letter >= b'a' { (Wrapping(letter) - Wrapping(0x20)).0 } else { letter };
}
#[inline(always)]fn fast_to_ascii_lowercase(letter: u8) -> u8 {
return if letter <= b'Z' { (Wrapping(letter) + Wrapping(0x20)).0 } else { letter };
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_translate_word_with_style() {
let suffix_special_case_suffix_pairs = [
("ay", "way"), ("ay", "yay"), ("ay", "hay"), ("erb", "ferb"), ("ancy", "fancy"), ("orange", "porange"), ("anana", "banana"), ("atin", "latin"), ("ust", "rust")
];
for pair in suffix_special_case_suffix_pairs {
let suffix = pair.0;
let special_case_suffix = pair.1;
assert_eq!(translate_word_with_style("Hello", suffix, special_case_suffix), "Elloh".to_string() + suffix);
assert_eq!(translate_word_with_style("World", suffix, special_case_suffix), "Orldw".to_string() + suffix);
assert_eq!(translate_word_with_style("This", suffix, special_case_suffix), "Isth".to_string() + suffix);
assert_eq!(translate_word_with_style("is", suffix, special_case_suffix), "is".to_string() + special_case_suffix);
assert_eq!(translate_word_with_style("a", suffix, special_case_suffix), "a".to_string() + special_case_suffix);
assert_eq!(translate_word_with_style("test", suffix, special_case_suffix), "estt".to_string() + suffix);
assert_eq!(translate_word_with_style("of", suffix, special_case_suffix), "of".to_string() + special_case_suffix);
assert_eq!(translate_word_with_style("the", suffix, special_case_suffix), "eth".to_string() + suffix);
assert_eq!(translate_word_with_style("function", suffix, special_case_suffix), "unctionf".to_string() + suffix);
assert_eq!(translate_word_with_style("translate", suffix, special_case_suffix), "anslatetr".to_string() + suffix);
assert_eq!(translate_word_with_style("word", suffix, special_case_suffix), "ordw".to_string() + suffix);
assert_eq!(translate_word_with_style("I", suffix, special_case_suffix), "I".to_string() + special_case_suffix);
assert_eq!(translate_word_with_style("Love", suffix, special_case_suffix), "Ovel".to_string() + suffix);
assert_eq!(translate_word_with_style("Pig", suffix, special_case_suffix), "Igp".to_string() + suffix);
assert_eq!(translate_word_with_style("Latin", suffix, special_case_suffix), "Atinl".to_string() + suffix);
assert_eq!(translate_word_with_style("You", suffix, special_case_suffix), "Ouy".to_string() + suffix); assert_eq!(translate_word_with_style("should", suffix, special_case_suffix), "ouldsh".to_string() + suffix);
assert_eq!(translate_word_with_style("try", suffix, special_case_suffix), "ytr".to_string() + suffix); assert_eq!(translate_word_with_style("yougurt", suffix, special_case_suffix), "ougurty".to_string() + suffix); assert_eq!(translate_word_with_style("quite", suffix, special_case_suffix), "uiteq".to_string() + suffix); assert_eq!(translate_word_with_style("nice", suffix, special_case_suffix), "icen".to_string() + suffix);
}
}
fn translate_word_with_style(english_word: &str, suffix_lower: &str, special_case_suffix_lower: &str) -> String {
let mut suffix_upper = String::new();
for letter in suffix_lower.chars() {
suffix_upper.push(letter.to_ascii_uppercase());
}
let mut special_case_suffix_upper = String::new();
for letter in special_case_suffix_lower.chars() {
special_case_suffix_upper.push(letter.to_ascii_uppercase());
}
let mut pig_latin_word = Vec::<u8>::new();
translate_word_with_style_reuse_buffers (
english_word.as_bytes(),
suffix_lower.as_bytes(), special_case_suffix_lower.as_bytes(), &suffix_upper.as_bytes(), &special_case_suffix_upper.as_bytes(),
&mut pig_latin_word
);
return std::str::from_utf8(pig_latin_word.as_slice()).unwrap().to_string();
}
#[test]
fn test_is_vowel() {
for letter in b"aeiouAEIOU".iter() {
assert!(is_vowel(*letter));
}
for letter in b"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ".iter() {
assert!(!is_vowel(*letter));
}
for not_letter in b" !@#$%^&*()_+={}|\":>?~`\\][';/.,\t\n".iter() {
assert!(!is_vowel(*not_letter));
}
}
#[test]
fn test_is_y() {
for letter in b"yY".iter() {
assert!(is_y(*letter));
}
for letter in b"abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXZ".iter() {
assert!(!is_y(*letter));
}
for not_letter in b" !@#$%^&*()_+={}|\":>?~`\\][';/.,\t\n".iter() {
assert!(!is_y(*not_letter));
}
}
#[test]
fn test_word_is_uppercase() {
assert!(word_is_uppercase(b"HELLO"));
assert!(word_is_uppercase(b"WORLD"));
assert!(word_is_uppercase(b"I"));
assert!(!word_is_uppercase(b"would"));
assert!(!word_is_uppercase(b"like"));
assert!(!word_is_uppercase(b"a"));
assert!(!word_is_uppercase(b"pizza"));
assert!(!word_is_uppercase(b"Sussus"));
assert!(!word_is_uppercase(b"Amogus"));
}
#[test]
fn test_fast_is_ascii_uppercase() {
for letter in b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".iter() {
assert_eq!(fast_is_ascii_uppercase(*letter), letter.is_ascii_uppercase());
}
}
#[test]
fn test_fast_to_ascii_uppercase() {
for letter in b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".iter() {
assert_eq!(fast_to_ascii_uppercase(*letter), letter.to_ascii_uppercase());
}
}
#[test]
fn test_fast_to_ascii_lowercase() {
for letter in b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".iter() {
assert_eq!(fast_to_ascii_lowercase(*letter), letter.to_ascii_lowercase());
}
}
}
#[cfg_attr(feature = "nightly-features-benches", cfg(test))]
#[cfg(feature = "nightly-features-benches")]
mod benches {
extern crate test;
use test::Bencher;
use super::*;
const PROJECT_DESCRIPTION: &[u8] = b"A simple Rust library to translate from English to Pig Latin!";
const LOREM_IPSUM: &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
#[bench]
fn way_the_word_translator(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(64 * 2);
b.iter(|| {
let word = test::black_box(b"translator");
translate_word_with_style_reuse_buffers (
word,
b"ay", b"way", b"AY", b"WAY",
&mut pig_latin_word
);
pig_latin_word.truncate(0);
});
eprintln!("{}", std::str::from_utf8(pig_latin_word.as_slice()).unwrap()); }
#[bench]
fn yay_the_word_translator(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(64 * 2);
b.iter(|| {
let word = test::black_box(b"translator");
translate_word_with_style_reuse_buffers (
word,
b"ay", b"yay", b"AY", b"YAY",
&mut pig_latin_word
);
pig_latin_word.truncate(0);
});
eprintln!("{}", std::str::from_utf8(pig_latin_word.as_slice()).unwrap()); }
#[bench]
fn hay_the_word_translator(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(64 * 2);
b.iter(|| {
let word = test::black_box(b"translator");
translate_word_with_style_reuse_buffers (
word,
b"ay", b"hay", b"AY", b"HAY",
&mut pig_latin_word
);
pig_latin_word.truncate(0);
});
eprintln!("{}", std::str::from_utf8(pig_latin_word.as_slice()).unwrap()); }
#[bench]
fn ferb_the_word_translator(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(64 * 2);
b.iter(|| {
let word = test::black_box(b"translator");
translate_word_with_style_reuse_buffers (
word,
b"erb", b"ferb", b"ERB", b"FERB",
&mut pig_latin_word
);
pig_latin_word.truncate(0);
});
eprintln!("{}", std::str::from_utf8(pig_latin_word.as_slice()).unwrap()); }
#[bench]
fn way_project_description(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(PROJECT_DESCRIPTION.len() * 2);
b.iter(|| {
let word = test::black_box(PROJECT_DESCRIPTION);
translate_way(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn yay_project_description(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(PROJECT_DESCRIPTION.len() * 2);
b.iter(|| {
let word = test::black_box(PROJECT_DESCRIPTION);
translate_yay(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn hay_project_description(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(PROJECT_DESCRIPTION.len() * 2);
b.iter(|| {
let word = test::black_box(PROJECT_DESCRIPTION);
translate_hay(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn ferb_project_description(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(PROJECT_DESCRIPTION.len() * 2);
b.iter(|| {
let word = test::black_box(PROJECT_DESCRIPTION);
translate_ferb(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn way_lorem_ipsum(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(LOREM_IPSUM.len() * 2);
b.iter(|| {
let word = test::black_box(LOREM_IPSUM);
translate_way(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn yay_lorem_ipsum(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(LOREM_IPSUM.len() * 2);
b.iter(|| {
let word = test::black_box(LOREM_IPSUM);
translate_yay(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn hay_lorem_ipsum(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(LOREM_IPSUM.len() * 2);
b.iter(|| {
let word = test::black_box(LOREM_IPSUM);
translate_hay(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
#[bench]
fn ferb_lorem_ipsum(b: &mut Bencher) {
let mut pig_latin_word = Vec::<u8>::with_capacity(LOREM_IPSUM.len() * 2);
b.iter(|| {
let word = test::black_box(LOREM_IPSUM);
translate_ferb(word, &mut pig_latin_word);
pig_latin_word.truncate(0);
});
}
}