vortex_dtype/
nullability.rs

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