LCOV - code coverage report
Current view: top level - libs/utils/src - bin_ser.rs (source / functions) Coverage Total Hit
Test: 6df3fc19ec669bcfbbf9aba41d1338898d24eaa0.info Lines: 87.6 % 209 183
Test Date: 2025-03-12 18:28:53 Functions: 43.2 % 271 117

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

Generated by: LCOV version 2.1-beta