flagsmith_flag_engine/types/
mod.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2
3use serde::de;
4use std::fmt;
5
6#[derive(Clone, Debug, PartialEq)]
7pub enum FlagsmithValueType {
8    String,
9    Bool,
10    Integer,
11    Float,
12    None,
13}
14
15#[derive(Clone, Debug, PartialEq)]
16pub struct FlagsmithValue {
17    pub value_type: FlagsmithValueType,
18    pub value: String,
19}
20
21impl Default for FlagsmithValue {
22    fn default() -> Self {
23        FlagsmithValue {
24            value_type: FlagsmithValueType::None,
25            value: "".to_string(),
26        }
27    }
28}
29
30impl Serialize for FlagsmithValue {
31    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32    where
33        S: Serializer,
34    {
35        match self.value_type {
36            FlagsmithValueType::Bool => serializer.serialize_bool(self.value.parse().unwrap()),
37            FlagsmithValueType::Integer => serializer.serialize_i64(self.value.parse().unwrap()),
38            FlagsmithValueType::String => serializer.serialize_str(self.value.as_str()),
39            FlagsmithValueType::None => serializer.serialize_none(),
40            FlagsmithValueType::Float => serializer.serialize_f64(self.value.parse().unwrap()),
41        }
42    }
43}
44
45struct FlagsmithValueVisitor;
46impl<'de> de::Visitor<'de> for FlagsmithValueVisitor {
47    type Value = FlagsmithValue;
48
49    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
50        formatter.write_str("an integer, a string, a float, a None or boolean")
51    }
52
53    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
54    where
55        E: de::Error,
56    {
57        Ok(FlagsmithValue {
58            value: v.to_string(),
59            value_type: FlagsmithValueType::Integer,
60        })
61    }
62    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
63    where
64        E: de::Error,
65    {
66        Ok(FlagsmithValue {
67            value: v.to_string(),
68            value_type: FlagsmithValueType::Float,
69        })
70    }
71
72    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
73    where
74        E: de::Error,
75    {
76        Ok(FlagsmithValue {
77            value: v.to_string(),
78            value_type: FlagsmithValueType::Integer,
79        })
80    }
81    fn visit_unit<E>(self) -> Result<Self::Value, E>
82    where
83        E: de::Error,
84    {
85        Ok(FlagsmithValue {
86            value: "".to_string(),
87            value_type: FlagsmithValueType::None,
88        })
89    }
90    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
91    where
92        E: de::Error,
93    {
94        Ok(FlagsmithValue {
95            value: v.to_string(),
96            value_type: FlagsmithValueType::String,
97        })
98    }
99    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
100    where
101        E: de::Error,
102    {
103        Ok(FlagsmithValue {
104            value: v.to_string(),
105            value_type: FlagsmithValueType::Bool,
106        })
107    }
108}
109impl<'de> Deserialize<'de> for FlagsmithValue {
110    fn deserialize<D>(deserializer: D) -> Result<FlagsmithValue, D::Error>
111    where
112        D: Deserializer<'de>,
113    {
114        deserializer.deserialize_any(FlagsmithValueVisitor)
115    }
116}
117#[cfg(test)]
118mod tests {
119
120    use super::*;
121    use rstest::*;
122
123    #[rstest]
124    #[case(serde_json::json!(10), FlagsmithValueType::Integer)]
125    #[case(serde_json::json!(-10), FlagsmithValueType::Integer)]
126    #[case(serde_json::json!(10.1), FlagsmithValueType::Float)]
127    #[case(serde_json::json!(-10.1), FlagsmithValueType::Float)]
128    #[case(serde_json::json!(true), FlagsmithValueType::Bool)]
129    #[case(serde_json::json!(false), FlagsmithValueType::Bool)]
130    #[case(serde_json::json!(null), FlagsmithValueType::None)]
131    #[case(serde_json::json!("string"), FlagsmithValueType::String)]
132    #[case(serde_json::json!("10"), FlagsmithValueType::String)]
133    #[case(serde_json::json!("true"), FlagsmithValueType::String)]
134    #[case(serde_json::json!("10.1"), FlagsmithValueType::String)]
135    fn serialize_deserialize_flagsmith_value(
136        #[case] value_as_json: serde_json::Value,
137        #[case] expected_value_type: FlagsmithValueType,
138    ) {
139        // Convert json value to FlagsmithValue
140        let flagsmith_value: FlagsmithValue =
141            serde_json::from_value(value_as_json.clone()).unwrap();
142        assert_eq!(flagsmith_value.value_type, expected_value_type);
143
144        // Now let's test converting Flagsmith value to json value
145        let serialized_value = serde_json::to_value(flagsmith_value).unwrap();
146        assert_eq!(serialized_value, value_as_json);
147    }
148}