Skip to main content

wire_repr/codec/
integers.rs

1//! Built-in fixed-width integer codecs.
2
3use core::{convert::Infallible, fmt};
4
5use super::FixedCodec;
6
7/// Error returned when a `u32` does not fit in an unsigned 24-bit integer.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct U24RangeError {
10    value: u32,
11}
12
13impl U24RangeError {
14    /// Creates an error for an unrepresentable value.
15    #[must_use]
16    pub const fn new(value: u32) -> Self {
17        Self { value }
18    }
19
20    /// Returns the unrepresentable value.
21    #[must_use]
22    pub const fn value(&self) -> u32 {
23        self.value
24    }
25}
26
27impl fmt::Display for U24RangeError {
28    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
29        write!(
30            formatter,
31            "{} does not fit in an unsigned 24-bit integer",
32            self.value
33        )
34    }
35}
36
37impl core::error::Error for U24RangeError {}
38
39macro_rules! fixed_integer_codec {
40    ($name:ident, $value:ty, $width:literal, $from:ident, $to:ident) => {
41        impl FixedCodec for $name {
42            type Value<'wire>
43                = $value
44            where
45                Self: 'wire;
46            type EncodeError = Infallible;
47            type Plan<'value>
48                = [u8; $width]
49            where
50                Self: 'value;
51
52            const WIDTH: usize = $width;
53
54            #[inline]
55            fn decode<'wire>(bytes: &'wire [u8]) -> Self::Value<'wire> {
56                let mut encoded = [0_u8; $width];
57                encoded.copy_from_slice(bytes);
58                <$value>::$from(encoded)
59            }
60
61            #[inline]
62            fn plan<'value>(
63                value: Self::Value<'value>,
64            ) -> Result<Self::Plan<'value>, Self::EncodeError> {
65                Ok(value.$to())
66            }
67        }
68    };
69}
70
71/// One-byte unsigned integer codec.
72#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct U8;
74fixed_integer_codec!(U8, u8, 1, from_ne_bytes, to_ne_bytes);
75
76/// One-byte signed integer codec.
77#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct I8;
79fixed_integer_codec!(I8, i8, 1, from_ne_bytes, to_ne_bytes);
80
81/// Big-endian `u16` codec.
82#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
83pub struct BeU16;
84fixed_integer_codec!(BeU16, u16, 2, from_be_bytes, to_be_bytes);
85
86/// Little-endian `u16` codec.
87#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub struct LeU16;
89fixed_integer_codec!(LeU16, u16, 2, from_le_bytes, to_le_bytes);
90
91/// Big-endian `i16` codec.
92#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub struct BeI16;
94fixed_integer_codec!(BeI16, i16, 2, from_be_bytes, to_be_bytes);
95
96/// Little-endian `i16` codec.
97#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct LeI16;
99fixed_integer_codec!(LeI16, i16, 2, from_le_bytes, to_le_bytes);
100
101/// Big-endian `u32` codec.
102#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
103pub struct BeU32;
104fixed_integer_codec!(BeU32, u32, 4, from_be_bytes, to_be_bytes);
105
106/// Little-endian `u32` codec.
107#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct LeU32;
109fixed_integer_codec!(LeU32, u32, 4, from_le_bytes, to_le_bytes);
110
111/// Big-endian `i32` codec.
112#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
113pub struct BeI32;
114fixed_integer_codec!(BeI32, i32, 4, from_be_bytes, to_be_bytes);
115
116/// Little-endian `i32` codec.
117#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
118pub struct LeI32;
119fixed_integer_codec!(LeI32, i32, 4, from_le_bytes, to_le_bytes);
120
121/// Big-endian `u64` codec.
122#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
123pub struct BeU64;
124fixed_integer_codec!(BeU64, u64, 8, from_be_bytes, to_be_bytes);
125
126/// Little-endian `u64` codec.
127#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
128pub struct LeU64;
129fixed_integer_codec!(LeU64, u64, 8, from_le_bytes, to_le_bytes);
130
131/// Big-endian `i64` codec.
132#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
133pub struct BeI64;
134fixed_integer_codec!(BeI64, i64, 8, from_be_bytes, to_be_bytes);
135
136/// Little-endian `i64` codec.
137#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
138pub struct LeI64;
139fixed_integer_codec!(LeI64, i64, 8, from_le_bytes, to_le_bytes);
140
141/// Big-endian `u128` codec.
142#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
143pub struct BeU128;
144fixed_integer_codec!(BeU128, u128, 16, from_be_bytes, to_be_bytes);
145
146/// Little-endian `u128` codec.
147#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
148pub struct LeU128;
149fixed_integer_codec!(LeU128, u128, 16, from_le_bytes, to_le_bytes);
150
151/// Big-endian `i128` codec.
152#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
153pub struct BeI128;
154fixed_integer_codec!(BeI128, i128, 16, from_be_bytes, to_be_bytes);
155
156/// Little-endian `i128` codec.
157#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
158pub struct LeI128;
159fixed_integer_codec!(LeI128, i128, 16, from_le_bytes, to_le_bytes);
160
161#[inline]
162fn decode_be_u24(bytes: [u8; 3]) -> u32 {
163    u32::from_be_bytes([0, bytes[0], bytes[1], bytes[2]])
164}
165
166#[inline]
167fn decode_le_u24(bytes: [u8; 3]) -> u32 {
168    u32::from_le_bytes([bytes[0], bytes[1], bytes[2], 0])
169}
170
171#[inline]
172fn encode_be_u24(value: u32) -> [u8; 3] {
173    let bytes = value.to_be_bytes();
174    [bytes[1], bytes[2], bytes[3]]
175}
176
177#[inline]
178fn encode_le_u24(value: u32) -> [u8; 3] {
179    let bytes = value.to_le_bytes();
180    [bytes[0], bytes[1], bytes[2]]
181}
182
183/// Big-endian unsigned 24-bit integer codec over `u32`.
184#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
185pub struct BeU24;
186
187impl FixedCodec for BeU24 {
188    type Value<'wire>
189        = u32
190    where
191        Self: 'wire;
192    type EncodeError = U24RangeError;
193    type Plan<'value>
194        = [u8; 3]
195    where
196        Self: 'value;
197
198    const WIDTH: usize = 3;
199
200    #[inline]
201    fn decode<'wire>(bytes: &'wire [u8]) -> Self::Value<'wire> {
202        let mut encoded = [0_u8; 3];
203        encoded.copy_from_slice(bytes);
204        decode_be_u24(encoded)
205    }
206
207    #[inline]
208    fn plan<'value>(value: Self::Value<'value>) -> Result<Self::Plan<'value>, Self::EncodeError> {
209        if value > 0x00ff_ffff {
210            Err(U24RangeError::new(value))
211        } else {
212            Ok(encode_be_u24(value))
213        }
214    }
215}
216
217/// Little-endian unsigned 24-bit integer codec over `u32`.
218#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
219pub struct LeU24;
220
221impl FixedCodec for LeU24 {
222    type Value<'wire>
223        = u32
224    where
225        Self: 'wire;
226    type EncodeError = U24RangeError;
227    type Plan<'value>
228        = [u8; 3]
229    where
230        Self: 'value;
231
232    const WIDTH: usize = 3;
233
234    #[inline]
235    fn decode<'wire>(bytes: &'wire [u8]) -> Self::Value<'wire> {
236        let mut encoded = [0_u8; 3];
237        encoded.copy_from_slice(bytes);
238        decode_le_u24(encoded)
239    }
240
241    #[inline]
242    fn plan<'value>(value: Self::Value<'value>) -> Result<Self::Plan<'value>, Self::EncodeError> {
243        if value > 0x00ff_ffff {
244            Err(U24RangeError::new(value))
245        } else {
246            Ok(encode_le_u24(value))
247        }
248    }
249}