pub fn bubblebabble(bytes: &[u8]) -> String {
bubblebabble_impl(bytes, true)
}
pub fn stablebabble(bytes: &[u8]) -> String {
bubblebabble_impl(bytes, false)
}
fn bubblebabble_impl(bytes: &[u8], use_seed: bool) -> String {
let vowels = ['a', 'e', 'i', 'o', 'u', 'y'];
let consonants = [
'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'z', 'x',
];
let rounds = (bytes.len() / 2) + 1;
let mut bubble = String::with_capacity(rounds * 6);
let mut seed = 1;
bubble.push('x');
for i in 0..rounds {
let mut idx = [0usize; 5];
if (i + 1 < rounds) || bytes.len() % 2 != 0 {
idx[0] = ((((bytes[2 * i]) as usize >> 6) & 3) + seed) % 6;
idx[1] = ((bytes[2 * i]) >> 2) as usize & 15;
idx[2] = (((bytes[2 * i]) & 3) as usize + (seed / 6)) % 6;
bubble.push(vowels[idx[0]]);
bubble.push(consonants[idx[1]]);
bubble.push(vowels[idx[2]]);
if (i + 1) < rounds {
idx[3] = ((bytes[(2 * i) + 1]) as usize >> 4) & 15;
idx[4] = ((bytes[(2 * i) + 1]) as usize) & 15;
bubble.push(consonants[idx[3]]);
bubble.push('-');
bubble.push(consonants[idx[4]]);
seed = if use_seed {
((seed * 5)
+ (((bytes[2 * i]) as usize * 7) as usize
+ ((bytes[(2 * i) as usize + 1]) as usize)))
% 36
} else {
0
};
}
} else {
idx[0] = seed % 6;
idx[1] = 16;
idx[2] = seed / 6;
bubble.push(vowels[idx[0]]);
bubble.push(consonants[idx[1]]);
bubble.push(vowels[idx[2]]);
}
}
bubble.push('x');
if use_seed {
return bubble;
}
let mut result = String::new();
let mut last = "";
let mut count = 1;
for (i, word) in bubble.split('-').enumerate() {
if last == word {
count += 1;
} else if i > 0 {
if i > 1 {
result.push('-');
}
if count > 1 {
result.push_str(&count.to_string());
}
result.push_str(last);
count = 1;
}
last = word;
}
result.push('-');
result.push_str(last);
result.replace("babab", "wa")
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv6Addr;
#[test]
fn test_bubblebabble() {
let tests = [
(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
"xebab-bybab-bebub-bybib-bebib-bybub-bebab-bybab-bexux",
),
(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
"xebab-bybab-bebub-bybib-bebib-bybub-bebab-bybab-cixux",
),
(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2),
"xebab-bybab-bebub-bybib-bebib-bybub-bebab-bybab-doxux",
),
(
"2a0a:e5c0:2:5:5cf9:ccc8:7c48:97c0".parse().unwrap(),
"xepib-panus-bubub-dubyb-hilyz-nefas-myzug-mihos-bexux",
),
(
"fe80::4685:ff:fe76:1722".parse().unwrap(),
"xuzim-bobab-bobib-bobab-bucum-hibiz-zuzil-kyhed-duxix",
),
];
for addr in tests.iter() {
assert_eq!(bubblebabble(&(addr.0).octets()), addr.1);
}
}
#[test]
fn test_stablebabble() {
let tests = [
(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), "xebab-7wa-baxax"),
(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), "xebab-7wa-caxax"),
(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2), "xebab-7wa-daxax"),
(
"2a0a:e5c0:2:5:5cf9:ccc8:7c48:97c0".parse().unwrap(),
"xepib-pones-wa-dabab-helaz-nofas-mezag-mihos-baxax",
),
(
"fe80::4685:ff:fe76:1722".parse().unwrap(),
"xuzim-3wa-becim-habaz-zozil-kahod-daxax",
),
];
for addr in tests.iter() {
assert_eq!(stablebabble(&(addr.0).octets()), addr.1);
}
}
}