trs_data_value/
extract.rs

1use super::{DataValue, Extract};
2
3macro_rules! impl_extract_nums {
4    ($($t:ty),*) => {
5        $(
6        impl Extract for $t {
7            #[inline]
8            fn extract(v: &DataValue) -> $t {
9                use DataValue::*;
10                match v {
11                    Bool(b) => (if b == &true { 1 } else { 0 })  as $t,
12                    U32(i) => *i as $t,
13                    I32(i) => *i as $t,
14                    U8(i) => *i as $t,
15                    U64(i) => *i as $t,
16                    I64(i) => *i as $t,
17                    F32(i) => *i as $t,
18                    F64(i) => *i as $t,
19                    U128(i) => *i as $t,
20                    I128(i) => *i as $t,
21                    EnumNumber(i) => *i as $t,
22                    _ => 0 as $t,
23                }
24            }
25        }
26    )*
27    };
28}
29
30impl_extract_nums!(u32, u64, i32, i64, f32, f64, u128, i128);
31impl Extract for u8 {
32    fn extract(v: &DataValue) -> u8 {
33        use DataValue::*;
34        match v {
35            U8(i) => *i,
36            _ => 0,
37        }
38    }
39}
40
41impl Extract for bool {
42    fn extract(v: &DataValue) -> bool {
43        match v {
44            DataValue::Bool(i) => *i,
45            DataValue::U8(i) => *i != 0,
46            DataValue::U32(i) => *i != 0,
47            DataValue::I32(i) => *i != 0,
48            DataValue::U64(i) => *i != 0,
49            DataValue::I64(i) => *i != 0,
50            DataValue::F32(i) => *i != 0.,
51            DataValue::F64(i) => *i != 0.,
52            _ => false,
53        }
54    }
55}
56
57impl Extract for String {
58    fn extract(v: &DataValue) -> String {
59        match v {
60            DataValue::String(i) => i.to_string(),
61            v => format!("{v}"),
62        }
63    }
64}
65
66impl<T> Extract for Vec<T>
67where
68    T: Extract,
69{
70    fn extract(v: &DataValue) -> Vec<T> {
71        use DataValue::*;
72        match v {
73            Vec(i) => i.iter().map(|x| T::extract(x)).collect(),
74            _ => vec![],
75        }
76    }
77}
78
79impl<V> Extract for std::collections::HashMap<smartstring::alias::String, V>
80where
81    V: Extract,
82{
83    fn extract(v: &DataValue) -> std::collections::HashMap<smartstring::alias::String, V> {
84        use DataValue::*;
85        match v {
86            Map(i) => i.iter().map(|(k, v)| (k.clone(), V::extract(v))).collect(),
87            _ => Default::default(),
88        }
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use super::*;
95    use rstest::*;
96
97    #[rstest]
98    #[case(DataValue::U8(1), 1)]
99    #[case(DataValue::U32(1), 1)]
100    #[case(DataValue::I32(1), 1)]
101    #[case(DataValue::U64(1), 1)]
102    #[case(DataValue::I64(1), 1)]
103    #[case(DataValue::F32(1.0), 1)]
104    #[case(DataValue::F64(1.0), 1)]
105    #[case(DataValue::U128(1), 1)]
106    #[case(DataValue::I128(1), 1)]
107    #[case(DataValue::EnumNumber(1), 1)]
108    #[case(DataValue::Bool(true), 1)]
109    #[case(DataValue::Bool(false), 0)]
110    #[case(DataValue::String("1".into()), 0)]
111    fn test_extract_num(#[case] input: DataValue, #[case] expected: u32) {
112        assert_eq!(u32::extract(&input), expected);
113    }
114
115    #[rstest]
116    #[case(DataValue::U8(1), "1")]
117    #[case(DataValue::U32(1), "1")]
118    #[case(DataValue::I32(1), "1")]
119    #[case(DataValue::U64(1), "1")]
120    #[case(DataValue::I64(1), "1")]
121    #[case(DataValue::F32(1.1), "1.1")]
122    #[case(DataValue::F64(1.1), "1.1")]
123    #[case(DataValue::U128(1), "1")]
124    #[case(DataValue::I128(1), "1")]
125    #[case(DataValue::EnumNumber(1), "1")]
126    #[case(DataValue::Bool(true), "true")]
127    #[case(DataValue::Bool(false), "false")]
128    #[case(DataValue::String("1".into()), "1")]
129    fn test_extract_string(#[case] input: DataValue, #[case] expected: &str) {
130        assert_eq!(String::extract(&input), expected.to_string());
131    }
132    #[rstest]
133    #[case(DataValue::U8(1), 1)]
134    #[case(DataValue::U32(1), 1)]
135    #[case(DataValue::I32(1), 1)]
136    #[case(DataValue::U64(1), 1)]
137    #[case(DataValue::I64(1), 1)]
138    #[case(DataValue::F32(1.0), 1)]
139    #[case(DataValue::F64(1.0), 1)]
140    #[case(DataValue::U128(1), 1)]
141    #[case(DataValue::I128(1), 1)]
142    #[case(DataValue::EnumNumber(1), 1)]
143    #[case(DataValue::Bool(true), 1)]
144    #[case(DataValue::Bool(false), 0)]
145    #[case(DataValue::String("1".into()), 0)]
146    fn test_extract_u64(#[case] input: DataValue, #[case] expected: u64) {
147        assert_eq!(u64::extract(&input), expected);
148    }
149
150    #[rstest]
151    #[case(DataValue::U8(1), 1)]
152    #[case(DataValue::U32(1), 1)]
153    #[case(DataValue::I32(1), 1)]
154    #[case(DataValue::U64(1), 1)]
155    #[case(DataValue::I64(1), 1)]
156    #[case(DataValue::F32(1.0), 1)]
157    #[case(DataValue::F64(1.0), 1)]
158    #[case(DataValue::U128(1), 1)]
159    #[case(DataValue::I128(1), 1)]
160    #[case(DataValue::EnumNumber(1), 1)]
161    #[case(DataValue::Bool(true), 1)]
162    #[case(DataValue::Bool(false), 0)]
163    #[case(DataValue::String("1".into()), 0)]
164    fn test_extract_i32(#[case] input: DataValue, #[case] expected: i32) {
165        assert_eq!(i32::extract(&input), expected);
166    }
167
168    #[rstest]
169    #[case(DataValue::U8(1), 1)]
170    #[case(DataValue::U32(1), 1)]
171    #[case(DataValue::I32(1), 1)]
172    #[case(DataValue::U64(1), 1)]
173    #[case(DataValue::I64(1), 1)]
174    #[case(DataValue::F32(1.0), 1)]
175    #[case(DataValue::F64(1.0), 1)]
176    #[case(DataValue::U128(1), 1)]
177    #[case(DataValue::I128(1), 1)]
178    #[case(DataValue::EnumNumber(1), 1)]
179    #[case(DataValue::Bool(true), 1)]
180    #[case(DataValue::Bool(false), 0)]
181    #[case(DataValue::String("1".into()), 0)]
182    fn test_extract_i64(#[case] input: DataValue, #[case] expected: i64) {
183        assert_eq!(i64::extract(&input), expected);
184    }
185
186    #[rstest]
187    #[case(DataValue::U8(1), 1f64)]
188    #[case(DataValue::U32(1), 1f64)]
189    #[case(DataValue::I32(1), 1f64)]
190    #[case(DataValue::U64(1), 1f64)]
191    #[case(DataValue::I64(1), 1f64)]
192    #[case(DataValue::F32(1.0), 1f64)]
193    #[case(DataValue::F64(1.0), 1f64)]
194    #[case(DataValue::U128(1), 1f64)]
195    #[case(DataValue::I128(1), 1f64)]
196    #[case(DataValue::EnumNumber(1), 1f64)]
197    #[case(DataValue::Bool(true), 1f64)]
198    #[case(DataValue::Bool(false), 0f64)]
199    #[case(DataValue::String("1".into()), 0f64)]
200    fn test_extract_f64(#[case] input: DataValue, #[case] expected: f64) {
201        assert_eq!(f64::extract(&input), expected);
202    }
203
204    #[rstest]
205    #[case(DataValue::U8(1), 1f32)]
206    #[case(DataValue::U32(1), 1f32)]
207    #[case(DataValue::I32(1), 1f32)]
208    #[case(DataValue::U64(1), 1f32)]
209    #[case(DataValue::I64(1), 1f32)]
210    #[case(DataValue::F32(1.0), 1f32)]
211    #[case(DataValue::F64(1.0), 1f32)]
212    #[case(DataValue::U128(1), 1f32)]
213    #[case(DataValue::I128(1), 1f32)]
214    #[case(DataValue::EnumNumber(1), 1f32)]
215    #[case(DataValue::Bool(true), 1f32)]
216    #[case(DataValue::Bool(false), 0f32)]
217    #[case(DataValue::String("1".into()), 0f32)]
218    #[case(DataValue::Null, 0f32)]
219    fn test_extract_f32(#[case] input: DataValue, #[case] expected: f32) {
220        assert_eq!(f32::extract(&input), expected);
221    }
222
223    #[rstest]
224    #[case(DataValue::Vec(vec![1.into()]), vec![1])]
225    #[case(DataValue::Vec(vec![1.into(), 2.into()]), vec![1, 2])]
226    #[case(DataValue::Vec(vec![1.into(), 2.into(), 3.into()]), vec![1, 2, 3])]
227    fn test_extract_vec(#[case] input: DataValue, #[case] expected: Vec<u32>) {
228        assert_eq!(Vec::<u32>::extract(&input), expected);
229    }
230
231    #[rstest]
232    #[case(DataValue::Map(crate::stdhashmap!("a" => 1)), crate::stdhashmap!("a" => 1))]
233    #[case(DataValue::Map(crate::stdhashmap!("a" => 1, "b" => 2)), crate::stdhashmap!("a" => 1, "b" => 2))]
234    #[case(DataValue::Map(crate::stdhashmap!("a" => 1, "b" => 2, "c" => 3)), crate::stdhashmap!("a" => 1, "b" => 2, "c" => 3))]
235    fn test_extract_map(
236        #[case] input: DataValue,
237        #[case] expected: std::collections::HashMap<smartstring::alias::String, i32>,
238    ) {
239        assert_eq!(
240            std::collections::HashMap::<smartstring::alias::String, i32>::extract(&input),
241            expected
242        );
243    }
244}