const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; pub fn encode(input: &[u8]) -> String { let mut out = String::with_capacity(input.len().div_ceil(3) * 4); for chunk in input.chunks(3) { let b0 = chunk[0] as u32; let b1 = chunk.get(1).copied().unwrap_or(0) as u32; let b2 = chunk.get(2).copied().unwrap_or(0) as u32; let triple = (b0 << 16) | (b1 << 8) | b2; out.push(ALPHABET[(triple >> 18) as usize & 0x3F] as char); out.push(ALPHABET[(triple >> 12) as usize & 0x3F] as char); out.push(if chunk.len() > 1 { ALPHABET[(triple >> 6) as usize & 0x3F] as char } else { '=' }); out.push(if chunk.len() > 2 { ALPHABET[triple as usize & 0x3F] as char } else { '=' }); } out } pub fn decode(input: &str) -> Option> { let bytes: Vec = input.bytes().filter(|byte| *byte != b'=').collect(); let mut out = Vec::with_capacity(bytes.len() * 3 / 4); let mut accumulator: u32 = 0; let mut bits: u32 = 0; for byte in bytes { let value = ALPHABET.iter().position(|candidate| *candidate == byte)? as u32; accumulator = (accumulator << 6) | value; bits += 6; if bits >= 8 { bits -= 8; out.push((accumulator >> bits) as u8); } } Some(out) } pub mod serde_bytes { use serde::{Deserialize, Deserializer, Serializer}; pub fn serialize(value: &[u8], serializer: S) -> Result { serializer.serialize_str(&super::encode(value)) } pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { let text = String::deserialize(deserializer)?; super::decode(&text).ok_or_else(|| serde::de::Error::custom("invalid base64 payload")) } }