use std::{fmt, marker::PhantomData};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Base64<C = Standard, B = Vec<u8>> {
bytes: B,
_phantom_conf: PhantomData<fn(C) -> C>,
}
pub trait Base64Config {
#[doc(hidden)]
const CONF: Conf;
}
#[doc(hidden)]
pub struct Conf(base64::Config);
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Standard;
impl Base64Config for Standard {
const CONF: Conf = Conf(base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true));
}
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct UrlSafe;
impl Base64Config for UrlSafe {
const CONF: Conf = Conf(base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true));
}
impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> {
pub fn new(bytes: B) -> Self {
Self { bytes, _phantom_conf: PhantomData }
}
pub fn as_bytes(&self) -> &[u8] {
self.bytes.as_ref()
}
pub fn encode(&self) -> String {
base64::encode_config(&self.bytes, C::CONF.0)
}
}
impl<C, B> Base64<C, B> {
pub fn into_inner(self) -> B {
self.bytes
}
}
impl<C: Base64Config> Base64<C> {
pub fn empty() -> Self {
Self::new(Vec::new())
}
pub fn parse(encoded: impl AsRef<[u8]>) -> Result<Self, Base64DecodeError> {
base64::decode_config(encoded, C::CONF.0).map(Self::new).map_err(Base64DecodeError)
}
}
impl<C: Base64Config, B: AsRef<[u8]>> fmt::Debug for Base64<C, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.encode().fmt(f)
}
}
impl<C: Base64Config, B: AsRef<[u8]>> fmt::Display for Base64<C, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.encode().fmt(f)
}
}
impl<'de, C: Base64Config> Deserialize<'de> for Base64<C> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let encoded = crate::deserialize_cow_str(deserializer)?;
Self::parse(&*encoded).map_err(de::Error::custom)
}
}
impl<C: Base64Config, B: AsRef<[u8]>> Serialize for Base64<C, B> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.encode())
}
}
#[derive(Clone)]
pub struct Base64DecodeError(base64::DecodeError);
impl fmt::Debug for Base64DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Display for Base64DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for Base64DecodeError {}