postcard/
byte_array.rs

1use serde::ser::SerializeTupleStruct;
2use serde::Serialize;
3use serde::Serializer;
4
5use core::convert::TryInto;
6use core::fmt;
7use serde::Deserializer;
8use serde::Deserialize;
9use serde::de;
10
11/// Represents a fixed-size byte array for better performance with `postcard`.
12///
13/// This struct *only* works with `postcard` (de-)serialization.
14#[repr(transparent)]
15pub struct FixedSizeByteArray<const N: usize> {
16    inner: FixedSizeByteArrayInner<N>,
17}
18
19impl<const N: usize> From<[u8; N]> for FixedSizeByteArray<N> {
20    fn from(array: [u8; N]) -> FixedSizeByteArray<N> {
21        FixedSizeByteArray {
22            inner: FixedSizeByteArrayInner {
23                array,
24            },
25        }
26    }
27}
28
29impl<const N: usize> FixedSizeByteArray<N> {
30    /// Extract the actual array.
31    pub fn into_inner(self) -> [u8; N] {
32        self.inner.array
33    }
34}
35
36#[repr(transparent)]
37struct FixedSizeByteArrayInner<const N: usize> {
38    array: [u8; N],
39}
40
41pub static TOKEN: &str = "$postcard::private::FixedSizeByteArray";
42
43impl<const N: usize> Serialize for FixedSizeByteArray<N> {
44    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45    where
46        S: Serializer,
47    {
48        let mut s = serializer.serialize_tuple_struct(TOKEN, 1)?;
49        s.serialize_field(&self.inner)?;
50        s.end()
51    }
52}
53
54impl<const N: usize> Serialize for FixedSizeByteArrayInner<N> {
55    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56    where
57        S: Serializer,
58    {
59        serializer.serialize_bytes(&self.array)
60    }
61}
62
63impl<'de, const N: usize> Deserialize<'de> for FixedSizeByteArray<N> {
64    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65    where
66        D: Deserializer<'de>,
67    {
68        struct Visitor<const N: usize>;
69
70        impl<'de, const N: usize> de::Visitor<'de> for Visitor<N> {
71            type Value = FixedSizeByteArray<N>;
72
73            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74                write!(formatter, "byte array of length {}", N)
75            }
76
77            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
78            where
79                E: de::Error,
80            {
81                let array: [u8; N] = match v.try_into() {
82                    Ok(a) => a,
83                    Err(_) => return Err(de::Error::invalid_length(v.len(), &self)),
84                };
85                Ok(FixedSizeByteArray::from(array))
86            }
87        }
88
89        deserializer.deserialize_tuple_struct(TOKEN, N, Visitor)
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use crate::Error;
96    use super::FixedSizeByteArray;
97
98    #[test]
99    fn test_byte_array_serialize() {
100        let empty = FixedSizeByteArray::from([]);
101        let mut buf = [0; 32];
102        let serialized = crate::to_slice(&empty, &mut buf).unwrap();
103        assert_eq!(serialized, &[]);
104
105        let single = FixedSizeByteArray::from([0x12]);
106        let mut buf = [0; 32];
107        let serialized = crate::to_slice(&single, &mut buf).unwrap();
108        assert_eq!(serialized, &[0x12]);
109
110        let five_bytes = FixedSizeByteArray::from([0x12, 0x34, 0x56, 0x78, 0x90]);
111        let mut buf = [0; 32];
112        let serialized = crate::to_slice(&five_bytes, &mut buf).unwrap();
113        assert_eq!(serialized, &[0x12, 0x34, 0x56, 0x78, 0x90]);
114    }
115
116    #[test]
117    fn test_byte_array_deserialize() {
118        let deserialized: FixedSizeByteArray<0> = crate::from_bytes(&[]).unwrap();
119        assert_eq!(deserialized.into_inner(), []);
120
121        let deserialized: FixedSizeByteArray<0> = crate::from_bytes(&[0x12]).unwrap();
122        assert_eq!(deserialized.into_inner(), []);
123
124        let deserialized: FixedSizeByteArray<1> = crate::from_bytes(&[0x12]).unwrap();
125        assert_eq!(deserialized.into_inner(), [0x12]);
126
127        let deserialized: FixedSizeByteArray<5> = crate::from_bytes(&[0x12, 0x34, 0x56, 0x78, 0x90]).unwrap();
128        assert_eq!(deserialized.into_inner(), [0x12, 0x34, 0x56, 0x78, 0x90]);
129    }
130
131    #[test]
132    fn test_byte_array_deserialize_error() {
133        let result: Result<FixedSizeByteArray<1>, _> = crate::from_bytes(&[]);
134        assert_eq!(result.err().unwrap(), Error::DeserializeUnexpectedEnd);
135
136        let result: Result<FixedSizeByteArray<8>, _> = crate::from_bytes(&[0x12]);
137        assert_eq!(result.err().unwrap(), Error::DeserializeUnexpectedEnd);
138
139        let result: Result<FixedSizeByteArray<8>, _> = crate::from_bytes(&[0x12, 0x34, 0x56, 0x78]);
140        assert_eq!(result.err().unwrap(), Error::DeserializeUnexpectedEnd);
141    }
142}