serdect/
slice.rs

1//! Serialization primitives for slices.
2
3use core::fmt;
4
5use serde::de::{Error, Visitor};
6use serde::{Deserializer, Serialize, Serializer};
7
8#[cfg(feature = "alloc")]
9use ::{alloc::vec::Vec, serde::Deserialize};
10
11#[cfg(feature = "zeroize")]
12use zeroize::Zeroize;
13
14/// Serialize the given type as lower case hex when using human-readable
15/// formats or binary if the format is binary.
16pub fn serialize_hex_lower_or_bin<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
17where
18    S: Serializer,
19    T: AsRef<[u8]>,
20{
21    if serializer.is_human_readable() {
22        crate::serialize_hex::<_, _, false>(value, serializer)
23    } else {
24        value.as_ref().serialize(serializer)
25    }
26}
27
28/// Serialize the given type as upper case hex when using human-readable
29/// formats or binary if the format is binary.
30pub fn serialize_hex_upper_or_bin<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
31where
32    S: Serializer,
33    T: AsRef<[u8]>,
34{
35    if serializer.is_human_readable() {
36        crate::serialize_hex::<_, _, true>(value, serializer)
37    } else {
38        value.as_ref().serialize(serializer)
39    }
40}
41
42/// Deserialize from hex when using human-readable formats or binary if the
43/// format is binary. Fails if the `buffer` is smaller then the resulting
44/// slice.
45pub fn deserialize_hex_or_bin<'de, D>(buffer: &mut [u8], deserializer: D) -> Result<&[u8], D::Error>
46where
47    D: Deserializer<'de>,
48{
49    if deserializer.is_human_readable() {
50        struct StrVisitor<'b>(&'b mut [u8]);
51
52        impl<'de, 'b> Visitor<'de> for StrVisitor<'b> {
53            type Value = &'b [u8];
54
55            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
56                write!(
57                    formatter,
58                    "a string with a maximum length of {}",
59                    self.0.len() * 2
60                )
61            }
62
63            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
64            where
65                E: Error,
66            {
67                // TODO: Map `base16ct::Error::InvalidLength` to `Error::invalid_length`.
68                base16ct::mixed::decode(v, self.0).map_err(E::custom)
69            }
70        }
71
72        deserializer.deserialize_str(StrVisitor(buffer))
73    } else {
74        struct SliceVisitor<'b>(&'b mut [u8]);
75
76        impl<'de, 'b> Visitor<'de> for SliceVisitor<'b> {
77            type Value = &'b [u8];
78
79            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
80                write!(
81                    formatter,
82                    "a slice with a maximum length of {}",
83                    self.0.len()
84                )
85            }
86
87            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
88            where
89                E: Error,
90            {
91                // Workaround for
92                // https://github.com/rust-lang/rfcs/blob/b1de05846d9bc5591d753f611ab8ee84a01fa500/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions
93                if v.len() <= self.0.len() {
94                    let buffer = &mut self.0[..v.len()];
95                    buffer.copy_from_slice(v);
96                    return Ok(buffer);
97                }
98
99                Err(E::invalid_length(v.len(), &self))
100            }
101
102            #[cfg(feature = "alloc")]
103            fn visit_byte_buf<E>(self, mut v: Vec<u8>) -> Result<Self::Value, E>
104            where
105                E: Error,
106            {
107                // Workaround for
108                // https://github.com/rust-lang/rfcs/blob/b1de05846d9bc5591d753f611ab8ee84a01fa500/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions
109                if v.len() <= self.0.len() {
110                    let buffer = &mut self.0[..v.len()];
111                    buffer.swap_with_slice(&mut v);
112                    return Ok(buffer);
113                }
114
115                Err(E::invalid_length(v.len(), &self))
116            }
117        }
118
119        deserializer.deserialize_byte_buf(SliceVisitor(buffer))
120    }
121}
122
123/// Deserialize from hex when using human-readable formats or binary if the
124/// format is binary.
125#[cfg(feature = "alloc")]
126#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
127pub fn deserialize_hex_or_bin_vec<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
128where
129    D: Deserializer<'de>,
130{
131    if deserializer.is_human_readable() {
132        struct StrVisitor;
133
134        impl<'de> Visitor<'de> for StrVisitor {
135            type Value = Vec<u8>;
136
137            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
138                write!(formatter, "a string")
139            }
140
141            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
142            where
143                E: Error,
144            {
145                base16ct::mixed::decode_vec(v).map_err(E::custom)
146            }
147        }
148
149        deserializer.deserialize_str(StrVisitor)
150    } else {
151        Vec::deserialize(deserializer)
152    }
153}
154
155/// [`HexOrBin`] serializer which uses lower case.
156#[cfg(feature = "alloc")]
157#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
158pub type HexLowerOrBin = HexOrBin<false>;
159
160/// [`HexOrBin`] serializer which uses upper case.
161#[cfg(feature = "alloc")]
162#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
163pub type HexUpperOrBin = HexOrBin<true>;
164
165/// Serializer/deserializer newtype which encodes bytes as either binary or hex.
166///
167/// Use hexadecimal with human-readable formats, or raw binary with binary formats.
168#[cfg(feature = "alloc")]
169#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
170#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
171pub struct HexOrBin<const UPPERCASE: bool>(pub Vec<u8>);
172
173#[cfg(feature = "alloc")]
174#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
175impl<const UPPERCASE: bool> AsRef<[u8]> for HexOrBin<UPPERCASE> {
176    fn as_ref(&self) -> &[u8] {
177        self.0.as_ref()
178    }
179}
180
181#[cfg(feature = "alloc")]
182#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
183impl<const UPPERCASE: bool> From<&[u8]> for HexOrBin<UPPERCASE> {
184    fn from(bytes: &[u8]) -> HexOrBin<UPPERCASE> {
185        Self(bytes.into())
186    }
187}
188
189#[cfg(feature = "alloc")]
190#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
191impl<const UPPERCASE: bool> From<Vec<u8>> for HexOrBin<UPPERCASE> {
192    fn from(vec: Vec<u8>) -> HexOrBin<UPPERCASE> {
193        Self(vec)
194    }
195}
196
197#[cfg(feature = "alloc")]
198#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
199impl<const UPPERCASE: bool> From<HexOrBin<UPPERCASE>> for Vec<u8> {
200    fn from(vec: HexOrBin<UPPERCASE>) -> Vec<u8> {
201        vec.0
202    }
203}
204
205#[cfg(feature = "alloc")]
206#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
207impl<const UPPERCASE: bool> Serialize for HexOrBin<UPPERCASE> {
208    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
209    where
210        S: Serializer,
211    {
212        if UPPERCASE {
213            serialize_hex_upper_or_bin(self, serializer)
214        } else {
215            serialize_hex_lower_or_bin(self, serializer)
216        }
217    }
218}
219
220#[cfg(feature = "alloc")]
221#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
222impl<'de, const UPPERCASE: bool> Deserialize<'de> for HexOrBin<UPPERCASE> {
223    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
224    where
225        D: Deserializer<'de>,
226    {
227        deserialize_hex_or_bin_vec(deserializer).map(Self)
228    }
229}
230
231#[cfg(all(feature = "alloc", feature = "zeroize"))]
232#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "zeroize"))))]
233impl<const UPPERCASE: bool> Zeroize for HexOrBin<UPPERCASE> {
234    fn zeroize(&mut self) {
235        self.0.as_mut_slice().zeroize();
236    }
237}