const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
pub(crate) fn strict_encode(input: &[u8]) -> String {
let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
let mut chunks = input.chunks_exact(3);
for chunk in chunks.by_ref() {
let &[a, b, c] = chunk else { continue };
let n = (u32::from(a) << 16) | (u32::from(b) << 8) | u32::from(c);
out.push(sextet(n >> 18));
out.push(sextet(n >> 12));
out.push(sextet(n >> 6));
out.push(sextet(n));
}
match chunks.remainder() {
[a] => {
let n = u32::from(*a) << 16;
out.push(sextet(n >> 18));
out.push(sextet(n >> 12));
out.push('=');
out.push('=');
}
[a, b] => {
let n = (u32::from(*a) << 16) | (u32::from(*b) << 8);
out.push(sextet(n >> 18));
out.push(sextet(n >> 12));
out.push(sextet(n >> 6));
out.push('=');
}
_ => {}
}
out
}
fn sextet(value: u32) -> char {
#[allow(clippy::indexing_slicing)]
let c = ALPHABET[(value & 0x3f) as usize];
c as char
}
#[cfg(test)]
mod tests {
use super::strict_encode;
#[test]
fn rfc4648_test_vectors() {
assert_eq!(strict_encode(b""), "");
assert_eq!(strict_encode(b"f"), "Zg==");
assert_eq!(strict_encode(b"fo"), "Zm8=");
assert_eq!(strict_encode(b"foo"), "Zm9v");
assert_eq!(strict_encode(b"foob"), "Zm9vYg==");
assert_eq!(strict_encode(b"fooba"), "Zm9vYmE=");
assert_eq!(strict_encode(b"foobar"), "Zm9vYmFy");
}
#[test]
fn encodes_full_byte_range() {
let bytes: Vec<u8> = (0u8..=255).collect();
let encoded = strict_encode(&bytes);
assert!(!encoded.contains('\n'));
assert!(encoded.starts_with("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8g"));
assert!(encoded.contains('+'));
assert!(encoded.contains('/'));
assert_eq!(encoded.len(), 344);
}
}