#![allow(dead_code)] use crate::bytes::Bytes; use std::str; pub struct BytesBase64(pub Vec); impl std::fmt::Display for BytesBase64 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let BytesBase64(digits) = self; let mut r: Vec = digits .iter() .map(|d| match d { 0..=25 => *d + b'A', 26..=51 => *d - 26 + b'a', 52..=61 => *d - 52 + b'0', 62 => b'+', 63 => b'/', _ => panic!("Unexpected base64 digit '{}'", d), }) .collect(); // Handle padding let pad = b'='; match r.len() % 4 { 0 => (), 2 => { r.push(pad); r.push(pad); } 3 => r.push(pad), _ => panic!("Unexpected lenght for padding '{}'", r.len()), } let s = str::from_utf8(r.as_slice()).unwrap().to_string(); write!(f, "{}", s) } } impl BytesBase64 { pub fn from_bytes(Bytes(bytes): Bytes) -> BytesBase64 { fn to_base64(c: &[u8]) -> Vec { let mut v = c.to_vec(); // pad with bytes for conversion while v.len() < 3 { v.push(0); } let mut result = vec![ (v[0] & 0b1111_1100) >> 2, (v[0] & 0b0000_0011) << 4 | (v[1] & 0b1111_0000) >> 4, (v[1] & 0b0000_1111) << 2 | (v[2] & 0b1100_0000) >> 6, (v[2] & 0b0011_1111), ]; // removed padded bytes for _ in c.len()..3 { result.pop(); } result } BytesBase64(bytes.chunks(3).flat_map(to_base64).collect()) } pub fn to_bytes(&self) -> Bytes { fn to_bytes(c: &[u8]) -> Vec { let mut v = c.to_vec(); // pad with bytes for conversion while v.len() < 4 { v.push(0); } let mut result: Vec = vec![ ((v[0] & 0b0011_1111) << 2) | ((v[1] & 0b0011_0000) >> 4), ((v[1] & 0b0000_1111) << 4) | ((v[2] & 0b0011_1100) >> 2), ((v[2] & 0b0000_0011) << 6) | (v[3] & 0b0011_1111), ]; // removed padded bytes for _ in c.len()..4 { result.pop(); } result } let BytesBase64(v) = self; Bytes(v.chunks(4).flat_map(to_bytes).collect()) } pub fn from_base64(s: &str) -> Result { let mut r: Vec = Vec::with_capacity(s.len()); for c in s.chars() { match c { 'A'..='Z' => r.push((c as u8) - b'A'), 'a'..='z' => r.push((c as u8) - b'a' + 26), '0'..='9' => r.push((c as u8) - b'0' + 52), '+' => r.push(62), '/' => r.push(63), '\n' | '=' | ' ' => (), _ => { return Err(format!("Unexpected character '{}'", c)); } } } Ok(BytesBase64(r)) } }