postcard/
fixint.rs

1//! # Fixed Size Integers
2//!
3//! In some cases, the use of variably length encoded data may not be
4//! preferrable. These modules, for use with `#[serde(with = ...)]`
5//! "opt out" of variable length encoding.
6//!
7//! Support explicitly not provided for `usize` or `isize`, as
8//! these types would not be portable between systems of different
9//! pointer widths.
10//!
11//! Although all data in Postcard is typically encoded in little-endian
12//! order, these modules provide a choice to the user to encode the data
13//! in either little or big endian form, which may be useful for zero-copy
14//! applications.
15
16use serde::{Deserialize, Serialize, Serializer};
17
18/// Use with the `#[serde(with = "postcard::fixint::le")]` field attribute.
19///
20/// Disables varint serialization/deserialization for the specified integer
21/// field. The integer will always be serialized in the same way as a fixed
22/// size array, in **Little Endian** order on the wire.
23///
24/// ```rust
25/// # use serde::Serialize;
26/// #[derive(Serialize)]
27/// pub struct DefinitelyLittleEndian {
28///     #[serde(with = "postcard::fixint::le")]
29///     x: u16,
30/// }
31/// ```
32pub mod le {
33    use serde::{Deserialize, Deserializer, Serialize, Serializer};
34
35    use super::LE;
36
37    /// Serialize the integer value as a little-endian fixed-size array.
38    pub fn serialize<S, T>(val: &T, serializer: S) -> Result<S::Ok, S::Error>
39    where
40        S: Serializer,
41        T: Copy,
42        LE<T>: Serialize,
43    {
44        LE(*val).serialize(serializer)
45    }
46
47    /// Deserialize the integer value from a little-endian fixed-size array.
48    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
49    where
50        D: Deserializer<'de>,
51        LE<T>: Deserialize<'de>,
52    {
53        LE::<T>::deserialize(deserializer).map(|x| x.0)
54    }
55}
56
57/// Disables varint serialization/deserialization for the specified integer field.
58///
59/// Use with the `#[serde(with = "postcard::fixint::be")]` field attribute.
60/// The integer will always be serialized in the same way as a fixed
61/// size array, in **Big Endian** order on the wire.
62///
63/// ```rust
64/// # use serde::Serialize;
65/// #[derive(Serialize)]
66/// pub struct DefinitelyBigEndian {
67///     #[serde(with = "postcard::fixint::be")]
68///     x: u16,
69/// }
70/// ```
71pub mod be {
72    use serde::{Deserialize, Deserializer, Serialize, Serializer};
73
74    use super::BE;
75
76    /// Serialize the integer value as a big-endian fixed-size array.
77    pub fn serialize<S, T>(val: &T, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: Serializer,
80        T: Copy,
81        BE<T>: Serialize,
82    {
83        BE(*val).serialize(serializer)
84    }
85
86    /// Deserialize the integer value from a big-endian fixed-size array.
87    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
88    where
89        D: Deserializer<'de>,
90        BE<T>: Deserialize<'de>,
91    {
92        BE::<T>::deserialize(deserializer).map(|x| x.0)
93    }
94}
95
96#[doc(hidden)]
97pub struct LE<T>(T);
98
99#[doc(hidden)]
100pub struct BE<T>(T);
101
102macro_rules! impl_fixint {
103    ($( $int:ty ),*) => {
104        $(
105            impl Serialize for LE<$int> {
106                #[inline]
107                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108                where
109                    S: Serializer,
110                {
111                    self.0.to_le_bytes().serialize(serializer)
112                }
113            }
114
115            impl<'de> Deserialize<'de> for LE<$int> {
116                #[inline]
117                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
118                where
119                    D: serde::Deserializer<'de>,
120                {
121                    <_ as Deserialize>::deserialize(deserializer)
122                        .map(<$int>::from_le_bytes)
123                        .map(Self)
124                }
125            }
126
127            impl Serialize for BE<$int> {
128                #[inline]
129                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
130                where
131                    S: Serializer,
132                {
133                    self.0.to_be_bytes().serialize(serializer)
134                }
135            }
136
137            impl<'de> Deserialize<'de> for BE<$int> {
138                #[inline]
139                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140                where
141                    D: serde::Deserializer<'de>,
142                {
143                    <_ as Deserialize>::deserialize(deserializer)
144                        .map(<$int>::from_be_bytes)
145                        .map(Self)
146                }
147            }
148        )*
149    };
150}
151
152impl_fixint![i16, i32, i64, i128, u16, u32, u64, u128];
153
154#[cfg(test)]
155mod tests {
156    use serde::{Deserialize, Serialize};
157
158    #[test]
159    fn test_little_endian() {
160        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
161        pub struct DefinitelyLE {
162            #[serde(with = "crate::fixint::le")]
163            x: u16,
164        }
165
166        let input = DefinitelyLE { x: 0xABCD };
167        let mut buf = [0; 32];
168        let serialized = crate::to_slice(&input, &mut buf).unwrap();
169        assert_eq!(serialized, &[0xCD, 0xAB]);
170
171        let deserialized: DefinitelyLE = crate::from_bytes(serialized).unwrap();
172        assert_eq!(deserialized, input);
173    }
174
175    #[test]
176    fn test_big_endian() {
177        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
178        pub struct DefinitelyBE {
179            #[serde(with = "crate::fixint::be")]
180            x: u16,
181        }
182
183        let input = DefinitelyBE { x: 0xABCD };
184        let mut buf = [0; 32];
185        let serialized = crate::to_slice(&input, &mut buf).unwrap();
186        assert_eq!(serialized, &[0xAB, 0xCD]);
187
188        let deserialized: DefinitelyBE = crate::from_bytes(serialized).unwrap();
189        assert_eq!(deserialized, input);
190    }
191}