1use crate::{Base64Slice, base64_slice::QuotedBase64};
7use alloc::{borrow::ToOwned, vec::Vec};
8use base64::Engine;
9use core::{borrow::Borrow, error, fmt, str::FromStr};
10
11#[must_use]
33#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
34pub struct Base64Vec(pub Vec<u8>);
35
36impl Base64Vec {
37 #[inline]
39 pub fn new(bytes: Vec<u8>) -> Self {
40 Self(bytes)
41 }
42
43 #[inline]
45 #[must_use]
46 pub fn into_inner(self) -> Vec<u8> {
47 self.0
48 }
49
50 #[inline]
51 fn as_base64_slice(&self) -> &Base64Slice {
52 Base64Slice::new(&self.0)
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
58pub enum ParseBase64Error {
59 InvalidByte {
61 offset: usize,
63 byte: u8,
65 },
66 InvalidLength {
68 length: usize,
70 },
71 InvalidLastSymbol {
74 offset: usize,
76 byte: u8,
78 },
79 InvalidPadding,
81}
82
83impl fmt::Display for ParseBase64Error {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 ParseBase64Error::InvalidByte { offset, byte } => {
87 write!(f, "invalid base64 symbol {byte}, offset {offset}",)
88 }
89 ParseBase64Error::InvalidLength { length } => {
90 write!(f, "invalid base64 input length: {length}",)
91 }
92 ParseBase64Error::InvalidLastSymbol { offset, byte } => {
93 write!(
94 f,
95 "invalid base64 last symbol {byte}, \
96 offset {offset}",
97 )
98 }
99 ParseBase64Error::InvalidPadding => {
100 write!(f, "invalid base64 padding")
101 }
102 }
103 }
104}
105
106impl error::Error for ParseBase64Error {}
107
108fn from_decode_error(e: base64::DecodeError) -> ParseBase64Error {
109 match e {
110 base64::DecodeError::InvalidByte(offset, byte) => {
111 ParseBase64Error::InvalidByte { offset, byte }
112 }
113 base64::DecodeError::InvalidLength(length) => {
114 ParseBase64Error::InvalidLength { length }
115 }
116 base64::DecodeError::InvalidLastSymbol {
117 offset,
118 symbol,
119 symbol_value: _,
120 } => ParseBase64Error::InvalidLastSymbol { offset, byte: symbol },
121 base64::DecodeError::InvalidPadding => ParseBase64Error::InvalidPadding,
122 }
123}
124
125impl FromStr for Base64Vec {
126 type Err = ParseBase64Error;
127
128 fn from_str(s: &str) -> Result<Self, Self::Err> {
129 base64::engine::general_purpose::STANDARD
130 .decode(s)
131 .map(Self)
132 .map_err(from_decode_error)
133 }
134}
135
136impl fmt::Debug for Base64Vec {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_tuple("Base64Vec").field(&QuotedBase64(&self.0)).finish()
139 }
140}
141
142impl fmt::Display for Base64Vec {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 fmt::Display::fmt(self.as_base64_slice(), f)
145 }
146}
147
148impl core::ops::Deref for Base64Vec {
149 type Target = Base64Slice;
150
151 #[inline]
152 fn deref(&self) -> &Self::Target {
153 self.as_base64_slice()
154 }
155}
156
157impl Borrow<Base64Slice> for Base64Vec {
158 #[inline]
159 fn borrow(&self) -> &Base64Slice {
160 self.as_base64_slice()
161 }
162}
163
164impl ToOwned for Base64Slice {
165 type Owned = Base64Vec;
166
167 #[inline]
168 fn to_owned(&self) -> Self::Owned {
169 Base64Vec(self.as_bytes().to_vec())
170 }
171}
172
173impl AsRef<Base64Slice> for Base64Vec {
174 #[inline]
175 fn as_ref(&self) -> &Base64Slice {
176 self.as_base64_slice()
177 }
178}
179
180impl AsRef<[u8]> for Base64Vec {
181 #[inline]
182 fn as_ref(&self) -> &[u8] {
183 &self.0
184 }
185}
186
187impl AsMut<[u8]> for Base64Vec {
188 #[inline]
189 fn as_mut(&mut self) -> &mut [u8] {
190 &mut self.0
191 }
192}
193
194impl From<Vec<u8>> for Base64Vec {
195 #[inline]
196 fn from(bytes: Vec<u8>) -> Self {
197 Self(bytes)
198 }
199}
200
201impl From<Base64Vec> for Vec<u8> {
202 #[inline]
203 fn from(base64_vec: Base64Vec) -> Self {
204 base64_vec.0
205 }
206}
207
208impl PartialEq<Base64Slice> for Base64Vec {
209 #[inline]
210 fn eq(&self, other: &Base64Slice) -> bool {
211 self.as_base64_slice() == other
212 }
213}
214
215impl PartialEq<&Base64Slice> for Base64Vec {
216 #[inline]
217 fn eq(&self, other: &&Base64Slice) -> bool {
218 self.as_base64_slice() == *other
219 }
220}
221
222impl PartialEq<Base64Vec> for Base64Slice {
223 #[inline]
224 fn eq(&self, other: &Base64Vec) -> bool {
225 self == other.as_base64_slice()
226 }
227}
228
229impl PartialEq<Base64Vec> for &Base64Slice {
230 #[inline]
231 fn eq(&self, other: &Base64Vec) -> bool {
232 *self == other.as_base64_slice()
233 }
234}
235
236#[cfg(feature = "serde")]
237mod serde_impls {
238 use super::Base64Vec;
239 use crate::Base64Slice;
240 use alloc::vec::Vec;
241 use base64::Engine;
242 use core::fmt;
243 use serde_core::{Deserializer, Serialize, Serializer, de::Visitor};
244
245 fn deserialize_bytes<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
248 where
249 D: Deserializer<'de>,
250 {
251 use serde_core::de::Error;
252
253 if deserializer.is_human_readable() {
254 struct Base64Visitor;
255
256 impl<'de2> Visitor<'de2> for Base64Visitor {
257 type Value = Vec<u8>;
258
259 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 write!(f, "a base64-encoded string")
261 }
262
263 fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
264 where
265 E: Error,
266 {
267 base64::engine::general_purpose::STANDARD
268 .decode(data)
269 .map_err(Error::custom)
270 }
271 }
272
273 deserializer.deserialize_str(Base64Visitor)
274 } else {
275 crate::serde_util::deserialize_byte_buf(deserializer)
276 }
277 }
278
279 impl Base64Vec {
280 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
302 pub fn serialize<S>(
303 bytes: &[u8],
304 serializer: S,
305 ) -> Result<S::Ok, S::Error>
306 where
307 S: Serializer,
308 {
309 Base64Slice::new(bytes).serialize(serializer)
310 }
311
312 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
333 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
334 where
335 D: Deserializer<'de>,
336 {
337 deserialize_bytes(deserializer)
338 }
339 }
340
341 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
342 impl serde_core::Serialize for Base64Vec {
343 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
344 where
345 S: Serializer,
346 {
347 self.as_base64_slice().serialize(serializer)
348 }
349 }
350
351 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
352 impl<'de> serde_core::Deserialize<'de> for Base64Vec {
353 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
354 where
355 D: Deserializer<'de>,
356 {
357 deserialize_bytes(deserializer).map(Self)
358 }
359 }
360}
361
362#[cfg(feature = "schemars08")]
363mod schemars_impls {
364 use super::Base64Vec;
365 use crate::{Base64Slice, schemars_util::x_rust_type_extension};
366 use alloc::string::String;
367 use schemars08::{
368 JsonSchema,
369 r#gen::SchemaGenerator,
370 schema::{InstanceType, Schema, SchemaObject},
371 };
372
373 impl JsonSchema for Base64Vec {
374 fn schema_name() -> String {
375 "Base64Vec".into()
376 }
377
378 fn is_referenceable() -> bool {
379 false
380 }
381
382 fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
383 let mut extensions = x_rust_type_extension("Base64Vec");
384 extensions.insert("contentEncoding".into(), "base64".into());
385 Schema::Object(SchemaObject {
386 instance_type: Some(InstanceType::String.into()),
387 format: Some("byte".into()),
388 extensions,
389 ..Default::default()
390 })
391 }
392 }
393
394 impl JsonSchema for Base64Slice {
398 fn schema_name() -> String {
399 Base64Vec::schema_name()
400 }
401
402 fn is_referenceable() -> bool {
403 Base64Vec::is_referenceable()
404 }
405
406 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
407 Base64Vec::json_schema(generator)
408 }
409 }
410}