1use std::{fmt, marker::PhantomData};
4
5use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
6
7#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Base64<C = Standard, B = Vec<u8>> {
13 bytes: B,
14 _phantom_conf: PhantomData<fn(C) -> C>,
16}
17
18pub trait Base64Config {
20 #[doc(hidden)]
24 const CONF: Conf;
25}
26
27#[doc(hidden)]
28pub struct Conf(base64::Config);
29
30#[non_exhaustive]
34#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
36pub struct Standard;
37
38impl Base64Config for Standard {
39 const CONF: Conf = Conf(base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true));
41}
42
43#[non_exhaustive]
47#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
49pub struct UrlSafe;
50
51impl Base64Config for UrlSafe {
52 const CONF: Conf = Conf(base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true));
53}
54
55impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> {
56 pub fn new(bytes: B) -> Self {
58 Self { bytes, _phantom_conf: PhantomData }
59 }
60
61 pub fn as_bytes(&self) -> &[u8] {
63 self.bytes.as_ref()
64 }
65
66 pub fn encode(&self) -> String {
68 base64::encode_config(&self.bytes, C::CONF.0)
69 }
70}
71
72impl<C, B> Base64<C, B> {
73 pub fn into_inner(self) -> B {
75 self.bytes
76 }
77}
78
79impl<C: Base64Config> Base64<C> {
80 pub fn empty() -> Self {
82 Self::new(Vec::new())
83 }
84
85 pub fn parse(encoded: impl AsRef<[u8]>) -> Result<Self, Base64DecodeError> {
87 base64::decode_config(encoded, C::CONF.0).map(Self::new).map_err(Base64DecodeError)
88 }
89}
90
91impl<C: Base64Config, B: AsRef<[u8]>> fmt::Debug for Base64<C, B> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 self.encode().fmt(f)
94 }
95}
96
97impl<C: Base64Config, B: AsRef<[u8]>> fmt::Display for Base64<C, B> {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 self.encode().fmt(f)
100 }
101}
102
103impl<'de, C: Base64Config> Deserialize<'de> for Base64<C> {
104 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
105 where
106 D: Deserializer<'de>,
107 {
108 let encoded = crate::deserialize_cow_str(deserializer)?;
109 Self::parse(&*encoded).map_err(de::Error::custom)
110 }
111}
112
113impl<C: Base64Config, B: AsRef<[u8]>> Serialize for Base64<C, B> {
114 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115 where
116 S: Serializer,
117 {
118 serializer.serialize_str(&self.encode())
119 }
120}
121
122#[derive(Clone)]
124pub struct Base64DecodeError(base64::DecodeError);
125
126impl fmt::Debug for Base64DecodeError {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 self.0.fmt(f)
129 }
130}
131
132impl fmt::Display for Base64DecodeError {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 self.0.fmt(f)
135 }
136}
137
138impl std::error::Error for Base64DecodeError {}