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(offset, byte) => {
111 ParseBase64Error::InvalidLastSymbol { offset, byte }
112 }
113 base64::DecodeError::InvalidPadding => ParseBase64Error::InvalidPadding,
114 }
115}
116
117impl FromStr for Base64Vec {
118 type Err = ParseBase64Error;
119
120 fn from_str(s: &str) -> Result<Self, Self::Err> {
121 base64::engine::general_purpose::STANDARD
122 .decode(s)
123 .map(Self)
124 .map_err(from_decode_error)
125 }
126}
127
128impl fmt::Debug for Base64Vec {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_tuple("Base64Vec")
131 .field(&base64::engine::general_purpose::STANDARD.encode(&self.0))
132 .finish()
133 }
134}
135
136impl fmt::Display for Base64Vec {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 base64::engine::general_purpose::STANDARD.encode(&self.0).fmt(f)
139 }
140}
141
142impl core::ops::Deref for Base64Vec {
143 type Target = Vec<u8>;
144
145 #[inline]
146 fn deref(&self) -> &Self::Target {
147 &self.0
148 }
149}
150
151impl core::ops::DerefMut for Base64Vec {
152 #[inline]
153 fn deref_mut(&mut self) -> &mut Self::Target {
154 &mut self.0
155 }
156}
157
158impl AsRef<[u8]> for Base64Vec {
159 #[inline]
160 fn as_ref(&self) -> &[u8] {
161 &self.0
162 }
163}
164
165impl AsMut<[u8]> for Base64Vec {
166 #[inline]
167 fn as_mut(&mut self) -> &mut [u8] {
168 &mut self.0
169 }
170}
171
172impl From<Vec<u8>> for Base64Vec {
173 #[inline]
174 fn from(bytes: Vec<u8>) -> Self {
175 Self(bytes)
176 }
177}
178
179impl From<Base64Vec> for Vec<u8> {
180 #[inline]
181 fn from(base64_vec: Base64Vec) -> Self {
182 base64_vec.0
183 }
184}
185
186#[cfg(feature = "serde")]
187mod serde_impls {
188 use super::Base64Vec;
189 use alloc::vec::Vec;
190 use base64::Engine;
191 use core::fmt;
192 use serde_core::{
193 Deserializer, Serializer,
194 de::{SeqAccess, Visitor},
195 };
196
197 fn serialize_bytes<S>(
200 bytes: &[u8],
201 serializer: S,
202 ) -> Result<S::Ok, S::Error>
203 where
204 S: Serializer,
205 {
206 if serializer.is_human_readable() {
207 let encoded =
208 base64::engine::general_purpose::STANDARD.encode(bytes);
209 serializer.serialize_str(&encoded)
210 } else {
211 serializer.serialize_bytes(bytes)
212 }
213 }
214
215 fn deserialize_bytes<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
218 where
219 D: Deserializer<'de>,
220 {
221 use serde_core::de::Error;
222
223 if deserializer.is_human_readable() {
224 struct Base64Visitor;
225
226 impl<'de2> Visitor<'de2> for Base64Visitor {
227 type Value = Vec<u8>;
228
229 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 write!(f, "a base64-encoded string")
231 }
232
233 fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
234 where
235 E: Error,
236 {
237 base64::engine::general_purpose::STANDARD
238 .decode(data)
239 .map_err(Error::custom)
240 }
241 }
242
243 deserializer.deserialize_str(Base64Visitor)
244 } else {
245 struct BytesVisitor;
246
247 impl<'de2> Visitor<'de2> for BytesVisitor {
248 type Value = Vec<u8>;
249
250 fn expecting(
251 &self,
252 formatter: &mut fmt::Formatter,
253 ) -> fmt::Result {
254 write!(formatter, "a byte array")
255 }
256
257 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
258 where
259 E: Error,
260 {
261 Ok(v.to_vec())
262 }
263
264 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
265 where
266 E: Error,
267 {
268 Ok(v)
269 }
270
271 fn visit_seq<A>(
272 self,
273 mut seq: A,
274 ) -> Result<Self::Value, A::Error>
275 where
276 A: SeqAccess<'de2>,
277 {
278 let hint = seq.size_hint().unwrap_or(0);
279 let mut out = Vec::with_capacity(hint.min(4096));
280 while let Some(byte) = seq.next_element()? {
281 out.push(byte);
282 }
283 Ok(out)
284 }
285 }
286
287 deserializer.deserialize_bytes(BytesVisitor)
288 }
289 }
290
291 impl Base64Vec {
292 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
314 pub fn serialize<S>(
315 bytes: &[u8],
316 serializer: S,
317 ) -> Result<S::Ok, S::Error>
318 where
319 S: Serializer,
320 {
321 serialize_bytes(bytes, serializer)
322 }
323
324 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
345 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
346 where
347 D: Deserializer<'de>,
348 {
349 deserialize_bytes(deserializer)
350 }
351 }
352
353 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
354 impl serde_core::Serialize for Base64Vec {
355 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
356 where
357 S: Serializer,
358 {
359 serialize_bytes(&self.0, serializer)
360 }
361 }
362
363 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
364 impl<'de> serde_core::Deserialize<'de> for Base64Vec {
365 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
366 where
367 D: Deserializer<'de>,
368 {
369 deserialize_bytes(deserializer).map(Self)
370 }
371 }
372}
373
374#[cfg(feature = "schemars08")]
375mod schemars_impls {
376 use super::Base64Vec;
377 use crate::schemars_util::x_rust_type_extension;
378 use alloc::string::String;
379 use schemars08::{
380 JsonSchema,
381 r#gen::SchemaGenerator,
382 schema::{InstanceType, Schema, SchemaObject},
383 };
384
385 impl JsonSchema for Base64Vec {
386 fn schema_name() -> String {
387 "Base64Vec".into()
388 }
389
390 fn is_referenceable() -> bool {
391 false
392 }
393
394 fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
395 let mut extensions = x_rust_type_extension("Base64Vec");
396 extensions.insert("contentEncoding".into(), "base64".into());
397 Schema::Object(SchemaObject {
398 instance_type: Some(InstanceType::String.into()),
399 format: Some("byte".into()),
400 extensions,
401 ..Default::default()
402 })
403 }
404 }
405}