Line data Source code
1 : //! Utilities for binary serialization/deserialization.
2 : //!
3 : //! The [`BeSer`] trait allows us to define data structures
4 : //! that can match data structures that are sent over the wire
5 : //! in big-endian form with no packing.
6 : //!
7 : //! The [`LeSer`] trait does the same thing, in little-endian form.
8 : //!
9 : //! Note: you will get a compile error if you try to `use` both traits
10 : //! in the same module or scope. This is intended to be a safety
11 : //! mechanism: mixing big-endian and little-endian encoding in the same file
12 : //! is error-prone.
13 :
14 : #![warn(missing_docs)]
15 :
16 : use bincode::Options;
17 : use serde::{de::DeserializeOwned, Serialize};
18 : use std::io::{self, Read, Write};
19 : use thiserror::Error;
20 :
21 : /// An error that occurred during a deserialize operation
22 : ///
23 : /// This could happen because the input data was too short,
24 : /// or because an invalid value was encountered.
25 0 : #[derive(Debug, Error)]
26 : pub enum DeserializeError {
27 : /// The deserializer isn't able to deserialize the supplied data.
28 : #[error("deserialize error")]
29 : BadInput,
30 : /// While deserializing from a `Read` source, an `io::Error` occurred.
31 : #[error("deserialize error: {0}")]
32 : Io(io::Error),
33 : }
34 :
35 : impl From<bincode::Error> for DeserializeError {
36 2 : fn from(e: bincode::Error) -> Self {
37 2 : match *e {
38 2 : bincode::ErrorKind::Io(io_err) => DeserializeError::Io(io_err),
39 0 : _ => DeserializeError::BadInput,
40 : }
41 2 : }
42 : }
43 :
44 : /// An error that occurred during a serialize operation
45 : ///
46 : /// This probably means our [`Write`] failed, e.g. we tried
47 : /// to write beyond the end of a buffer.
48 0 : #[derive(Debug, Error)]
49 : pub enum SerializeError {
50 : /// The serializer isn't able to serialize the supplied data.
51 : #[error("serialize error")]
52 : BadInput,
53 : /// While serializing into a `Write` sink, an `io::Error` occurred.
54 : #[error("serialize error: {0}")]
55 : Io(io::Error),
56 : }
57 :
58 : impl From<bincode::Error> for SerializeError {
59 0 : fn from(e: bincode::Error) -> Self {
60 0 : match *e {
61 0 : bincode::ErrorKind::Io(io_err) => SerializeError::Io(io_err),
62 0 : _ => SerializeError::BadInput,
63 : }
64 0 : }
65 : }
66 :
67 : /// A shortcut that configures big-endian binary serialization
68 : ///
69 : /// Properties:
70 : /// - Big endian
71 : /// - Fixed integer encoding (i.e. 1u32 is 00000001 not 01)
72 : ///
73 : /// Does not allow trailing bytes in deserialization. If this is desired, you
74 : /// may set [`Options::allow_trailing_bytes`] to explicitly accommodate this.
75 14610450 : pub fn be_coder() -> impl Options {
76 14610450 : bincode::DefaultOptions::new()
77 14610450 : .with_big_endian()
78 14610450 : .with_fixint_encoding()
79 14610450 : }
80 :
81 : /// A shortcut that configures little-ending binary serialization
82 : ///
83 : /// Properties:
84 : /// - Little endian
85 : /// - Fixed integer encoding (i.e. 1u32 is 00000001 not 01)
86 : ///
87 : /// Does not allow trailing bytes in deserialization. If this is desired, you
88 : /// may set [`Options::allow_trailing_bytes`] to explicitly accommodate this.
89 397765 : pub fn le_coder() -> impl Options {
90 397765 : bincode::DefaultOptions::new()
91 397765 : .with_little_endian()
92 397765 : .with_fixint_encoding()
93 397765 : }
94 :
95 : /// Binary serialize/deserialize helper functions (Big Endian)
96 : ///
97 : pub trait BeSer {
98 : /// Serialize into a byte slice
99 0 : fn ser_into_slice(&self, mut b: &mut [u8]) -> Result<(), SerializeError>
100 0 : where
101 0 : Self: Serialize,
102 0 : {
103 0 : // &mut [u8] implements Write, but `ser_into` needs a mutable
104 0 : // reference to that. So we need the slightly awkward "mutable
105 0 : // reference to a mutable reference.
106 0 : self.ser_into(&mut b)
107 0 : }
108 :
109 : /// Serialize into a borrowed writer
110 : ///
111 : /// This is useful for most `Write` types except `&mut [u8]`, which
112 : /// can more easily use [`ser_into_slice`](Self::ser_into_slice).
113 5092304 : fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
114 5092304 : where
115 5092304 : Self: Serialize,
116 5092304 : {
117 5092304 : be_coder().serialize_into(w, &self).map_err(|e| e.into())
118 5092304 : }
119 :
120 : /// Serialize into a new heap-allocated buffer
121 2087172 : fn ser(&self) -> Result<Vec<u8>, SerializeError>
122 2087172 : where
123 2087172 : Self: Serialize,
124 2087172 : {
125 2087172 : be_coder().serialize(&self).map_err(|e| e.into())
126 2087172 : }
127 :
128 : /// Deserialize from the full contents of a byte slice
129 : ///
130 : /// See also: [`BeSer::des_prefix`]
131 2753614 : fn des(buf: &[u8]) -> Result<Self, DeserializeError>
132 2753614 : where
133 2753614 : Self: DeserializeOwned,
134 2753614 : {
135 2753614 : be_coder()
136 2753614 : .deserialize(buf)
137 2753614 : .or(Err(DeserializeError::BadInput))
138 2753614 : }
139 :
140 : /// Deserialize from a prefix of the byte slice
141 : ///
142 : /// Uses as much of the byte slice as is necessary to deserialize the
143 : /// type, but does not guarantee that the entire slice is used.
144 : ///
145 : /// See also: [`BeSer::des`]
146 1191 : fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
147 1191 : where
148 1191 : Self: DeserializeOwned,
149 1191 : {
150 1191 : be_coder()
151 1191 : .allow_trailing_bytes()
152 1191 : .deserialize(buf)
153 1191 : .or(Err(DeserializeError::BadInput))
154 1191 : }
155 :
156 : /// Deserialize from a reader
157 2 : fn des_from<R: Read>(r: &mut R) -> Result<Self, DeserializeError>
158 2 : where
159 2 : Self: DeserializeOwned,
160 2 : {
161 2 : be_coder().deserialize_from(r).map_err(|e| e.into())
162 2 : }
163 :
164 : /// Compute the serialized size of a data structure
165 : ///
166 : /// Note: it may be faster to serialize to a buffer and then measure the
167 : /// buffer length, than to call `serialized_size` and then `ser_into`.
168 4676167 : fn serialized_size(&self) -> Result<u64, SerializeError>
169 4676167 : where
170 4676167 : Self: Serialize,
171 4676167 : {
172 4676167 : be_coder().serialized_size(self).map_err(|e| e.into())
173 4676167 : }
174 : }
175 :
176 : /// Binary serialize/deserialize helper functions (Little Endian)
177 : ///
178 : pub trait LeSer {
179 : /// Serialize into a byte slice
180 0 : fn ser_into_slice(&self, mut b: &mut [u8]) -> Result<(), SerializeError>
181 0 : where
182 0 : Self: Serialize,
183 0 : {
184 0 : // &mut [u8] implements Write, but `ser_into` needs a mutable
185 0 : // reference to that. So we need the slightly awkward "mutable
186 0 : // reference to a mutable reference.
187 0 : self.ser_into(&mut b)
188 0 : }
189 :
190 : /// Serialize into a borrowed writer
191 : ///
192 : /// This is useful for most `Write` types except `&mut [u8]`, which
193 : /// can more easily use [`ser_into_slice`](Self::ser_into_slice).
194 5 : fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
195 5 : where
196 5 : Self: Serialize,
197 5 : {
198 5 : le_coder().serialize_into(w, &self).map_err(|e| e.into())
199 5 : }
200 :
201 : /// Serialize into a new heap-allocated buffer
202 35603 : fn ser(&self) -> Result<Vec<u8>, SerializeError>
203 35603 : where
204 35603 : Self: Serialize,
205 35603 : {
206 35603 : le_coder().serialize(&self).map_err(|e| e.into())
207 35603 : }
208 :
209 : /// Deserialize from the full contents of a byte slice
210 : ///
211 : /// See also: [`LeSer::des_prefix`]
212 170074 : fn des(buf: &[u8]) -> Result<Self, DeserializeError>
213 170074 : where
214 170074 : Self: DeserializeOwned,
215 170074 : {
216 170074 : le_coder()
217 170074 : .deserialize(buf)
218 170074 : .or(Err(DeserializeError::BadInput))
219 170074 : }
220 :
221 : /// Deserialize from a prefix of the byte slice
222 : ///
223 : /// Uses as much of the byte slice as is necessary to deserialize the
224 : /// type, but does not guarantee that the entire slice is used.
225 : ///
226 : /// See also: [`LeSer::des`]
227 5 : fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
228 5 : where
229 5 : Self: DeserializeOwned,
230 5 : {
231 5 : le_coder()
232 5 : .allow_trailing_bytes()
233 5 : .deserialize(buf)
234 5 : .or(Err(DeserializeError::BadInput))
235 5 : }
236 :
237 : /// Deserialize from a reader
238 192076 : fn des_from<R: Read>(r: &mut R) -> Result<Self, DeserializeError>
239 192076 : where
240 192076 : Self: DeserializeOwned,
241 192076 : {
242 192076 : le_coder().deserialize_from(r).map_err(|e| e.into())
243 192076 : }
244 :
245 : /// Compute the serialized size of a data structure
246 : ///
247 : /// Note: it may be faster to serialize to a buffer and then measure the
248 : /// buffer length, than to call `serialized_size` and then `ser_into`.
249 2 : fn serialized_size(&self) -> Result<u64, SerializeError>
250 2 : where
251 2 : Self: Serialize,
252 2 : {
253 2 : le_coder().serialized_size(self).map_err(|e| e.into())
254 2 : }
255 : }
256 :
257 : // Because usage of `BeSer` or `LeSer` can be done with *either* a Serialize or
258 : // DeserializeOwned implementation, the blanket implementation has to be for every type.
259 : impl<T> BeSer for T {}
260 : impl<T> LeSer for T {}
261 :
262 : #[cfg(test)]
263 : mod tests {
264 : use super::DeserializeError;
265 : use serde::{Deserialize, Serialize};
266 : use std::io::Cursor;
267 :
268 12 : #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
269 : pub struct ShortStruct {
270 : a: u8,
271 : b: u32,
272 : }
273 :
274 : const SHORT1: ShortStruct = ShortStruct { a: 7, b: 65536 };
275 : const SHORT1_ENC_BE: &[u8] = &[7, 0, 1, 0, 0];
276 : const SHORT1_ENC_BE_TRAILING: &[u8] = &[7, 0, 1, 0, 0, 255, 255, 255];
277 : const SHORT1_ENC_LE: &[u8] = &[7, 0, 0, 1, 0];
278 : const SHORT1_ENC_LE_TRAILING: &[u8] = &[7, 0, 0, 1, 0, 255, 255, 255];
279 :
280 : const SHORT2: ShortStruct = ShortStruct {
281 : a: 8,
282 : b: 0x07030000,
283 : };
284 : const SHORT2_ENC_BE: &[u8] = &[8, 7, 3, 0, 0];
285 : const SHORT2_ENC_BE_TRAILING: &[u8] = &[8, 7, 3, 0, 0, 0xff, 0xff, 0xff];
286 : const SHORT2_ENC_LE: &[u8] = &[8, 0, 0, 3, 7];
287 : const SHORT2_ENC_LE_TRAILING: &[u8] = &[8, 0, 0, 3, 7, 0xff, 0xff, 0xff];
288 :
289 2 : #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
290 : pub struct LongMsg {
291 : pub tag: u8,
292 : pub blockpos: u32,
293 : pub last_flush_position: u64,
294 : pub apply: u64,
295 : pub timestamp: i64,
296 : pub reply_requested: u8,
297 : }
298 :
299 : const LONG1: LongMsg = LongMsg {
300 : tag: 42,
301 : blockpos: 0x1000_2000,
302 : last_flush_position: 0x1234_2345_3456_4567,
303 : apply: 0x9876_5432_10FE_DCBA,
304 : timestamp: 0x7788_99AA_BBCC_DDFF,
305 : reply_requested: 1,
306 : };
307 :
308 : #[test]
309 1 : fn be_short() {
310 : use super::BeSer;
311 :
312 1 : assert_eq!(SHORT1.serialized_size().unwrap(), 5);
313 :
314 1 : let encoded = SHORT1.ser().unwrap();
315 1 : assert_eq!(encoded, SHORT1_ENC_BE);
316 :
317 1 : let decoded = ShortStruct::des(SHORT2_ENC_BE).unwrap();
318 1 : assert_eq!(decoded, SHORT2);
319 :
320 : // with trailing data
321 1 : let decoded = ShortStruct::des_prefix(SHORT2_ENC_BE_TRAILING).unwrap();
322 1 : assert_eq!(decoded, SHORT2);
323 1 : let err = ShortStruct::des(SHORT2_ENC_BE_TRAILING).unwrap_err();
324 1 : assert!(matches!(err, DeserializeError::BadInput));
325 :
326 : // serialize into a `Write` sink.
327 1 : let mut buf = Cursor::new(vec![0xFF; 8]);
328 1 : SHORT1.ser_into(&mut buf).unwrap();
329 1 : assert_eq!(buf.into_inner(), SHORT1_ENC_BE_TRAILING);
330 :
331 : // deserialize from a `Write` sink.
332 1 : let mut buf = Cursor::new(SHORT2_ENC_BE);
333 1 : let decoded = ShortStruct::des_from(&mut buf).unwrap();
334 1 : assert_eq!(decoded, SHORT2);
335 :
336 : // deserialize from a `Write` sink that terminates early.
337 1 : let mut buf = Cursor::new([0u8; 4]);
338 1 : let err = ShortStruct::des_from(&mut buf).unwrap_err();
339 1 : assert!(matches!(err, DeserializeError::Io(_)));
340 1 : }
341 :
342 : #[test]
343 1 : fn le_short() {
344 : use super::LeSer;
345 :
346 1 : assert_eq!(SHORT1.serialized_size().unwrap(), 5);
347 :
348 1 : let encoded = SHORT1.ser().unwrap();
349 1 : assert_eq!(encoded, SHORT1_ENC_LE);
350 :
351 1 : let decoded = ShortStruct::des(SHORT2_ENC_LE).unwrap();
352 1 : assert_eq!(decoded, SHORT2);
353 :
354 : // with trailing data
355 1 : let decoded = ShortStruct::des_prefix(SHORT2_ENC_LE_TRAILING).unwrap();
356 1 : assert_eq!(decoded, SHORT2);
357 1 : let err = ShortStruct::des(SHORT2_ENC_LE_TRAILING).unwrap_err();
358 1 : assert!(matches!(err, DeserializeError::BadInput));
359 :
360 : // serialize into a `Write` sink.
361 1 : let mut buf = Cursor::new(vec![0xFF; 8]);
362 1 : SHORT1.ser_into(&mut buf).unwrap();
363 1 : assert_eq!(buf.into_inner(), SHORT1_ENC_LE_TRAILING);
364 :
365 : // deserialize from a `Write` sink.
366 1 : let mut buf = Cursor::new(SHORT2_ENC_LE);
367 1 : let decoded = ShortStruct::des_from(&mut buf).unwrap();
368 1 : assert_eq!(decoded, SHORT2);
369 :
370 : // deserialize from a `Write` sink that terminates early.
371 1 : let mut buf = Cursor::new([0u8; 4]);
372 1 : let err = ShortStruct::des_from(&mut buf).unwrap_err();
373 1 : assert!(matches!(err, DeserializeError::Io(_)));
374 1 : }
375 :
376 : #[test]
377 1 : fn be_long() {
378 : use super::BeSer;
379 :
380 1 : assert_eq!(LONG1.serialized_size().unwrap(), 30);
381 :
382 1 : let msg = LONG1;
383 1 :
384 1 : let encoded = msg.ser().unwrap();
385 1 : let expected = hex_literal::hex!(
386 1 : "2A 1000 2000 1234 2345 3456 4567 9876 5432 10FE DCBA 7788 99AA BBCC DDFF 01"
387 1 : );
388 1 : assert_eq!(encoded, expected);
389 :
390 1 : let msg2 = LongMsg::des(&encoded).unwrap();
391 1 : assert_eq!(msg, msg2);
392 1 : }
393 :
394 : #[test]
395 1 : fn le_long() {
396 : use super::LeSer;
397 :
398 1 : assert_eq!(LONG1.serialized_size().unwrap(), 30);
399 :
400 1 : let msg = LONG1;
401 1 :
402 1 : let encoded = msg.ser().unwrap();
403 1 : let expected = hex_literal::hex!(
404 1 : "2A 0020 0010 6745 5634 4523 3412 BADC FE10 3254 7698 FFDD CCBB AA99 8877 01"
405 1 : );
406 1 : assert_eq!(encoded, expected);
407 :
408 1 : let msg2 = LongMsg::des(&encoded).unwrap();
409 1 : assert_eq!(msg, msg2);
410 1 : }
411 : }
|