nautilus_core/
serialization.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Common serialization traits and functions.
17
18use bytes::Bytes;
19use serde::{
20    de::{Unexpected, Visitor},
21    Deserializer,
22};
23
24struct BoolVisitor;
25use serde::{Deserialize, Serialize};
26
27/// Represents types which are serializable for JSON and `MsgPack` specifications.
28pub trait Serializable: Serialize + for<'de> Deserialize<'de> {
29    /// Deserialize an object from JSON encoded bytes.
30    ///
31    /// # Errors
32    ///
33    /// Returns serialization errors.
34    fn from_json_bytes(data: &[u8]) -> Result<Self, serde_json::Error> {
35        serde_json::from_slice(data)
36    }
37
38    /// Deserialize an object from `MsgPack` encoded bytes.
39    ///
40    /// # Errors
41    ///
42    /// Returns serialization errors.
43    fn from_msgpack_bytes(data: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
44        rmp_serde::from_slice(data)
45    }
46
47    /// Serialize an object to JSON encoded bytes.
48    ///
49    /// # Errors
50    ///
51    /// Returns serialization errors.
52    fn as_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
53        serde_json::to_vec(self).map(Bytes::from)
54    }
55
56    /// Serialize an object to `MsgPack` encoded bytes.
57    ///
58    /// # Errors
59    ///
60    /// Returns serialization errors.
61    fn as_msgpack_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
62        rmp_serde::to_vec_named(self).map(Bytes::from)
63    }
64}
65
66impl Visitor<'_> for BoolVisitor {
67    type Value = u8;
68
69    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        formatter.write_str("a boolean as u8")
71    }
72
73    fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
74    where
75        E: serde::de::Error,
76    {
77        Ok(u8::from(value))
78    }
79
80    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
81    where
82        E: serde::de::Error,
83    {
84        if value > u64::from(u8::MAX) {
85            Err(E::invalid_value(Unexpected::Unsigned(value), &self))
86        } else {
87            Ok(value as u8)
88        }
89    }
90}
91
92/// Deserialize the boolean value as a `u8`.
93///
94/// # Errors
95///
96/// Returns serialization errors.
97pub fn from_bool_as_u8<'de, D>(deserializer: D) -> Result<u8, D::Error>
98where
99    D: Deserializer<'de>,
100{
101    deserializer.deserialize_any(BoolVisitor)
102}
103
104////////////////////////////////////////////////////////////////////////////////
105// Tests
106////////////////////////////////////////////////////////////////////////////////
107#[cfg(test)]
108mod tests {
109    use rstest::*;
110    use serde::Deserialize;
111
112    use super::from_bool_as_u8;
113
114    #[derive(Deserialize)]
115    pub struct TestStruct {
116        #[serde(deserialize_with = "from_bool_as_u8")]
117        pub value: u8,
118    }
119
120    #[rstest]
121    #[case(r#"{"value": true}"#, 1)]
122    #[case(r#"{"value": false}"#, 0)]
123    fn test_deserialize_bool_as_u8_with_boolean(#[case] json_str: &str, #[case] expected: u8) {
124        let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
125        assert_eq!(test_struct.value, expected);
126    }
127
128    #[rstest]
129    #[case(r#"{"value": 1}"#, 1)]
130    #[case(r#"{"value": 0}"#, 0)]
131    fn test_deserialize_bool_as_u8_with_u64(#[case] json_str: &str, #[case] expected: u8) {
132        let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
133        assert_eq!(test_struct.value, expected);
134    }
135}