trs_data_value/
lib.rs

1use std::collections::HashMap;
2
3#[cfg(feature = "python")]
4mod python;
5
6mod basic_operation;
7mod deserializer;
8mod extract;
9mod from;
10mod operators;
11mod utils;
12pub use smartstring::alias::String;
13
14/// Represents a generic value (something like serde_json::Value) which can be
15/// converted from/to python and provides other benefits.
16#[derive(Debug, Clone, Default)]
17pub enum DataValue {
18    String(String),
19    Bytes(Vec<u8>),
20    U8(u8),
21    Bool(bool),
22    I32(i32),
23    U32(u32),
24    I64(i64),
25    U64(u64),
26    I128(i128),
27    U128(u128),
28    F32(f32),
29    F64(f64),
30    Map(HashMap<String, DataValue>),
31    Vec(Vec<DataValue>),
32    EnumNumber(i32),
33    #[default]
34    Null,
35}
36
37impl std::fmt::Display for DataValue {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        use DataValue::*;
40        match self {
41            Bool(i) => write!(f, "{}", i),
42            U32(i) => write!(f, "{}", i),
43            I32(i) => write!(f, "{}", i),
44            U8(i) => write!(f, "{}", i),
45            U64(i) => write!(f, "{}", i),
46            I64(i) => write!(f, "{}", i),
47            F32(i) => write!(f, "{}", i),
48            F64(i) => write!(f, "{}", i),
49            U128(i) => write!(f, "{}", i),
50            I128(i) => write!(f, "{}", i),
51            String(i) => write!(f, "{}", i),
52            Bytes(i) => write!(f, "{}", std::string::String::from_utf8_lossy(i)),
53            Null => write!(f, "null",),
54            Vec(i) => write!(f, "{:?}", i),
55            EnumNumber(i) => write!(f, "{:?}", i),
56            Map(i) => write!(f, "{:?}", i),
57        }
58    }
59}
60impl DataValue {
61    pub fn extract<T>(&self) -> T
62    where
63        T: Extract,
64    {
65        T::extract(self)
66    }
67
68    pub fn extract_bytes(&self) -> Vec<u8> {
69        match self {
70            DataValue::Bytes(i) => i.to_vec(),
71            _ => vec![],
72        }
73    }
74}
75
76pub trait Extract {
77    fn extract(v: &DataValue) -> Self;
78}
79
80impl DataValue {
81    pub fn contains(&self, other: &str) -> bool {
82        match self {
83            DataValue::Vec(v) => v.iter().any(|x| x.contains(other)),
84            DataValue::Map(v) => v.keys().any(|x| x.contains(other)),
85            DataValue::String(v) => v.contains(other),
86            _ => false,
87        }
88    }
89}
90
91pub fn convert<D: Extract>(data: &[DataValue]) -> Vec<D> {
92    let mut result = Vec::with_capacity(data.len());
93    for d in data {
94        result.push(D::extract(d));
95    }
96    result
97}
98
99#[macro_export]
100macro_rules! datavalue {
101
102     // case vec![1, 2, 3]
103    ($(vec![$($value:expr),*]),*) => {
104        $crate::datavalue!($([$($value),*]),*)
105    };
106
107    // case vec![1, 2, 3]
108    ($([$($value:expr),*]),*) => {
109        {
110        $(
111            let mut _vec = Vec::new();
112            $(
113                _vec.push($crate::DataValue::from($value));
114            )*
115            $crate::DataValue::Vec(_vec)
116        )*
117        }
118    };
119    // case { "a" => 1, }
120    ($($key:expr => $value:expr,)+) => { $crate::datavalue!($($key => $value),+) };
121    // case { "a" => vec![1, 2, 3] }
122    ($($key:expr => vec![$($value:expr),*]),*) => {
123        $crate::datavalue!($($key => [$($value),*]),*)
124    };
125    // case { "a" => [1, 2, 3] }
126    ($($key:expr => [$($value:expr),*]),*) => {
127        {
128            let mut _map = ::std::collections::HashMap::new();
129            $(
130                let mut _arr = Vec::new();
131                $(
132                    _arr.push($value.into());
133                )*
134                _map.insert($key.into(), $crate::DataValue::Vec(_arr));
135            )*
136            $crate::DataValue::Map(_map)
137        }
138    };
139    // case { "a" => 1 }
140    ($($key:expr => $value:expr),*) => {
141        {
142            let mut _map = ::std::collections::HashMap::new();
143            $(
144                _map.insert($key.into(), $value.into());
145            )*
146            $crate::DataValue::Map(_map)
147        }
148    };
149    // case simple value
150    ($value:expr) => {
151        $crate::DataValue::from($value)
152    };
153}
154#[cfg(test)]
155mod test {
156    use std::fmt::Debug;
157
158    use super::*;
159    use rstest::*;
160
161    #[test]
162    fn from_json_object_to_datavalue() {
163        let value = DataValue::from(&serde_json::json!(12));
164        assert_eq!(value, DataValue::I64(12));
165
166        let value = DataValue::from(&serde_json::json!(12.0));
167        assert_eq!(value, DataValue::F64(12.0));
168
169        let value = DataValue::from(&serde_json::json!("12"));
170        assert_eq!(value, DataValue::String("12".into()));
171
172        let value = DataValue::from(&serde_json::json!(true));
173        assert_eq!(value, DataValue::Bool(true));
174
175        let value = DataValue::from(&serde_json::json!(false));
176        assert_eq!(value, DataValue::Bool(false));
177
178        let value = DataValue::from(&serde_json::json!(null));
179        assert_eq!(value, DataValue::Null);
180    }
181
182    #[test]
183    fn from_native_to_datavalue() {
184        let value = DataValue::from(12u32);
185        assert_eq!(value, DataValue::U32(12));
186
187        let value = DataValue::from(12.0f64);
188        assert_eq!(value, DataValue::F64(12.0));
189
190        let value = DataValue::from("12");
191        assert_eq!(value, DataValue::String("12".into()));
192
193        let value = DataValue::from(true);
194        assert_eq!(value, DataValue::Bool(true));
195
196        let value = DataValue::from(false);
197        assert_eq!(value, DataValue::Bool(false));
198
199        let value = DataValue::from(());
200        assert_eq!(value, DataValue::Null);
201    }
202
203    #[rstest]
204    #[case(DataValue::U32(12), 12u32)]
205    #[case(DataValue::I32(12), 12i32)]
206    #[case(DataValue::U8(12), 12u8)]
207    #[case(DataValue::U64(12), 12u64)]
208    #[case(DataValue::I64(12), 12i64)]
209    #[case(DataValue::F32(12.0), 12f32)]
210    #[case(DataValue::F64(12.0), 12f64)]
211    #[case(DataValue::U128(12), 12u128)]
212    #[case(DataValue::I128(12), 12i128)]
213    #[case(DataValue::String("12".into()), "12".to_string())]
214    #[case(DataValue::Bool(true), true)]
215    #[case(DataValue::Bool(false), false)]
216    fn as_data_value_test<T: PartialEq + std::fmt::Debug + Into<DataValue> + Extract>(
217        #[case] value: DataValue,
218        #[case] expected: T,
219    ) {
220        assert_eq!(value.extract::<T>(), expected);
221        assert_eq!(value, expected.into());
222    }
223
224    #[rstest]
225    #[case(DataValue::Bytes("12".as_bytes().to_vec()), "12".as_bytes().to_vec())]
226    fn as_data_value_test_bytes(#[case] value: DataValue, #[case] expected: Vec<u8>) {
227        assert_eq!(value.extract_bytes(), expected);
228    }
229
230    #[rstest]
231    #[case(DataValue::U32(12), DataValue::U32(12), true)]
232    #[case(DataValue::I32(12), DataValue::I32(12), true)]
233    #[case(DataValue::U8(12), DataValue::U8(12), true)]
234    #[case(DataValue::U64(12), DataValue::U64(12), true)]
235    #[case(DataValue::I64(12), DataValue::I64(12), true)]
236    #[case(DataValue::F32(12.0), DataValue::F32(12.0), true)]
237    #[case(DataValue::F64(12.0), DataValue::F64(12.0), true)]
238    #[case(DataValue::U128(12), DataValue::U128(12), true)]
239    #[case(DataValue::I128(12), DataValue::I128(12), true)]
240    #[case(DataValue::String("12".into()), DataValue::String("12".into()), true)]
241    #[case(DataValue::Bytes("12".as_bytes().to_vec()), DataValue::Bytes("12".as_bytes().to_vec()), true)]
242    #[case(DataValue::Bool(true), DataValue::Bool(true), true)]
243    #[case(DataValue::Bool(false), DataValue::Bool(false), true)]
244    fn eq_test(#[case] value: DataValue, #[case] other: DataValue, #[case] expected: bool) {
245        assert_eq!(value == other, expected);
246        print!("{} == {} = {}", value, other, expected);
247    }
248
249    #[rstest]
250    #[case(
251        crate::datavalue!(1u32),
252        DataValue::U32(1),
253        vec![1u32]
254    )]
255    #[case(
256        crate::datavalue!(vec![1u32, 2u32]),
257        DataValue::Vec(vec![DataValue::U32(1), DataValue::U32(2)]),
258        vec![vec![1u32, 2u32]]
259    )]
260    fn convert_test<T: Extract + PartialEq + Debug>(
261        #[case] value: DataValue,
262        #[case] expected: DataValue,
263        #[case] expected_native: Vec<T>,
264    ) {
265        assert_eq!(value, expected);
266        let converted: Vec<T> = convert::<T>(&[value]);
267        assert_eq!(converted, expected_native);
268    }
269}