Skip to main content

deser_core/
bytes_format.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::fmt;
4
5use crate::State;
6use crate::adapters::bytes::decode_base64;
7use crate::adapters::{Base64, BytesEncoding};
8use crate::error::Error;
9
10/// How bytes are represented in formats without native bytes.
11///
12/// It's an extension value, usually configured in the
13/// [`Context`](crate::Context) (or in the [`State`], see
14/// [`set`](Self::set)).  It's used in three places:
15///
16/// * The serializers of formats without native bytes (like JSON and TOML)
17///   write all bytes that do not request a format in it.  The default is
18///   [`BytesFormat::BASE64`].
19/// * Bytes can carry a format as fallback (see
20///   [`Bytes::fallback`](crate::Bytes::fallback)) which takes precedence
21///   over the format of the context.  The
22///   [`BytesFallback`](crate::adapters::BytesFallback) adapter does this.
23/// * The types that expect bytes decode strings with it.  Without a format
24///   lenient base64 is used.  Strings are decoded as base64 for
25///   [`BytesFormat::SEQ`].
26///
27/// ```
28/// use deser::adapters::Base64Url;
29/// use deser::{BytesFormat, Context};
30///
31/// // writes and reads URL-safe base64 in formats without native bytes
32/// let context = Context::with(BytesFormat::encoded::<Base64Url>());
33/// # let _ = context;
34/// ```
35///
36/// ```
37/// use deser::adapters::Base64UrlNoPad;
38/// use deser::BytesFormat;
39///
40/// const URL_SAFE: BytesFormat = BytesFormat::encoded::<Base64UrlNoPad>();
41/// assert_eq!(URL_SAFE.encode(b"\xfb\xff").as_deref(), Some("-_8"));
42/// // decoding is lenient
43/// assert_eq!(URL_SAFE.decode("+/8=").unwrap(), b"\xfb\xff");
44/// assert_eq!(BytesFormat::SEQ.encode(b"\x01\xff"), None);
45/// ```
46///
47/// Two formats are equal if they are both sequences or encodings with the
48/// same [name](crate::adapters::BytesEncoding::NAME).
49#[derive(Clone, Copy)]
50pub struct BytesFormat(Repr);
51
52#[derive(Clone, Copy)]
53enum Repr {
54    Encoded {
55        name: &'static str,
56        encode: fn(&[u8], &mut String),
57        decode: fn(&str) -> Result<Vec<u8>, Error>,
58    },
59    Seq,
60}
61
62impl BytesFormat {
63    /// Bytes are strings in base64 with the standard alphabet and padding.
64    ///
65    /// This is the default.
66    pub const BASE64: BytesFormat = BytesFormat::encoded::<Base64>();
67
68    /// Bytes are sequences of integers.
69    ///
70    /// This is how `serde_json` represents bytes.
71    pub const SEQ: BytesFormat = BytesFormat(Repr::Seq);
72
73    /// Bytes are strings in the given encoding.
74    pub const fn encoded<E: BytesEncoding>() -> BytesFormat {
75        BytesFormat(Repr::Encoded {
76            name: E::NAME,
77            encode: E::encode,
78            decode: E::decode,
79        })
80    }
81
82    /// Returns the format of a serialization or deserialization.
83    ///
84    /// This is [`BytesFormat::BASE64`] unless the state or the context has a
85    /// different one.
86    // not inlined: serializers read it once per value, inlining the lookup
87    // into their loops made them slower
88    #[inline(never)]
89    pub fn of(state: &State) -> BytesFormat {
90        state.get::<BytesFormat>().copied().unwrap_or_default()
91    }
92
93    /// Sets the format the types that expect bytes decode strings with.
94    #[inline]
95    pub fn set(self, state: &mut State) {
96        *state.get_mut::<BytesFormat>() = self;
97    }
98
99    /// Returns the name of the format.
100    ///
101    /// This is the [name](crate::adapters::BytesEncoding::NAME) of the encoding or `seq`.
102    pub fn name(&self) -> &'static str {
103        match self.0 {
104            Repr::Encoded { name, .. } => name,
105            Repr::Seq => "seq",
106        }
107    }
108
109    /// Encodes bytes as string.
110    ///
111    /// Returns `None` if bytes are sequences of integers.
112    pub fn encode(&self, bytes: &[u8]) -> Option<String> {
113        match self.0 {
114            Repr::Encoded { encode, .. } => {
115                let mut rv = String::new();
116                encode(bytes, &mut rv);
117                Some(rv)
118            }
119            Repr::Seq => None,
120        }
121    }
122
123    /// Decodes bytes from a string.
124    ///
125    /// For sequences of integers the string is decoded as base64.
126    pub fn decode(&self, s: &str) -> Result<Vec<u8>, Error> {
127        match self.0 {
128            Repr::Encoded { decode, .. } => decode(s),
129            Repr::Seq => decode_base64(s),
130        }
131    }
132}
133
134impl Default for BytesFormat {
135    fn default() -> BytesFormat {
136        BytesFormat::BASE64
137    }
138}
139
140impl fmt::Debug for BytesFormat {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        f.debug_tuple("BytesFormat").field(&self.name()).finish()
143    }
144}
145
146impl PartialEq for BytesFormat {
147    fn eq(&self, other: &Self) -> bool {
148        match (self.0, other.0) {
149            (Repr::Encoded { name: a, .. }, Repr::Encoded { name: b, .. }) => a == b,
150            (Repr::Seq, Repr::Seq) => true,
151            _ => false,
152        }
153    }
154}
155
156impl Eq for BytesFormat {}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use crate::adapters::Base64Url;
162
163    #[test]
164    fn test_format() {
165        assert_eq!(BytesFormat::default(), BytesFormat::BASE64);
166        assert_eq!(BytesFormat::encoded::<Base64>(), BytesFormat::BASE64);
167        assert_ne!(BytesFormat::encoded::<Base64Url>(), BytesFormat::BASE64);
168        assert_ne!(BytesFormat::SEQ, BytesFormat::BASE64);
169        assert_eq!(format!("{:?}", BytesFormat::SEQ), "BytesFormat(\"seq\")");
170        assert_eq!(BytesFormat::SEQ.decode("AQ==").unwrap(), b"\x01");
171    }
172}