nullvec/nullvec/
nullvec_convert.rs

1use super::NullVec;
2use nullable::Nullable;
3use traits::NullStorable;
4
5impl<T: NullStorable> From<Vec<T>> for NullVec<T> {
6    fn from(values: Vec<T>) -> Self {
7        NullVec::new(values)
8    }
9}
10
11// &str handling
12impl<'a> From<Vec<&'a str>> for NullVec<String> {
13    fn from(values: Vec<&'a str>) -> Self {
14        let string: Vec<String> = values.iter().map(|x| x.to_string()).collect();
15        string.into()
16    }
17}
18
19impl<T: NullStorable> From<Vec<Nullable<T>>> for NullVec<T> {
20    fn from(values: Vec<Nullable<T>>) -> Self {
21        let mut new_values: Vec<T> = Vec::with_capacity(values.len());
22        let mut new_mask: Vec<bool> = Vec::with_capacity(values.len());
23        let mut has_null: bool = false;
24        for v in values.into_iter() {
25            match v {
26                Nullable::Value(v) => {
27                    new_values.push(v);
28                    new_mask.push(false);
29                }
30                Nullable::Null => {
31                    new_values.push(T::default());
32                    new_mask.push(true);
33                    has_null = true;
34                }
35            }
36        }
37        if has_null {
38            NullVec {
39                data: new_values,
40                mask: Some(new_mask),
41            }
42        } else {
43            NullVec {
44                data: new_values,
45                mask: None,
46            }
47        }
48    }
49}
50
51macro_rules! impl_from {
52    ($t:ident) => {
53        impl From<NullVec<$t>> for Vec<$t> {
54            fn from(values: NullVec<$t>) -> Vec<$t> {
55                // ToDo: check has_primitive_null and return type null
56                match values.mask {
57                    None => values.data,
58                    // ToDo: must be TryFrom
59                    _ => panic!("Unable to convert NaN to specified type")
60                }
61            }
62        }
63
64        impl From<NullVec<$t>> for Vec<Nullable<$t>> {
65            fn from(values: NullVec<$t>) -> Vec<Nullable<$t>> {
66                // ToDo: check has_primitive_null and return type null
67                match values.mask {
68                    None => values.data
69                                  .into_iter()
70                                  .map(|x| Nullable::Value(x))
71                                  .collect(),
72                    Some(mask) => values.data
73                                  .into_iter()
74                                  .zip(mask.into_iter())
75                                  .map(|(x, m)| if m == true {
76                                                    Nullable::Null
77                                                } else {
78                                                    Nullable::Value(x)
79                                                })
80                                  .collect(),
81
82                }
83            }
84        }
85    }
86}
87macro_dispatch!(
88    impl_from,
89    i64,
90    i32,
91    i16,
92    i8,
93    isize,
94    u64,
95    u32,
96    u16,
97    u8,
98    usize,
99    f64,
100    f32,
101    bool,
102    String
103);
104
105
106#[cfg(test)]
107mod tests {
108
109    use std::f64;
110    use nullable::Nullable;
111    use nullvec::NullVec;
112
113    #[test]
114    fn test_float_conv_from_vec() {
115        let nv = NullVec::<f64>::from(vec![1., 2.]);
116        assert_eq!(nv.data, vec![1., 2.]);
117        assert_eq!(nv.mask, None);
118
119        let res = Vec::<f64>::from(nv);
120        assert_eq!(res, vec![1., 2.]);
121
122        let nv = NullVec::<f64>::from(vec![1., f64::NAN]);
123        assert_eq!(nv.data, vec![1., 0.]);
124        assert_eq!(nv.mask, Some(vec![false, true]));
125    }
126
127    #[test]
128    fn test_float_conv_from_vec_contains_null() {
129        let nv = NullVec::<f64>::from(vec![1., f64::NAN]);
130        assert_eq!(nv.data, vec![1.0f64, 0.]);
131        assert_eq!(nv.mask, Some(vec![false, true]));
132    }
133
134    #[test]
135    #[should_panic]
136    fn test_float_conv_from_vec_contains_null_panic() {
137        let nv = NullVec::<f64>::from(vec![1., f64::NAN]);
138        // ToDo: this must success
139        Vec::<f64>::from(nv);
140    }
141
142    #[test]
143    fn test_float_conv_from_nullablevec() {
144        let nv = NullVec::<f64>::from(vec![Nullable::Value(1.), Nullable::Value(2.)]);
145        assert_eq!(nv.data, vec![1., 2.]);
146        assert_eq!(nv.mask, None);
147
148        let res = Vec::<Nullable<f64>>::from(nv);
149        assert_eq!(res, vec![Nullable::Value(1.), Nullable::Value(2.)]);
150
151        let nv = NullVec::<f64>::from(vec![Nullable::Value(1.), Nullable::Null]);
152        assert_eq!(nv.data, vec![1., 0.]);
153        assert_eq!(nv.mask, Some(vec![false, true]));
154
155        let res = Vec::<Nullable<f64>>::from(nv);
156        assert_eq!(res, vec![Nullable::Value(1.), Nullable::Null]);
157    }
158
159    #[test]
160    fn test_string_conv_from_vec() {
161        let nv = NullVec::<String>::from(vec!["a".to_string(), "b".to_string()]);
162        assert_eq!(nv.data, vec!["a".to_string(), "b".to_string()]);
163        assert_eq!(nv.mask, None);
164
165        let res = Vec::<String>::from(nv);
166        assert_eq!(res, vec!["a".to_string(), "b".to_string()]);
167    }
168
169    #[test]
170    fn test_str_conv_from_vec() {
171        let nv = NullVec::<String>::from(vec!["a", "b"]);
172        assert_eq!(nv.data, vec!["a".to_string(), "b".to_string()]);
173        assert_eq!(nv.mask, None);
174
175        let res = Vec::<String>::from(nv);
176        assert_eq!(res, vec!["a".to_string(), "b".to_string()]);
177    }
178}