use ::base64::Engine;
use ::base64::engine::general_purpose::{
STANDARD,
STANDARD_NO_PAD,
URL_SAFE,
URL_SAFE_NO_PAD,
};
use crate::{
MiscCodecError,
MiscCodecResult,
ValueDecoder,
ValueEncoder,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Base64Codec {
url_safe: bool,
padding: bool,
}
impl Base64Codec {
#[inline]
pub fn standard() -> Self {
Self {
url_safe: false,
padding: true,
}
}
#[inline]
pub fn standard_no_pad() -> Self {
Self {
url_safe: false,
padding: false,
}
}
#[inline]
pub fn url_safe() -> Self {
Self {
url_safe: true,
padding: true,
}
}
#[inline]
pub fn url_safe_no_pad() -> Self {
Self {
url_safe: true,
padding: false,
}
}
#[inline]
pub fn encode(&self, bytes: &[u8]) -> String {
self.engine().encode(bytes)
}
#[inline]
pub fn decode(&self, text: &str) -> MiscCodecResult<Vec<u8>> {
self.engine().decode(text).map_err(|source| {
MiscCodecError::InvalidInput {
codec: "base64",
reason: source.to_string(),
}
})
}
#[inline(always)]
fn engine(&self) -> &'static ::base64::engine::GeneralPurpose {
match (self.url_safe, self.padding) {
(false, true) => &STANDARD,
(false, false) => &STANDARD_NO_PAD,
(true, true) => &URL_SAFE,
(true, false) => &URL_SAFE_NO_PAD,
}
}
}
impl Default for Base64Codec {
#[inline]
fn default() -> Self {
Self::standard()
}
}
impl ValueEncoder<[u8]> for Base64Codec {
type Error = MiscCodecError;
type Output = String;
#[inline]
fn encode(&self, input: &[u8]) -> Result<Self::Output, Self::Error> {
Ok(Base64Codec::encode(self, input))
}
}
impl ValueDecoder<str> for Base64Codec {
type Error = MiscCodecError;
type Output = Vec<u8>;
#[inline]
fn decode(&self, input: &str) -> Result<Self::Output, Self::Error> {
Base64Codec::decode(self, input)
}
}