proc_heim/process/
serde.rs

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#[cfg(any(feature = "json", feature = "message-pack"))]
pub use inner::{MessageFormat, SerdeError, SerdeUtil};

#[cfg(feature = "message-pack")]
pub use inner::Encoding;

#[cfg(any(feature = "json", feature = "message-pack"))]
mod inner {
    #[cfg(feature = "message-pack")]
    use base64::prelude::*;

    use std::fmt::Display;

    /// Message data format type.
    #[derive(Debug, Clone)]
    #[non_exhaustive]
    pub enum MessageFormat {
        /// `JSON` format.
        #[cfg(feature = "json")]
        Json,
        /// `MessagePack` binary format.
        /// `MessagePack` serialization can produce `null bytes`, which will break a communication via pipes.
        /// Therefore the messages should be additionally encoded.
        #[cfg(feature = "message-pack")]
        MessagePack(Encoding),
    }

    /// Enum describing message encoding.
    #[cfg(feature = "message-pack")]
    #[derive(Debug, Clone)]
    pub enum Encoding {
        /// `Base64` encoding.
        Base64,
        /// `Hexadecimal` encoding.
        Hex,
    }

    impl Display for MessageFormat {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self {
                #[cfg(feature = "json")]
                MessageFormat::Json => f.write_str("Json"),
                #[cfg(feature = "message-pack")]
                MessageFormat::MessagePack(_encoding) => f.write_str("MessagePack"),
            }
        }
    }

    #[cfg(feature = "message-pack")]
    impl Display for Encoding {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self {
                Encoding::Base64 => f.write_str("Base64"),
                Encoding::Hex => f.write_str("Hex"),
            }
        }
    }

    /// Error type representing message (de)serialization failure.
    #[derive(thiserror::Error, Debug)]
    pub enum SerdeError {
        /// Cannot serialize data with provided format (first value). Second value is a more detailed error message.
        #[error("Cannot serialize data with format: {0}. Cause: {1}")]
        SerializationFailure(MessageFormat, String),
        /// Cannot deserialize data with provided format (first value). Second value is a more detailed error message.
        #[error("Cannot deserialize data with format: {0}. Cause: {1}")]
        DeserializationFailure(MessageFormat, String),
        /// Cannot decode data with provided encoding format (first value). Second value is a more detailed error message.
        #[error("Cannot decode data with {0}. Cause: {1}")]
        #[cfg(feature = "message-pack")]
        DecodingFailure(Encoding, String),
    }

    pub struct SerdeUtil {}

    impl SerdeUtil {
        pub fn serialize<T: serde::Serialize>(
            data: &T,
            format: &MessageFormat,
        ) -> Result<Vec<u8>, SerdeError> {
            let bytes = match format {
                #[cfg(feature = "json")]
                MessageFormat::Json => serde_json::to_vec(&data).map_err(|err| {
                    SerdeError::SerializationFailure(format.clone(), err.to_string())
                }),
                #[cfg(feature = "message-pack")]
                MessageFormat::MessagePack(ref encoding) => {
                    let bytes = rmp_serde::to_vec(&data).map_err(|err| {
                        SerdeError::SerializationFailure(format.clone(), err.to_string())
                    })?;
                    Ok(match encoding {
                        Encoding::Base64 => BASE64_STANDARD.encode(bytes),
                        Encoding::Hex => hex::encode(bytes),
                    }
                    .into_bytes())
                }
            }?;
            Ok(bytes)
        }

        pub fn deserialize<T: for<'de> serde::Deserialize<'de>>(
            bytes: &[u8],
            format: &MessageFormat,
        ) -> Result<T, SerdeError> {
            match format {
                #[cfg(feature = "json")]
                MessageFormat::Json => serde_json::from_slice(bytes).map_err(|err| {
                    SerdeError::DeserializationFailure(format.clone(), err.to_string())
                }),
                #[cfg(feature = "message-pack")]
                MessageFormat::MessagePack(ref encoding) => {
                    let decoded_bytes = match encoding {
                        Encoding::Base64 => {
                            BASE64_STANDARD.decode(bytes).map_err(|err| err.to_string())
                        }
                        Encoding::Hex => hex::decode(bytes).map_err(|err| err.to_string()),
                    }
                    .map_err(|err_source_msg| {
                        SerdeError::DecodingFailure(encoding.clone(), err_source_msg)
                    })?;
                    rmp_serde::from_slice(&decoded_bytes).map_err(|err| {
                        SerdeError::DeserializationFailure(format.clone(), err.to_string())
                    })
                }
            }
        }
    }
}