1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::{Decoder, Encoder};
use thiserror::Error;

/// A binary codec that uses rust own binary encoding functions to encode and decode data.
/// This can be used if you want to encode only primitives and don't want to rely on third party
/// crates like `bincode` or `rmp-serde`. If you have more complex data check out
/// [`BincodeSerdeCodec`] or [`MsgpackSerdeCodec`].
pub struct FromToBytesCodec;

#[derive(Error, Debug)]
pub enum FromToBytesCodecError {
    #[error("failed to convert byte slice to byte array")]
    InvalidByteSlice(#[from] std::array::TryFromSliceError),

    #[error("failed to convert byte array to string")]
    InvalidString(#[from] std::string::FromUtf8Error),
}

macro_rules! impl_bin_codec_for_number {
    ($num:ty) => {
        impl Encoder<$num> for FromToBytesCodec {
            type Error = ();
            type Encoded = Vec<u8>;

            fn encode(val: &$num) -> Result<Self::Encoded, Self::Error> {
                Ok(val.to_be_bytes().to_vec())
            }
        }

        impl Decoder<$num> for FromToBytesCodec {
            type Error = FromToBytesCodecError;
            type Encoded = [u8];

            fn decode(val: &Self::Encoded) -> Result<$num, Self::Error> {
                Ok(<$num>::from_be_bytes(val.try_into()?))
            }
        }
    };
}

impl_bin_codec_for_number!(i8);
impl_bin_codec_for_number!(u8);

impl_bin_codec_for_number!(i16);
impl_bin_codec_for_number!(u16);

impl_bin_codec_for_number!(i32);
impl_bin_codec_for_number!(u32);

impl_bin_codec_for_number!(i64);
impl_bin_codec_for_number!(u64);

impl_bin_codec_for_number!(i128);
impl_bin_codec_for_number!(u128);

impl_bin_codec_for_number!(isize);
impl_bin_codec_for_number!(usize);

impl_bin_codec_for_number!(f32);
impl_bin_codec_for_number!(f64);

impl Encoder<bool> for FromToBytesCodec {
    type Error = ();
    type Encoded = Vec<u8>;

    fn encode(val: &bool) -> Result<Self::Encoded, Self::Error> {
        let num: u8 = if *val { 1 } else { 0 };
        Self::encode(&num)
    }
}

impl Decoder<bool> for FromToBytesCodec {
    type Error = FromToBytesCodecError;
    type Encoded = [u8];

    fn decode(val: &Self::Encoded) -> Result<bool, Self::Error> {
        let num: u8 = Self::decode(val)?;
        Ok(num != 0)
    }
}

impl Encoder<String> for FromToBytesCodec {
    type Error = ();
    type Encoded = Vec<u8>;

    fn encode(val: &String) -> Result<Self::Encoded, Self::Error> {
        Ok(val.as_bytes().to_vec())
    }
}

impl Decoder<String> for FromToBytesCodec {
    type Error = FromToBytesCodecError;
    type Encoded = [u8];

    fn decode(val: &Self::Encoded) -> Result<String, Self::Error> {
        Ok(String::from_utf8(val.to_vec())?)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_fromtobytes_codec() {
        let t = 50;

        let enc: Vec<u8> = FromToBytesCodec::encode(&t).unwrap();
        let dec: i32 = FromToBytesCodec::decode(enc.as_slice()).unwrap();
        assert_eq!(dec, t);
    }
}