LCOV - code coverage report
Current view: top level - libs/utils/src - bin_ser.rs (source / functions) Coverage Total Hit
Test: fabb29a6339542ee130cd1d32b534fafdc0be240.info Lines: 86.7 % 196 170
Test Date: 2024-06-25 13:20:00 Functions: 47.6 % 233 111

            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            4 :     fn from(e: bincode::Error) -> Self {
      37            4 :         match *e {
      38            4 :             bincode::ErrorKind::Io(io_err) => DeserializeError::Io(io_err),
      39            0 :             _ => DeserializeError::BadInput,
      40              :         }
      41            4 :     }
      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     14263526 : pub fn be_coder() -> impl Options {
      76     14263526 :     bincode::DefaultOptions::new()
      77     14263526 :         .with_big_endian()
      78     14263526 :         .with_fixint_encoding()
      79     14263526 : }
      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       688273 : pub fn le_coder() -> impl Options {
      90       688273 :     bincode::DefaultOptions::new()
      91       688273 :         .with_little_endian()
      92       688273 :         .with_fixint_encoding()
      93       688273 : }
      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      5092055 :     fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
     114      5092055 :     where
     115      5092055 :         Self: Serialize,
     116      5092055 :     {
     117      5092055 :         be_coder().serialize_into(w, &self).map_err(|e| e.into())
     118      5092055 :     }
     119              : 
     120              :     /// Serialize into a new heap-allocated buffer
     121      2066738 :     fn ser(&self) -> Result<Vec<u8>, SerializeError>
     122      2066738 :     where
     123      2066738 :         Self: Serialize,
     124      2066738 :     {
     125      2066738 :         be_coder().serialize(&self).map_err(|e| e.into())
     126      2066738 :     }
     127              : 
     128              :     /// Deserialize from the full contents of a byte slice
     129              :     ///
     130              :     /// See also: [`BeSer::des_prefix`]
     131      7103637 :     fn des(buf: &[u8]) -> Result<Self, DeserializeError>
     132      7103637 :     where
     133      7103637 :         Self: DeserializeOwned,
     134      7103637 :     {
     135      7103637 :         be_coder()
     136      7103637 :             .deserialize(buf)
     137      7103637 :             .or(Err(DeserializeError::BadInput))
     138      7103637 :     }
     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         1088 :     fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
     147         1088 :     where
     148         1088 :         Self: DeserializeOwned,
     149         1088 :     {
     150         1088 :         be_coder()
     151         1088 :             .allow_trailing_bytes()
     152         1088 :             .deserialize(buf)
     153         1088 :             .or(Err(DeserializeError::BadInput))
     154         1088 :     }
     155              : 
     156              :     /// Deserialize from a reader
     157            4 :     fn des_from<R: Read>(r: &mut R) -> Result<Self, DeserializeError>
     158            4 :     where
     159            4 :         Self: DeserializeOwned,
     160            4 :     {
     161            4 :         be_coder().deserialize_from(r).map_err(|e| e.into())
     162            4 :     }
     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            4 :     fn serialized_size(&self) -> Result<u64, SerializeError>
     169            4 :     where
     170            4 :         Self: Serialize,
     171            4 :     {
     172            4 :         be_coder().serialized_size(self).map_err(|e| e.into())
     173            4 :     }
     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            6 :     fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
     195            6 :     where
     196            6 :         Self: Serialize,
     197            6 :     {
     198            6 :         le_coder().serialize_into(w, &self).map_err(|e| e.into())
     199            6 :     }
     200              : 
     201              :     /// Serialize into a new heap-allocated buffer
     202        98233 :     fn ser(&self) -> Result<Vec<u8>, SerializeError>
     203        98233 :     where
     204        98233 :         Self: Serialize,
     205        98233 :     {
     206        98233 :         le_coder().serialize(&self).map_err(|e| e.into())
     207        98233 :     }
     208              : 
     209              :     /// Deserialize from the full contents of a byte slice
     210              :     ///
     211              :     /// See also: [`LeSer::des_prefix`]
     212       221140 :     fn des(buf: &[u8]) -> Result<Self, DeserializeError>
     213       221140 :     where
     214       221140 :         Self: DeserializeOwned,
     215       221140 :     {
     216       221140 :         le_coder()
     217       221140 :             .deserialize(buf)
     218       221140 :             .or(Err(DeserializeError::BadInput))
     219       221140 :     }
     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            6 :     fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
     228            6 :     where
     229            6 :         Self: DeserializeOwned,
     230            6 :     {
     231            6 :         le_coder()
     232            6 :             .allow_trailing_bytes()
     233            6 :             .deserialize(buf)
     234            6 :             .or(Err(DeserializeError::BadInput))
     235            6 :     }
     236              : 
     237              :     /// Deserialize from a reader
     238       368884 :     fn des_from<R: Read>(r: &mut R) -> Result<Self, DeserializeError>
     239       368884 :     where
     240       368884 :         Self: DeserializeOwned,
     241       368884 :     {
     242       368884 :         le_coder().deserialize_from(r).map_err(|e| e.into())
     243       368884 :     }
     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            4 :     fn serialized_size(&self) -> Result<u64, SerializeError>
     250            4 :     where
     251            4 :         Self: Serialize,
     252            4 :     {
     253            4 :         le_coder().serialized_size(self).map_err(|e| e.into())
     254            4 :     }
     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           24 :     #[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            4 :     #[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            2 :     fn be_short() {
     310            2 :         use super::BeSer;
     311            2 : 
     312            2 :         assert_eq!(SHORT1.serialized_size().unwrap(), 5);
     313              : 
     314            2 :         let encoded = SHORT1.ser().unwrap();
     315            2 :         assert_eq!(encoded, SHORT1_ENC_BE);
     316              : 
     317            2 :         let decoded = ShortStruct::des(SHORT2_ENC_BE).unwrap();
     318            2 :         assert_eq!(decoded, SHORT2);
     319              : 
     320              :         // with trailing data
     321            2 :         let decoded = ShortStruct::des_prefix(SHORT2_ENC_BE_TRAILING).unwrap();
     322            2 :         assert_eq!(decoded, SHORT2);
     323            2 :         let err = ShortStruct::des(SHORT2_ENC_BE_TRAILING).unwrap_err();
     324            2 :         assert!(matches!(err, DeserializeError::BadInput));
     325              : 
     326              :         // serialize into a `Write` sink.
     327            2 :         let mut buf = Cursor::new(vec![0xFF; 8]);
     328            2 :         SHORT1.ser_into(&mut buf).unwrap();
     329            2 :         assert_eq!(buf.into_inner(), SHORT1_ENC_BE_TRAILING);
     330              : 
     331              :         // deserialize from a `Write` sink.
     332            2 :         let mut buf = Cursor::new(SHORT2_ENC_BE);
     333            2 :         let decoded = ShortStruct::des_from(&mut buf).unwrap();
     334            2 :         assert_eq!(decoded, SHORT2);
     335              : 
     336              :         // deserialize from a `Write` sink that terminates early.
     337            2 :         let mut buf = Cursor::new([0u8; 4]);
     338            2 :         let err = ShortStruct::des_from(&mut buf).unwrap_err();
     339            2 :         assert!(matches!(err, DeserializeError::Io(_)));
     340            2 :     }
     341              : 
     342              :     #[test]
     343            2 :     fn le_short() {
     344            2 :         use super::LeSer;
     345            2 : 
     346            2 :         assert_eq!(SHORT1.serialized_size().unwrap(), 5);
     347              : 
     348            2 :         let encoded = SHORT1.ser().unwrap();
     349            2 :         assert_eq!(encoded, SHORT1_ENC_LE);
     350              : 
     351            2 :         let decoded = ShortStruct::des(SHORT2_ENC_LE).unwrap();
     352            2 :         assert_eq!(decoded, SHORT2);
     353              : 
     354              :         // with trailing data
     355            2 :         let decoded = ShortStruct::des_prefix(SHORT2_ENC_LE_TRAILING).unwrap();
     356            2 :         assert_eq!(decoded, SHORT2);
     357            2 :         let err = ShortStruct::des(SHORT2_ENC_LE_TRAILING).unwrap_err();
     358            2 :         assert!(matches!(err, DeserializeError::BadInput));
     359              : 
     360              :         // serialize into a `Write` sink.
     361            2 :         let mut buf = Cursor::new(vec![0xFF; 8]);
     362            2 :         SHORT1.ser_into(&mut buf).unwrap();
     363            2 :         assert_eq!(buf.into_inner(), SHORT1_ENC_LE_TRAILING);
     364              : 
     365              :         // deserialize from a `Write` sink.
     366            2 :         let mut buf = Cursor::new(SHORT2_ENC_LE);
     367            2 :         let decoded = ShortStruct::des_from(&mut buf).unwrap();
     368            2 :         assert_eq!(decoded, SHORT2);
     369              : 
     370              :         // deserialize from a `Write` sink that terminates early.
     371            2 :         let mut buf = Cursor::new([0u8; 4]);
     372            2 :         let err = ShortStruct::des_from(&mut buf).unwrap_err();
     373            2 :         assert!(matches!(err, DeserializeError::Io(_)));
     374            2 :     }
     375              : 
     376              :     #[test]
     377            2 :     fn be_long() {
     378            2 :         use super::BeSer;
     379            2 : 
     380            2 :         assert_eq!(LONG1.serialized_size().unwrap(), 30);
     381              : 
     382            2 :         let msg = LONG1;
     383            2 : 
     384            2 :         let encoded = msg.ser().unwrap();
     385            2 :         let expected = hex_literal::hex!(
     386            2 :             "2A 1000 2000 1234 2345 3456 4567 9876 5432 10FE DCBA 7788 99AA BBCC DDFF 01"
     387            2 :         );
     388            2 :         assert_eq!(encoded, expected);
     389              : 
     390            2 :         let msg2 = LongMsg::des(&encoded).unwrap();
     391            2 :         assert_eq!(msg, msg2);
     392            2 :     }
     393              : 
     394              :     #[test]
     395            2 :     fn le_long() {
     396            2 :         use super::LeSer;
     397            2 : 
     398            2 :         assert_eq!(LONG1.serialized_size().unwrap(), 30);
     399              : 
     400            2 :         let msg = LONG1;
     401            2 : 
     402            2 :         let encoded = msg.ser().unwrap();
     403            2 :         let expected = hex_literal::hex!(
     404            2 :             "2A 0020 0010 6745 5634 4523 3412 BADC FE10 3254 7698 FFDD CCBB AA99 8877 01"
     405            2 :         );
     406            2 :         assert_eq!(encoded, expected);
     407              : 
     408            2 :         let msg2 = LongMsg::des(&encoded).unwrap();
     409            2 :         assert_eq!(msg, msg2);
     410            2 :     }
     411              : }
        

Generated by: LCOV version 2.1-beta