const VAL_TO_DIGIT: [u8; 58] = *b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
#[must_use]
#[inline]
pub fn encode(input: &[u8]) -> String {
if input.is_empty() {
return String::new();
}
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss
)]
let cap = ((input.len() as f64 * 1.3652).ceil() as usize).max(1);
let zeros = input.iter().take_while(|&&b| b == 0).count();
let non_zero = &input[zeros..];
if non_zero.is_empty() {
return "1".repeat(zeros);
}
let mut num = non_zero.to_vec();
let mut output = Vec::with_capacity(cap - zeros);
while !num.is_empty() {
let mut remainder = 0u32;
let mut all_zero = true;
#[allow(clippy::explicit_iter_loop, clippy::cast_possible_truncation)]
for byte in &mut num {
let temp = remainder * 256 + u32::from(*byte);
*byte = (temp / 58) as u8;
remainder = temp % 58;
if *byte != 0 {
all_zero = false;
}
}
output.push(VAL_TO_DIGIT[remainder as usize]);
if all_zero {
break;
}
while !num.is_empty() && num[0] == 0 {
num.remove(0);
}
}
output.reverse();
let mut result = String::with_capacity(zeros + output.len());
for _ in 0..zeros {
result.push('1');
}
result.extend(output.into_iter().map(|b| b as char));
result
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn encode_known_no_zeros() {
assert_eq!(encode(b""), "");
assert_eq!(encode(b"hello"), "Cn8eVZg");
let txid = hex!("a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef0");
assert_eq!(
encode(&txid),
"BtCjvJYNhqehX2sbzvBNrbkCYp2qfc6AepXfK1JGnELw"
);
}
#[test]
fn encode_with_zeros() {
assert_eq!(encode(&hex!("00")), "1");
assert_eq!(
encode(&hex!(
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
)),
"111114VYJtj3yEDffZem7N3PkK563wkLZZ8RjKzcfY"
);
}
#[test]
fn encode_large() {
let large = vec![0u8; 50];
let encoded = encode(&large);
assert_eq!(encoded, "1".repeat(50));
}
#[test]
fn correctness() {
let long = vec![42u8; 64];
let enc = encode(&long);
let dec = crate::decode(&enc).unwrap();
assert_eq!(dec, long);
}
#[test]
fn wide_limbs_correctness() {
let large = vec![42u8; 1024];
let enc = encode(&large);
let dec = crate::decode(&enc).unwrap();
assert_eq!(dec, large);
}
}