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;
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 From<bool> for Nullability {
42    #[inline]
43    fn from(value: bool) -> Self {
44        if value {
45            Self::Nullable
46        } else {
47            Self::NonNullable
48        }
49    }
50}
51
52impl From<Nullability> for bool {
53    #[inline]
54    fn from(value: Nullability) -> Self {
55        match value {
56            Nullability::NonNullable => false,
57            Nullability::Nullable => true,
58        }
59    }
60}
61
62impl Display for Nullability {
63    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64        match self {
65            Self::NonNullable => write!(f, ""),
66            Self::Nullable => write!(f, "?"),
67        }
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_nullability_default() {
77        let default = Nullability::default();
78        assert_eq!(default, Nullability::NonNullable);
79    }
80
81    #[test]
82    fn test_nullability_bitor() {
83        use Nullability::*;
84
85        // NonNullable | NonNullable = NonNullable
86        assert_eq!(NonNullable | NonNullable, NonNullable);
87
88        // NonNullable | Nullable = Nullable
89        assert_eq!(NonNullable | Nullable, Nullable);
90
91        // Nullable | NonNullable = Nullable
92        assert_eq!(Nullable | NonNullable, Nullable);
93
94        // Nullable | Nullable = Nullable
95        assert_eq!(Nullable | Nullable, Nullable);
96    }
97
98    #[test]
99    fn test_nullability_from_bool() {
100        assert_eq!(Nullability::from(false), Nullability::NonNullable);
101        assert_eq!(Nullability::from(true), Nullability::Nullable);
102    }
103
104    #[test]
105    fn test_bool_from_nullability() {
106        assert!(!bool::from(Nullability::NonNullable));
107        assert!(bool::from(Nullability::Nullable));
108    }
109
110    #[test]
111    fn test_nullability_roundtrip() {
112        // Test roundtrip conversion bool -> Nullability -> bool
113        assert!(!bool::from(Nullability::from(false)));
114        assert!(bool::from(Nullability::from(true)));
115
116        // Test roundtrip conversion Nullability -> bool -> Nullability
117        assert_eq!(
118            Nullability::from(bool::from(Nullability::NonNullable)),
119            Nullability::NonNullable
120        );
121        assert_eq!(
122            Nullability::from(bool::from(Nullability::Nullable)),
123            Nullability::Nullable
124        );
125    }
126
127    #[test]
128    fn test_nullability_chained_bitor() {
129        // Test chaining multiple BitOr operations
130        let result = Nullability::NonNullable | Nullability::NonNullable | Nullability::NonNullable;
131        assert_eq!(result, Nullability::NonNullable);
132
133        let result = Nullability::NonNullable | Nullability::Nullable | Nullability::NonNullable;
134        assert_eq!(result, Nullability::Nullable);
135    }
136}