1use alloc::vec::Vec;
7use base64::Engine;
8use core::{error, fmt, str::FromStr};
9
10#[must_use]
32#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
33pub struct Base64Vec(pub Vec<u8>);
34
35impl Base64Vec {
36 #[inline]
38 pub fn new(bytes: Vec<u8>) -> Self {
39 Self(bytes)
40 }
41
42 #[inline]
44 #[must_use]
45 pub fn into_inner(self) -> Vec<u8> {
46 self.0
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum ParseBase64Error {
53 InvalidByte {
55 offset: usize,
57 byte: u8,
59 },
60 InvalidLength {
62 length: usize,
64 },
65 InvalidLastSymbol {
68 offset: usize,
70 byte: u8,
72 },
73 InvalidPadding,
75}
76
77impl fmt::Display for ParseBase64Error {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 ParseBase64Error::InvalidByte { offset, byte } => {
81 write!(f, "invalid base64 symbol {byte}, offset {offset}",)
82 }
83 ParseBase64Error::InvalidLength { length } => {
84 write!(f, "invalid base64 input length: {length}",)
85 }
86 ParseBase64Error::InvalidLastSymbol { offset, byte } => {
87 write!(
88 f,
89 "invalid base64 last symbol {byte}, \
90 offset {offset}",
91 )
92 }
93 ParseBase64Error::InvalidPadding => {
94 write!(f, "invalid base64 padding")
95 }
96 }
97 }
98}
99
100impl error::Error for ParseBase64Error {}
101
102fn from_decode_error(e: base64::DecodeError) -> ParseBase64Error {
103 match e {
104 base64::DecodeError::InvalidByte(offset, byte) => {
105 ParseBase64Error::InvalidByte { offset, byte }
106 }
107 base64::DecodeError::InvalidLength(length) => {
108 ParseBase64Error::InvalidLength { length }
109 }
110 base64::DecodeError::InvalidLastSymbol {
111 offset,
112 symbol,
113 symbol_value: _,
114 } => ParseBase64Error::InvalidLastSymbol { offset, byte: symbol },
115 base64::DecodeError::InvalidPadding => ParseBase64Error::InvalidPadding,
116 }
117}
118
119impl FromStr for Base64Vec {
120 type Err = ParseBase64Error;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
123 base64::engine::general_purpose::STANDARD
124 .decode(s)
125 .map(Self)
126 .map_err(from_decode_error)
127 }
128}
129
130impl fmt::Debug for Base64Vec {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 f.debug_tuple("Base64Vec")
133 .field(&base64::engine::general_purpose::STANDARD.encode(&self.0))
134 .finish()
135 }
136}
137
138impl fmt::Display for Base64Vec {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 base64::engine::general_purpose::STANDARD.encode(&self.0).fmt(f)
141 }
142}
143
144impl core::ops::Deref for Base64Vec {
145 type Target = Vec<u8>;
146
147 #[inline]
148 fn deref(&self) -> &Self::Target {
149 &self.0
150 }
151}
152
153impl core::ops::DerefMut for Base64Vec {
154 #[inline]
155 fn deref_mut(&mut self) -> &mut Self::Target {
156 &mut self.0
157 }
158}
159
160impl AsRef<[u8]> for Base64Vec {
161 #[inline]
162 fn as_ref(&self) -> &[u8] {
163 &self.0
164 }
165}
166
167impl AsMut<[u8]> for Base64Vec {
168 #[inline]
169 fn as_mut(&mut self) -> &mut [u8] {
170 &mut self.0
171 }
172}
173
174impl From<Vec<u8>> for Base64Vec {
175 #[inline]
176 fn from(bytes: Vec<u8>) -> Self {
177 Self(bytes)
178 }
179}
180
181impl From<Base64Vec> for Vec<u8> {
182 #[inline]
183 fn from(base64_vec: Base64Vec) -> Self {
184 base64_vec.0
185 }
186}
187
188#[cfg(feature = "serde")]
189mod serde_impls {
190 use super::Base64Vec;
191 use alloc::vec::Vec;
192 use base64::Engine;
193 use core::fmt;
194 use serde_core::{
195 Deserializer, Serializer,
196 de::{SeqAccess, Visitor},
197 };
198
199 fn serialize_bytes<S>(
202 bytes: &[u8],
203 serializer: S,
204 ) -> Result<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 if serializer.is_human_readable() {
209 let encoded =
210 base64::engine::general_purpose::STANDARD.encode(bytes);
211 serializer.serialize_str(&encoded)
212 } else {
213 serializer.serialize_bytes(bytes)
214 }
215 }
216
217 fn deserialize_bytes<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
220 where
221 D: Deserializer<'de>,
222 {
223 use serde_core::de::Error;
224
225 if deserializer.is_human_readable() {
226 struct Base64Visitor;
227
228 impl<'de2> Visitor<'de2> for Base64Visitor {
229 type Value = Vec<u8>;
230
231 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
232 write!(f, "a base64-encoded string")
233 }
234
235 fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
236 where
237 E: Error,
238 {
239 base64::engine::general_purpose::STANDARD
240 .decode(data)
241 .map_err(Error::custom)
242 }
243 }
244
245 deserializer.deserialize_str(Base64Visitor)
246 } else {
247 struct BytesVisitor;
248
249 impl<'de2> Visitor<'de2> for BytesVisitor {
250 type Value = Vec<u8>;
251
252 fn expecting(
253 &self,
254 formatter: &mut fmt::Formatter,
255 ) -> fmt::Result {
256 write!(formatter, "a byte array")
257 }
258
259 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
260 where
261 E: Error,
262 {
263 Ok(v.to_vec())
264 }
265
266 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
267 where
268 E: Error,
269 {
270 Ok(v)
271 }
272
273 fn visit_seq<A>(
274 self,
275 mut seq: A,
276 ) -> Result<Self::Value, A::Error>
277 where
278 A: SeqAccess<'de2>,
279 {
280 let hint = seq.size_hint().unwrap_or(0);
281 let mut out = Vec::with_capacity(hint.min(4096));
282 while let Some(byte) = seq.next_element()? {
283 out.push(byte);
284 }
285 Ok(out)
286 }
287 }
288
289 deserializer.deserialize_bytes(BytesVisitor)
290 }
291 }
292
293 impl Base64Vec {
294 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
316 pub fn serialize<S>(
317 bytes: &[u8],
318 serializer: S,
319 ) -> Result<S::Ok, S::Error>
320 where
321 S: Serializer,
322 {
323 serialize_bytes(bytes, serializer)
324 }
325
326 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
347 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
348 where
349 D: Deserializer<'de>,
350 {
351 deserialize_bytes(deserializer)
352 }
353 }
354
355 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
356 impl serde_core::Serialize for Base64Vec {
357 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
358 where
359 S: Serializer,
360 {
361 serialize_bytes(&self.0, serializer)
362 }
363 }
364
365 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
366 impl<'de> serde_core::Deserialize<'de> for Base64Vec {
367 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
368 where
369 D: Deserializer<'de>,
370 {
371 deserialize_bytes(deserializer).map(Self)
372 }
373 }
374}
375
376#[cfg(feature = "schemars08")]
377mod schemars_impls {
378 use super::Base64Vec;
379 use crate::schemars_util::x_rust_type_extension;
380 use alloc::string::String;
381 use schemars08::{
382 JsonSchema,
383 r#gen::SchemaGenerator,
384 schema::{InstanceType, Schema, SchemaObject},
385 };
386
387 impl JsonSchema for Base64Vec {
388 fn schema_name() -> String {
389 "Base64Vec".into()
390 }
391
392 fn is_referenceable() -> bool {
393 false
394 }
395
396 fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
397 let mut extensions = x_rust_type_extension("Base64Vec");
398 extensions.insert("contentEncoding".into(), "base64".into());
399 Schema::Object(SchemaObject {
400 instance_type: Some(InstanceType::String.into()),
401 format: Some("byte".into()),
402 extensions,
403 ..Default::default()
404 })
405 }
406 }
407}