pub trait Write {
unsafe fn write(&mut self, u: u8);
}
impl Write for String {
unsafe fn write(&mut self, u: u8) {
self.as_mut_vec().push(u);
}
}
impl Write for Vec<u8> {
unsafe fn write(&mut self, u: u8) {
self.push(u);
}
}
pub fn encode(n: u64) -> String {
let mut fits = Vec::with_capacity(13);
encode_into(n, &mut fits);
unsafe { String::from_utf8_unchecked(fits) }
}
pub fn encode_into<T: Write>(mut n: u64, w: &mut T) {
use crate::UPPERCASE_ENCODING;
const QUAD_SHIFT: usize = 60;
const QUAD_RESET: usize = 4;
const FIVE_SHIFT: usize = 59;
const FIVE_RESET: usize = 5;
const STOP_BIT: u64 = 1 << QUAD_SHIFT;
if n == 0 {
unsafe {
w.write(b'0');
}
return;
}
match (n >> QUAD_SHIFT) as usize {
0 => {
n <<= QUAD_RESET;
n |= 1;
n <<= n.leading_zeros() / 5 * 5;
}
i => {
n <<= QUAD_RESET;
n |= 1;
unsafe {
w.write(UPPERCASE_ENCODING[i]);
}
}
}
while n != STOP_BIT {
unsafe {
w.write(UPPERCASE_ENCODING[(n >> FIVE_SHIFT) as usize]);
}
n <<= FIVE_RESET;
}
}
#[cfg(test)]
mod tests {
use std::str;
use crate::{decode, encode, encode_into};
#[test]
fn zero_returns_zero() {
let input = 0;
let expected = "0";
let actual = encode(input);
assert_eq!(expected, &*actual);
}
#[test]
fn large_value_returns_correct_large_value() {
let input = 65535;
let expected = "1ZZZ";
let actual = encode(input);
assert_eq!(expected, &*actual);
}
#[test]
fn x5111_is_4zq() {
assert_eq!("4ZQ", &*encode(5111));
}
#[test]
fn x18446744073709551615_is_fzzzzzzzzzzzz() {
assert_eq!("FZZZZZZZZZZZZ", &*encode(18446744073709551615));
}
#[test]
fn large_odd_number() {
let x = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001;
let y = decode(encode(x)).unwrap();
assert_eq!(x, y);
}
#[test]
fn large_even_number() {
let x = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
let y = decode(encode(x)).unwrap();
assert_eq!(x, y);
}
#[test]
fn tiny_number() {
let x = 1;
let y = decode(encode(x)).unwrap();
assert_eq!(x, y);
}
#[ignore]
#[test]
fn round_trips() {
let mut s = Vec::new();
for n in 0..20_000_001 {
encode_into(n, &mut s);
assert_eq!(n, decode(str::from_utf8(&s).unwrap()).unwrap());
s.clear();
}
for n in (u64::max_value() - 20_000_000)..u64::max_value() {
encode_into(n, &mut s);
assert_eq!(n, decode(str::from_utf8(&s).unwrap()).unwrap());
s.clear();
}
}
}