LCOV - differential code coverage report
Current view: top level - libs/utils/src - bin_ser.rs (source / functions) Coverage Total Hit UBC CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 87.0 % 200 174 26 174
Current Date: 2023-10-19 02:04:12 Functions: 51.9 % 241 125 116 125
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  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 UBC           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 CBC           2 :     fn from(e: bincode::Error) -> Self {
      37               2 :         match *e {
      38               2 :             bincode::ErrorKind::Io(io_err) => DeserializeError::Io(io_err),
      39 UBC           0 :             _ => DeserializeError::BadInput,
      40                 :         }
      41 CBC           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 UBC           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 CBC   358574418 : pub fn be_coder() -> impl Options {
      76       358574418 :     bincode::DefaultOptions::new()
      77       358574418 :         .with_big_endian()
      78       358574418 :         .with_fixint_encoding()
      79       358574418 : }
      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       243495581 : pub fn le_coder() -> impl Options {
      90       243495581 :     bincode::DefaultOptions::new()
      91       243495581 :         .with_little_endian()
      92       243495581 :         .with_fixint_encoding()
      93       243495581 : }
      94                 : 
      95                 : /// Binary serialize/deserialize helper functions (Big Endian)
      96                 : ///
      97                 : pub trait BeSer {
      98                 :     /// Serialize into a byte slice
      99 UBC           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 CBC    81644541 :     fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
     114        81644541 :     where
     115        81644541 :         Self: Serialize,
     116        81644541 :     {
     117        81644541 :         be_coder().serialize_into(w, &self).map_err(|e| e.into())
     118        81644541 :     }
     119                 : 
     120                 :     /// Serialize into a new heap-allocated buffer
     121        30199594 :     fn ser(&self) -> Result<Vec<u8>, SerializeError>
     122        30199594 :     where
     123        30199594 :         Self: Serialize,
     124        30199594 :     {
     125        30199594 :         be_coder().serialize(&self).map_err(|e| e.into())
     126        30199594 :     }
     127                 : 
     128                 :     /// Deserialize from the full contents of a byte slice
     129                 :     ///
     130                 :     /// See also: [`BeSer::des_prefix`]
     131       246710897 :     fn des(buf: &[u8]) -> Result<Self, DeserializeError>
     132       246710897 :     where
     133       246710897 :         Self: DeserializeOwned,
     134       246710897 :     {
     135       246710897 :         be_coder()
     136       246710897 :             .deserialize(buf)
     137       246710897 :             .or(Err(DeserializeError::BadInput))
     138       246710897 :     }
     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           14810 :     fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
     147           14810 :     where
     148           14810 :         Self: DeserializeOwned,
     149           14810 :     {
     150           14810 :         be_coder()
     151           14810 :             .allow_trailing_bytes()
     152           14810 :             .deserialize(buf)
     153           14810 :             .or(Err(DeserializeError::BadInput))
     154           14810 :     }
     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               2 :     fn serialized_size(&self) -> Result<u64, SerializeError>
     169               2 :     where
     170               2 :         Self: Serialize,
     171               2 :     {
     172               2 :         be_coder().serialized_size(self).map_err(|e| e.into())
     173               2 :     }
     174                 : }
     175                 : 
     176                 : /// Binary serialize/deserialize helper functions (Little Endian)
     177                 : ///
     178                 : pub trait LeSer {
     179                 :     /// Serialize into a byte slice
     180 UBC           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 CBC        5419 :     fn ser_into<W: Write>(&self, w: &mut W) -> Result<(), SerializeError>
     195            5419 :     where
     196            5419 :         Self: Serialize,
     197            5419 :     {
     198            5419 :         le_coder().serialize_into(w, &self).map_err(|e| e.into())
     199            5419 :     }
     200                 : 
     201                 :     /// Serialize into a new heap-allocated buffer
     202           30556 :     fn ser(&self) -> Result<Vec<u8>, SerializeError>
     203           30556 :     where
     204           30556 :         Self: Serialize,
     205           30556 :     {
     206           30556 :         le_coder().serialize(&self).map_err(|e| e.into())
     207           30556 :     }
     208                 : 
     209                 :     /// Deserialize from the full contents of a byte slice
     210                 :     ///
     211                 :     /// See also: [`LeSer::des_prefix`]
     212       168853976 :     fn des(buf: &[u8]) -> Result<Self, DeserializeError>
     213       168853976 :     where
     214       168853976 :         Self: DeserializeOwned,
     215       168853976 :     {
     216       168853976 :         le_coder()
     217       168853976 :             .deserialize(buf)
     218       168853976 :             .or(Err(DeserializeError::BadInput))
     219       168853976 :     }
     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            1791 :     fn des_prefix(buf: &[u8]) -> Result<Self, DeserializeError>
     228            1791 :     where
     229            1791 :         Self: DeserializeOwned,
     230            1791 :     {
     231            1791 :         le_coder()
     232            1791 :             .allow_trailing_bytes()
     233            1791 :             .deserialize(buf)
     234            1791 :             .or(Err(DeserializeError::BadInput))
     235            1791 :     }
     236                 : 
     237                 :     /// Deserialize from a reader
     238        74603069 :     fn des_from<R: Read>(r: &mut R) -> Result<Self, DeserializeError>
     239        74603069 :     where
     240        74603069 :         Self: DeserializeOwned,
     241        74603069 :     {
     242        74603069 :         le_coder().deserialize_from(r).map_err(|e| e.into())
     243        74603069 :     }
     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               6 :     #[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               1 :     #[test]
     309               1 :     fn be_short() {
     310               1 :         use super::BeSer;
     311               1 : 
     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               1 :     #[test]
     343               1 :     fn le_short() {
     344               1 :         use super::LeSer;
     345               1 : 
     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               1 :     #[test]
     377               1 :     fn be_long() {
     378               1 :         use super::BeSer;
     379               1 : 
     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               1 :     #[test]
     395               1 :     fn le_long() {
     396               1 :         use super::LeSer;
     397               1 : 
     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                 : }
        

Generated by: LCOV version 2.1-beta