1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//! # Fixed Size Integers
//!
//! In some cases, the use of variably length encoded data may not be
//! preferrable. These modules, for use with `#[serde(with = ...)]`
//! "opt out" of variable length encoding.
//!
//! Support explicitly not provided for `usize` or `isize`, as
//! these types would not be portable between systems of different
//! pointer widths.
//!
//! Although all data in Postcard is typically encoded in little-endian
//! order, these modules provide a choice to the user to encode the data
//! in either little or big endian form, which may be useful for zero-copy
//! applications.

use serde::{Deserialize, Serialize, Serializer};

/// Use with the `#[serde(with = "postcard::fixint::le")]` field attribute.
/// Disables varint serialization/deserialization for the specified integer
/// field. The integer will always be serialized in the same way as a fixed
/// size array, in **Little Endian** order on the wire.
///
/// ```rust
/// # use serde::Serialize;
/// #[derive(Serialize)]
/// pub struct DefinitelyLittleEndian {
///     #[serde(with = "postcard::fixint::le")]
///     x: u16,
/// }
/// ```
pub mod le {
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    use super::LE;

    /// Serialize the integer value as a little-endian fixed-size array.
    pub fn serialize<S, T>(val: &T, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
        T: Copy,
        LE<T>: Serialize,
    {
        LE(*val).serialize(serializer)
    }

    /// Deserialize the integer value from a little-endian fixed-size array.
    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
    where
        D: Deserializer<'de>,
        LE<T>: Deserialize<'de>,
    {
        LE::<T>::deserialize(deserializer).map(|x| x.0)
    }
}

/// Use with the `#[serde(with = "postcard::fixint::be")]` field attribute.
/// Disables varint serialization/deserialization for the specified integer
/// field. The integer will always be serialized in the same way as a fixed
/// size array, in **Big Endian** order on the wire.
///
/// ```rust
/// # use serde::Serialize;
/// #[derive(Serialize)]
/// pub struct DefinitelyBigEndian {
///     #[serde(with = "postcard::fixint::be")]
///     x: u16,
/// }
/// ```
pub mod be {
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    use super::BE;

    /// Serialize the integer value as a big-endian fixed-size array.
    pub fn serialize<S, T>(val: &T, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
        T: Copy,
        BE<T>: Serialize,
    {
        BE(*val).serialize(serializer)
    }

    /// Deserialize the integer value from a big-endian fixed-size array.
    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
    where
        D: Deserializer<'de>,
        BE<T>: Deserialize<'de>,
    {
        BE::<T>::deserialize(deserializer).map(|x| x.0)
    }
}

#[doc(hidden)]
pub struct LE<T>(T);

#[doc(hidden)]
pub struct BE<T>(T);

macro_rules! impl_fixint {
    ($( $int:ty ),*) => {
        $(
            impl Serialize for LE<$int> {
                #[inline]
                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where
                    S: Serializer,
                {
                    self.0.to_le_bytes().serialize(serializer)
                }
            }

            impl<'de> Deserialize<'de> for LE<$int> {
                #[inline]
                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where
                    D: serde::Deserializer<'de>,
                {
                    <_ as Deserialize>::deserialize(deserializer)
                        .map(<$int>::from_le_bytes)
                        .map(Self)
                }
            }

            impl Serialize for BE<$int> {
                #[inline]
                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where
                    S: Serializer,
                {
                    self.0.to_be_bytes().serialize(serializer)
                }
            }

            impl<'de> Deserialize<'de> for BE<$int> {
                #[inline]
                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where
                    D: serde::Deserializer<'de>,
                {
                    <_ as Deserialize>::deserialize(deserializer)
                        .map(<$int>::from_be_bytes)
                        .map(Self)
                }
            }
        )*
    };
}

impl_fixint![i16, i32, i64, i128, u16, u32, u64, u128];

#[cfg(test)]
mod tests {
    use serde::{Deserialize, Serialize};

    #[test]
    fn test_little_endian() {
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub struct DefinitelyLE {
            #[serde(with = "crate::fixint::le")]
            x: u16,
        }

        let input = DefinitelyLE { x: 0xABCD };
        let mut buf = [0; 32];
        let serialized = crate::to_slice(&input, &mut buf).unwrap();
        assert_eq!(serialized, &[0xCD, 0xAB]);

        let deserialized: DefinitelyLE = crate::from_bytes(serialized).unwrap();
        assert_eq!(deserialized, input);
    }

    #[test]
    fn test_big_endian() {
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub struct DefinitelyBE {
            #[serde(with = "crate::fixint::be")]
            x: u16,
        }

        let input = DefinitelyBE { x: 0xABCD };
        let mut buf = [0; 32];
        let serialized = crate::to_slice(&input, &mut buf).unwrap();
        assert_eq!(serialized, &[0xAB, 0xCD]);

        let deserialized: DefinitelyBE = crate::from_bytes(serialized).unwrap();
        assert_eq!(deserialized, input);
    }
}