nullvec/nullvec/
mod.rs

1//! Nullable `Vec` which can contains specified type `T` and `Null`.
2//!
3//! # Examples
4//!
5//! ```
6//! use nullvec::prelude::*;
7//! let v = NullVec::new(vec![1, 2, 3]);
8//! assert_eq!(v.is_null(), vec![false, false, false]);
9//!
10//! // masked values are regarded as Null
11//! let v = NullVec::with_mask(vec![1, 2, 3], Some(vec![true, false, true]));
12//! assert_eq!(v.is_null(), vec![true, false, true]);
13//! ```
14
15// use std::collections::BitVec;
16
17mod nullvec_convert;
18mod nullvec_impl;
19mod nullvec_impl_aggregation;
20mod nullvec_impl_iter;
21
22// broadcast op
23mod nullvec_ops_primitive;
24mod nullvec_ops_nullable;
25
26// elemwise op
27mod nullvec_ops_vec;
28mod nullvec_ops_nullvec;
29
30// scalar compat
31mod nullvec_scalar;
32
33use algos::vec_ops::Elemwise;
34use traits::NullStorable;
35
36/// Nullable Vector
37#[derive(Clone, Debug, PartialEq)]
38pub struct NullVec<T: NullStorable> {
39    data: Vec<T>,
40    // ToDo: use BitVec
41    mask: Option<Vec<bool>>,
42}
43
44fn maybe_null<T: NullStorable>(values: Vec<T>) -> (Vec<T>, Option<Vec<bool>>) {
45    if T::has_primitive_null() {
46        let mut not_null: Vec<T> = Vec::with_capacity(values.len());
47        let mut mask: Vec<bool> = Vec::with_capacity(values.len());
48        let mut has_null = false;
49
50        for v in values.into_iter() {
51            if v.is_null() {
52                not_null.push(T::default());
53                mask.push(true);
54                has_null = true;
55            } else {
56                not_null.push(v);
57                mask.push(false);
58            }
59        }
60        if has_null == true {
61            (not_null, Some(mask))
62        } else {
63            (not_null, None)
64        }
65    } else {
66        (values, None)
67    }
68
69}
70
71impl<T: NullStorable> NullVec<T> {
72    /// Create new `NullVec<T>` from `Vec<T>`.
73    ///
74    /// Float `NAN` is automatically replaced to `Null`.
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// use std::f64;
80    /// use nullvec::prelude::*;
81    ///
82    /// // regarded as [1, 2, 3]
83    /// let nv = NullVec::new(vec![1, 2, 3]);
84    /// assert_eq!(nv.is_null(), vec![false, false, false]);
85    ///
86    /// // regarded as [1, NULL, 3]
87    /// let nv = NullVec::new(vec![1., f64::NAN, 3.]);
88    /// assert_eq!(nv.is_null(), vec![false, true, false]);
89    /// ```
90    pub fn new(values: Vec<T>) -> Self {
91        let (not_null, mask) = maybe_null(values);
92
93        NullVec {
94            data: not_null,
95            mask: mask,
96        }
97    }
98
99    /// Create new `NullVec<T>` from `Vec<T>` and mask.
100    ///
101    /// # Parameters
102    ///
103    /// * `values` - Values of `NullVec<T>`.
104    /// * `mask` - Mask whether to be corresponding element should be regarded as `Null`.
105    ///   If mask is `true`, `values` of corresponding location is ignored and internally
106    ///   replaced to `Null`.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use std::f64;
112    /// use nullvec::prelude::*;
113    ///
114    /// // regarded as [NULL, 2, NULL]
115    /// let nv = NullVec::with_mask(vec![1, 2, 3], Some(vec![true, false, true]));
116    /// assert_eq!(nv.is_null(), vec![true, false, true]);
117    ///
118    /// // regarded as [1., NULL, NULL]
119    /// let nv = NullVec::with_mask(vec![1., f64::NAN, 3.], Some(vec![false, false, true]));
120    /// assert_eq!(nv.is_null(), vec![false, true, true]);
121    /// ```
122    pub fn with_mask(values: Vec<T>, mask: Option<Vec<bool>>) -> Self {
123        let (not_null, null_mask) = maybe_null(values);
124        let new_mask = match (null_mask, mask) {
125            (Some(lmask), Some(rmask)) => Some(Elemwise::elemwise_oo(lmask, rmask, |x, y| x | y)),
126            (Some(lmask), None) => Some(lmask),
127            (None, Some(rmask)) => Some(rmask),
128            (None, None) => None,
129        };
130
131        NullVec {
132            data: not_null,
133            mask: new_mask,
134        }
135    }
136}
137
138
139#[cfg(test)]
140mod tests {
141
142    use std::f64;
143
144    use super::{NullVec, maybe_null};
145
146    #[test]
147    fn test_int() {
148        let values: Vec<usize> = vec![1, 2, 3];
149        let nvec = NullVec::new(values);
150        assert_eq!(nvec.data, vec![1, 2, 3]);
151        assert_eq!(nvec.mask, None);
152    }
153
154    #[test]
155    fn test_float() {
156        let values: Vec<f64> = vec![1.1, 1.2, 1.3];
157        let nvec = NullVec::new(values);
158        assert_eq!(nvec.data, vec![1.1, 1.2, 1.3]);
159        assert_eq!(nvec.mask, None);
160    }
161
162    #[test]
163    fn test_float_nan() {
164        let values: Vec<f64> = vec![1.1, f64::NAN, 1.3];
165        let nvec = NullVec::new(values);
166        assert_eq!(nvec.data, vec![1.1, 0., 1.3]);
167        assert_eq!(nvec.mask, Some(vec![false, true, false]));
168    }
169
170    #[test]
171    fn test_int_with_mask() {
172        let values: Vec<usize> = vec![1, 2, 3];
173        let nvec = NullVec::with_mask(values, Some(vec![true, false, false]));
174        assert_eq!(nvec.data, vec![1, 2, 3]);
175        assert_eq!(nvec.mask, Some(vec![true, false, false]));
176    }
177
178    #[test]
179    fn test_float_with_mask() {
180        let values: Vec<f64> = vec![1.1, f64::NAN, 1.3];
181        let nvec = NullVec::with_mask(values, Some(vec![true, false, false]));
182        assert_eq!(nvec.data, vec![1.1, 0., 1.3]);
183        assert_eq!(nvec.mask, Some(vec![true, true, false]));
184
185        let values: Vec<f64> = vec![1.1, f64::NAN, 1.3];
186        let nvec = NullVec::with_mask(values, None);
187        assert_eq!(nvec.data, vec![1.1, 0., 1.3]);
188        assert_eq!(nvec.mask, Some(vec![false, true, false]));
189    }
190
191    #[test]
192    fn test_maybe_null() {
193        let values: Vec<f64> = vec![1.1, f64::NAN, 1.3];
194        let (not_null, mask) = maybe_null(values);
195        assert_eq!(not_null, vec![1.1, 0., 1.3]);
196        assert_eq!(mask, Some(vec![false, true, false]));
197
198        let values: Vec<f64> = vec![1.1, 1.2, 1.3];
199        let (not_null, mask) = maybe_null(values);
200        assert_eq!(not_null, vec![1.1, 1.2, 1.3]);
201        assert_eq!(mask, None);
202    }
203}