did_utils/jwk/
bytes.rs

1extern crate alloc;
2
3use zeroize::{Zeroize, Zeroizing};
4
5use core::{
6    fmt::{Debug, Formatter},
7    marker::PhantomData,
8    ops::{Deref, DerefMut},
9    str::FromStr,
10};
11
12use base64ct::{Base64UrlUnpadded, Encoding, Error as DecodeError};
13use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
14
15/// A serde wrapper for base64-encoded bytes.
16///
17/// # Type Parameters
18///
19/// - `T`: The type used to store the byte data (e.g., `Vec<u8>`, `Box<[u8]>`).
20/// - `E`: The base64 encoding type (e.g., `Base64UrlUnpadded`).
21#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
22pub struct Bytes<T = Box<[u8]>, E = Base64UrlUnpadded> {
23    buf: T,
24    cfg: PhantomData<E>,
25}
26
27impl<T: Zeroize, E> Zeroize for Bytes<T, E> {
28    fn zeroize(&mut self) {
29        self.buf.zeroize()
30    }
31}
32
33impl<T: Debug, E> Debug for Bytes<T, E> {
34    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
35        f.debug_tuple("Bytes").field(&self.buf).finish()
36    }
37}
38
39impl<T, E> Deref for Bytes<T, E> {
40    type Target = T;
41
42    fn deref(&self) -> &Self::Target {
43        &self.buf
44    }
45}
46
47impl<T, E> DerefMut for Bytes<T, E> {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        &mut self.buf
50    }
51}
52
53impl<T: AsRef<U>, U: ?Sized, E> AsRef<U> for Bytes<T, E> {
54    fn as_ref(&self) -> &U {
55        self.buf.as_ref()
56    }
57}
58
59impl<T: AsMut<U>, U: ?Sized, E> AsMut<U> for Bytes<T, E> {
60    fn as_mut(&mut self) -> &mut U {
61        self.buf.as_mut()
62    }
63}
64
65impl<T, E> From<T> for Bytes<T, E> {
66    fn from(buf: T) -> Self {
67        Self { buf, cfg: PhantomData }
68    }
69}
70
71impl<E> From<Vec<u8>> for Bytes<Box<[u8]>, E> {
72    fn from(buf: Vec<u8>) -> Self {
73        Self::from(buf.into_boxed_slice())
74    }
75}
76
77impl<E> From<Bytes<Vec<u8>, E>> for Bytes<Box<[u8]>, E> {
78    fn from(bytes: Bytes<Vec<u8>, E>) -> Self {
79        Self::from(bytes.buf.into_boxed_slice())
80    }
81}
82
83impl<E> From<Box<[u8]>> for Bytes<Vec<u8>, E> {
84    fn from(buf: Box<[u8]>) -> Self {
85        Self::from(buf.into_vec())
86    }
87}
88
89impl<E> From<Bytes<Box<[u8]>, E>> for Bytes<Vec<u8>, E> {
90    fn from(bytes: Bytes<Box<[u8]>, E>) -> Self {
91        Self::from(bytes.buf.into_vec())
92    }
93}
94
95impl<E: Encoding> FromStr for Bytes<Vec<u8>, E> {
96    type Err = DecodeError;
97
98    fn from_str(s: &str) -> Result<Self, Self::Err> {
99        Ok(Self {
100            buf: E::decode_vec(s)?,
101            cfg: PhantomData,
102        })
103    }
104}
105impl<E: Encoding> FromStr for Bytes<Box<[u8]>, E> {
106    type Err = DecodeError;
107
108    fn from_str(s: &str) -> Result<Self, Self::Err> {
109        Bytes::<Vec<u8>, E>::from_str(s).map(|x| x.buf.into_boxed_slice().into())
110    }
111}
112
113impl<T: AsRef<[u8]>, E: Encoding> Serialize for Bytes<T, E> {
114    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
115        let b64 = Zeroizing::from(E::encode_string(self.buf.as_ref()));
116        b64.serialize(serializer)
117    }
118}
119
120impl<'de, E: Encoding> Deserialize<'de> for Bytes<Vec<u8>, E> {
121    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
122        let enc = Zeroizing::from(String::deserialize(deserializer)?);
123        let dec = E::decode_vec(&enc).map_err(|_| D::Error::custom("invalid base64"))?;
124
125        Ok(Self { cfg: PhantomData, buf: dec })
126    }
127}
128
129impl<'de, E: Encoding> Deserialize<'de> for Bytes<Box<[u8]>, E> {
130    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
131        Bytes::<Vec<u8>, E>::deserialize(deserializer).map(|x| x.buf.into_boxed_slice().into())
132    }
133}
134
135impl<'de, E: Encoding, const N: usize> Deserialize<'de> for Bytes<[u8; N], E> {
136    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
137        let bytes = Bytes::<Vec<u8>, E>::deserialize(deserializer)?;
138        let array = <[u8; N]>::try_from(bytes.buf);
139
140        Ok(array.map_err(|_| D::Error::custom("invalid base64 length"))?.into())
141    }
142}
143
144impl<T: Default, E> Default for Bytes<T, E> {
145    fn default() -> Self {
146        Self {
147            buf: T::default(),
148            cfg: PhantomData,
149        }
150    }
151}