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    /// A self-describing displayed form.
19    ///
20    /// The usual Display renders [Nullability::NonNullable] as the empty string.
21    pub fn verbose_display(&self) -> impl Display {
22        match self {
23            Nullability::NonNullable => "NonNullable",
24            Nullability::Nullable => "Nullable",
25        }
26    }
27}
28
29impl BitOr for Nullability {
30    type Output = Nullability;
31
32    #[inline]
33    fn bitor(self, rhs: Self) -> Self::Output {
34        match (self, rhs) {
35            (Self::NonNullable, Self::NonNullable) => Self::NonNullable,
36            _ => Self::Nullable,
37        }
38    }
39}
40
41impl BitOrAssign for Nullability {
42    fn bitor_assign(&mut self, rhs: Self) {
43        *self = *self | rhs
44    }
45}
46
47impl From<bool> for Nullability {
48    #[inline]
49    fn from(value: bool) -> Self {
50        if value {
51            Self::Nullable
52        } else {
53            Self::NonNullable
54        }
55    }
56}
57
58impl From<Nullability> for bool {
59    #[inline]
60    fn from(value: Nullability) -> Self {
61        match value {
62            Nullability::NonNullable => false,
63            Nullability::Nullable => true,
64        }
65    }
66}
67
68impl Display for Nullability {
69    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70        match self {
71            Self::NonNullable => write!(f, ""),
72            Self::Nullable => write!(f, "?"),
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_nullability_default() {
83        let default = Nullability::default();
84        assert_eq!(default, Nullability::NonNullable);
85    }
86
87    #[test]
88    fn test_nullability_bitor() {
89        use Nullability::*;
90
91        // NonNullable | NonNullable = NonNullable
92        assert_eq!(NonNullable | NonNullable, NonNullable);
93
94        // NonNullable | Nullable = Nullable
95        assert_eq!(NonNullable | Nullable, Nullable);
96
97        // Nullable | NonNullable = Nullable
98        assert_eq!(Nullable | NonNullable, Nullable);
99
100        // Nullable | Nullable = Nullable
101        assert_eq!(Nullable | Nullable, Nullable);
102    }
103
104    #[test]
105    fn test_nullability_from_bool() {
106        assert_eq!(Nullability::from(false), Nullability::NonNullable);
107        assert_eq!(Nullability::from(true), Nullability::Nullable);
108    }
109
110    #[test]
111    fn test_bool_from_nullability() {
112        assert!(!bool::from(Nullability::NonNullable));
113        assert!(bool::from(Nullability::Nullable));
114    }
115
116    #[test]
117    fn test_nullability_roundtrip() {
118        // Test roundtrip conversion bool -> Nullability -> bool
119        assert!(!bool::from(Nullability::from(false)));
120        assert!(bool::from(Nullability::from(true)));
121
122        // Test roundtrip conversion Nullability -> bool -> Nullability
123        assert_eq!(
124            Nullability::from(bool::from(Nullability::NonNullable)),
125            Nullability::NonNullable
126        );
127        assert_eq!(
128            Nullability::from(bool::from(Nullability::Nullable)),
129            Nullability::Nullable
130        );
131    }
132
133    #[test]
134    fn test_nullability_chained_bitor() {
135        // Test chaining multiple BitOr operations
136        let result = Nullability::NonNullable | Nullability::NonNullable | Nullability::NonNullable;
137        assert_eq!(result, Nullability::NonNullable);
138
139        let result = Nullability::NonNullable | Nullability::Nullable | Nullability::NonNullable;
140        assert_eq!(result, Nullability::Nullable);
141    }
142}