proc_heim/process/
serde.rs

1#[cfg(any(feature = "json", feature = "message-pack"))]
2pub use inner::{MessageFormat, SerdeError, SerdeUtil};
3
4#[cfg(feature = "message-pack")]
5pub use inner::Encoding;
6
7#[cfg(any(feature = "json", feature = "message-pack"))]
8mod inner {
9    #[cfg(feature = "message-pack")]
10    use base64::prelude::*;
11
12    use std::fmt::Display;
13
14    /// Message data format type.
15    #[derive(Debug, Clone)]
16    #[non_exhaustive]
17    pub enum MessageFormat {
18        /// `JSON` format.
19        #[cfg(feature = "json")]
20        Json,
21        /// `MessagePack` binary format.
22        /// `MessagePack` serialization can produce `null bytes`, which will break a communication via pipes.
23        /// Therefore the messages should be additionally encoded.
24        #[cfg(feature = "message-pack")]
25        MessagePack(Encoding),
26    }
27
28    /// Enum describing message encoding.
29    #[cfg(feature = "message-pack")]
30    #[derive(Debug, Clone)]
31    pub enum Encoding {
32        /// `Base64` encoding.
33        Base64,
34        /// `Hexadecimal` encoding.
35        Hex,
36    }
37
38    impl Display for MessageFormat {
39        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40            match self {
41                #[cfg(feature = "json")]
42                MessageFormat::Json => f.write_str("Json"),
43                #[cfg(feature = "message-pack")]
44                MessageFormat::MessagePack(_encoding) => f.write_str("MessagePack"),
45            }
46        }
47    }
48
49    #[cfg(feature = "message-pack")]
50    impl Display for Encoding {
51        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52            match self {
53                Encoding::Base64 => f.write_str("Base64"),
54                Encoding::Hex => f.write_str("Hex"),
55            }
56        }
57    }
58
59    /// Error type representing message (de)serialization failure.
60    #[derive(thiserror::Error, Debug)]
61    pub enum SerdeError {
62        /// Cannot serialize data with provided format (first value). Second value is a more detailed error message.
63        #[error("Cannot serialize data with format: {0}. Cause: {1}")]
64        SerializationFailure(MessageFormat, String),
65        /// Cannot deserialize data with provided format (first value). Second value is a more detailed error message.
66        #[error("Cannot deserialize data with format: {0}. Cause: {1}")]
67        DeserializationFailure(MessageFormat, String),
68        /// Cannot decode data with provided encoding format (first value). Second value is a more detailed error message.
69        #[error("Cannot decode data with {0}. Cause: {1}")]
70        #[cfg(feature = "message-pack")]
71        DecodingFailure(Encoding, String),
72    }
73
74    pub struct SerdeUtil {}
75
76    impl SerdeUtil {
77        pub fn serialize<T: serde::Serialize>(
78            data: &T,
79            format: &MessageFormat,
80        ) -> Result<Vec<u8>, SerdeError> {
81            let bytes = match format {
82                #[cfg(feature = "json")]
83                MessageFormat::Json => serde_json::to_vec(&data).map_err(|err| {
84                    SerdeError::SerializationFailure(format.clone(), err.to_string())
85                }),
86                #[cfg(feature = "message-pack")]
87                MessageFormat::MessagePack(ref encoding) => {
88                    let bytes = rmp_serde::to_vec(&data).map_err(|err| {
89                        SerdeError::SerializationFailure(format.clone(), err.to_string())
90                    })?;
91                    Ok(match encoding {
92                        Encoding::Base64 => BASE64_STANDARD.encode(bytes),
93                        Encoding::Hex => hex::encode(bytes),
94                    }
95                    .into_bytes())
96                }
97            }?;
98            Ok(bytes)
99        }
100
101        pub fn deserialize<T: for<'de> serde::Deserialize<'de>>(
102            bytes: &[u8],
103            format: &MessageFormat,
104        ) -> Result<T, SerdeError> {
105            match format {
106                #[cfg(feature = "json")]
107                MessageFormat::Json => serde_json::from_slice(bytes).map_err(|err| {
108                    SerdeError::DeserializationFailure(format.clone(), err.to_string())
109                }),
110                #[cfg(feature = "message-pack")]
111                MessageFormat::MessagePack(ref encoding) => {
112                    let decoded_bytes = match encoding {
113                        Encoding::Base64 => {
114                            BASE64_STANDARD.decode(bytes).map_err(|err| err.to_string())
115                        }
116                        Encoding::Hex => hex::decode(bytes).map_err(|err| err.to_string()),
117                    }
118                    .map_err(|err_source_msg| {
119                        SerdeError::DecodingFailure(encoding.clone(), err_source_msg)
120                    })?;
121                    rmp_serde::from_slice(&decoded_bytes).map_err(|err| {
122                        SerdeError::DeserializationFailure(format.clone(), err.to_string())
123                    })
124                }
125            }
126        }
127    }
128}