use std::{borrow::Cow, sync::LazyLock};
use base64_simd::{Base64 as Raw, Error, STANDARD};
use regex::Regex;
pub struct Base64(Raw);
impl Base64 {
pub const fn new() -> Self {
Self(STANDARD)
}
pub fn encode_to_string<D: AsRef<[u8]>>(&self, data: D) -> String {
self.0.encode_to_string(data)
}
pub fn decode_to_vec<D: AsRef<[u8]>>(&self, data: D) -> Result<Vec<u8>, Error> {
self.0.decode_to_vec(data)
}
}
impl Default for Base64 {
fn default() -> Self {
Self::new()
}
}
static BASE64: Base64 = Base64::new();
pub fn encode_to_string<D: AsRef<[u8]>>(data: D) -> String {
BASE64.0.encode_to_string(data)
}
pub fn decode_to_vec<D: AsRef<[u8]>>(data: D) -> Result<Vec<u8>, Error> {
BASE64.0.decode_to_vec(data)
}
static INVALID_BASE64_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"[^+/0-9A-Za-z-_]").expect("Invalid RegExp"));
pub fn clean_base64(value: &str) -> Option<Cow<'_, str>> {
let value = value.split('=').next()?;
let value = value.trim();
let value = INVALID_BASE64_RE.replace_all(value, "");
if value.len() < 2 {
return Some(Cow::from(""));
}
let value = value.into_owned();
let len = value.len();
let remainder = len % 4;
if remainder == 0 {
return Some(Cow::from(value));
}
let pad_len = 4 - remainder;
if pad_len == 1 {
return Some(Cow::from(value + "="));
}
if pad_len == 2 {
return Some(Cow::from(value + "=="));
}
Some(Cow::from(value[..len - remainder].to_owned()))
}