Skip to main content

vortex_dtype/
nullability.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt::Display;
5use std::fmt::Formatter;
6use std::ops::BitOr;
7use std::ops::BitOrAssign;
8
9/// Whether an instance of a DType can be `null or not
10#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
11pub enum Nullability {
12    /// Instances of this DType are guaranteed to be non-nullable
13    #[default]
14    NonNullable,
15    /// Instances of this DType may contain a null value
16    Nullable,
17}
18
19impl Nullability {
20    /// Returns `true` if the nullability is [`Nullable`](Self::Nullable), otherwise returns
21    /// `false`.
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// use vortex_dtype::Nullability::*;
27    ///
28    /// assert!(!NonNullable.is_nullable());
29    /// assert!(Nullable.is_nullable());
30    /// ```
31    pub fn is_nullable(&self) -> bool {
32        match self {
33            Nullability::NonNullable => false,
34            Nullability::Nullable => true,
35        }
36    }
37}
38
39impl BitOr for Nullability {
40    type Output = Nullability;
41
42    #[inline]
43    fn bitor(self, rhs: Self) -> Self::Output {
44        match (self, rhs) {
45            (Self::NonNullable, Self::NonNullable) => Self::NonNullable,
46            _ => Self::Nullable,
47        }
48    }
49}
50
51impl BitOrAssign for Nullability {
52    fn bitor_assign(&mut self, rhs: Self) {
53        *self = *self | rhs
54    }
55}
56
57impl From<bool> for Nullability {
58    #[inline]
59    fn from(value: bool) -> Self {
60        if value {
61            Self::Nullable
62        } else {
63            Self::NonNullable
64        }
65    }
66}
67
68impl From<Nullability> for bool {
69    #[inline]
70    fn from(value: Nullability) -> Self {
71        match value {
72            Nullability::NonNullable => false,
73            Nullability::Nullable => true,
74        }
75    }
76}
77
78impl Display for Nullability {
79    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80        match self {
81            Self::NonNullable => {
82                if f.alternate() {
83                    write!(f, "NonNullable")
84                } else {
85                    write!(f, "")
86                }
87            }
88            Self::Nullable => {
89                if f.alternate() {
90                    write!(f, "Nullable")
91                } else {
92                    write!(f, "?")
93                }
94            }
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_nullability_default() {
105        let default = Nullability::default();
106        assert_eq!(default, Nullability::NonNullable);
107    }
108
109    #[test]
110    fn test_nullability_bitor() {
111        use Nullability::*;
112
113        // NonNullable | NonNullable = NonNullable
114        assert_eq!(NonNullable | NonNullable, NonNullable);
115
116        // NonNullable | Nullable = Nullable
117        assert_eq!(NonNullable | Nullable, Nullable);
118
119        // Nullable | NonNullable = Nullable
120        assert_eq!(Nullable | NonNullable, Nullable);
121
122        // Nullable | Nullable = Nullable
123        assert_eq!(Nullable | Nullable, Nullable);
124    }
125
126    #[test]
127    fn test_nullability_from_bool() {
128        assert_eq!(Nullability::from(false), Nullability::NonNullable);
129        assert_eq!(Nullability::from(true), Nullability::Nullable);
130    }
131
132    #[test]
133    fn test_bool_from_nullability() {
134        assert!(!bool::from(Nullability::NonNullable));
135        assert!(bool::from(Nullability::Nullable));
136    }
137
138    #[test]
139    fn test_nullability_roundtrip() {
140        // Test roundtrip conversion bool -> Nullability -> bool
141        assert!(!bool::from(Nullability::from(false)));
142        assert!(bool::from(Nullability::from(true)));
143
144        // Test roundtrip conversion Nullability -> bool -> Nullability
145        assert_eq!(
146            Nullability::from(bool::from(Nullability::NonNullable)),
147            Nullability::NonNullable
148        );
149        assert_eq!(
150            Nullability::from(bool::from(Nullability::Nullable)),
151            Nullability::Nullable
152        );
153    }
154
155    #[test]
156    fn test_nullability_chained_bitor() {
157        // Test chaining multiple BitOr operations
158        let result = Nullability::NonNullable | Nullability::NonNullable | Nullability::NonNullable;
159        assert_eq!(result, Nullability::NonNullable);
160
161        let result = Nullability::NonNullable | Nullability::Nullable | Nullability::NonNullable;
162        assert_eq!(result, Nullability::Nullable);
163    }
164}