vmm/cpu_config/
templates_serde.rs

1// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fmt::Debug;
5
6use serde::de::Error as SerdeError;
7use serde::{Deserialize, Deserializer, Serializer};
8
9/// Serializes number to hex
10pub fn serialize_to_hex_str<S, N>(number: &N, serializer: S) -> Result<S::Ok, S::Error>
11where
12    S: Serializer,
13    N: std::fmt::LowerHex + Debug,
14{
15    serializer.serialize_str(format!("{:#x}", number).as_str())
16}
17
18macro_rules! deserialize_from_str {
19    ($name:ident, $type:tt) => {
20        /// Deserializes number from string.
21        /// Number can be in binary, hex or dec formats.
22        pub fn $name<'de, D>(deserializer: D) -> Result<$type, D::Error>
23        where
24            D: Deserializer<'de>,
25        {
26            let number_str = String::deserialize(deserializer)?;
27            let deserialized_number = if let Some(s) = number_str.strip_prefix("0b") {
28                $type::from_str_radix(s, 2)
29            } else if let Some(s) = number_str.strip_prefix("0x") {
30                $type::from_str_radix(s, 16)
31            } else {
32                return Err(D::Error::custom(format!(
33                    "No supported number system prefix found in value [{}]. Make sure to prefix \
34                     the number with '0x' for hexadecimal numbers or '0b' for binary numbers.",
35                    number_str,
36                )));
37            }
38            .map_err(|err| {
39                D::Error::custom(format!(
40                    "Failed to parse string [{}] as a number for CPU template - {:?}",
41                    number_str, err
42                ))
43            })?;
44            Ok(deserialized_number)
45        }
46    };
47}
48
49deserialize_from_str!(deserialize_from_str_u32, u32);
50deserialize_from_str!(deserialize_from_str_u64, u64);
51
52#[cfg(test)]
53mod tests {
54    use serde::de::IntoDeserializer;
55    use serde::de::value::{Error, StrDeserializer};
56
57    use super::*;
58
59    #[test]
60    fn test_deserialize_from_str() {
61        let valid_string = "0b1000101";
62        let deserializer: StrDeserializer<Error> = valid_string.into_deserializer();
63        let valid_value = deserialize_from_str_u32(deserializer);
64        assert_eq!(valid_value.unwrap(), 69);
65
66        let valid_string = "0x0045";
67        let deserializer: StrDeserializer<Error> = valid_string.into_deserializer();
68        let valid_value = deserialize_from_str_u32(deserializer);
69        assert_eq!(valid_value.unwrap(), 69);
70
71        let invalid_string = "xϽ69";
72        let deserializer: StrDeserializer<Error> = invalid_string.into_deserializer();
73        let invalid_value = deserialize_from_str_u32(deserializer);
74        invalid_value.unwrap_err();
75
76        let invalid_string = "69";
77        let deserializer: StrDeserializer<Error> = invalid_string.into_deserializer();
78        let invalid_value = deserialize_from_str_u32(deserializer);
79        invalid_value.unwrap_err();
80    }
81}