1use std::cmp::Ordering;
5use std::fmt::{Display, Formatter};
6
7use vortex_dtype::Nullability::NonNullable;
8use vortex_dtype::{DType, Nullability};
9use vortex_error::{VortexError, VortexExpect as _, VortexResult, vortex_bail, vortex_err};
10
11use crate::{InnerScalarValue, Scalar, ScalarValue};
12
13#[derive(Debug, Hash)]
18pub struct BoolScalar<'a> {
19 dtype: &'a DType,
20 value: Option<bool>,
21}
22
23impl Display for BoolScalar<'_> {
24 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
25 match self.value {
26 None => write!(f, "null"),
27 Some(v) => write!(f, "{v}"),
28 }
29 }
30}
31
32impl PartialEq for BoolScalar<'_> {
33 fn eq(&self, other: &Self) -> bool {
34 self.dtype.eq_ignore_nullability(other.dtype) && self.value == other.value
35 }
36}
37
38impl Eq for BoolScalar<'_> {}
39
40impl PartialOrd for BoolScalar<'_> {
41 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
42 Some(self.value.cmp(&other.value))
43 }
44}
45
46impl Ord for BoolScalar<'_> {
47 fn cmp(&self, other: &Self) -> Ordering {
48 self.value.cmp(&other.value)
49 }
50}
51
52impl<'a> BoolScalar<'a> {
53 #[inline]
55 pub fn dtype(&self) -> &'a DType {
56 self.dtype
57 }
58
59 pub fn value(&self) -> Option<bool> {
61 self.value
62 }
63
64 pub(crate) fn cast(&self, dtype: &DType) -> VortexResult<Scalar> {
65 if !matches!(dtype, DType::Bool(..)) {
66 vortex_bail!("Can't cast bool to {}", dtype)
67 }
68 Ok(Scalar::bool(
69 self.value.vortex_expect("nullness handled in Scalar::cast"),
70 dtype.nullability(),
71 ))
72 }
73
74 pub fn invert(self) -> BoolScalar<'a> {
78 BoolScalar {
79 dtype: self.dtype,
80 value: self.value.map(|v| !v),
81 }
82 }
83
84 pub fn into_scalar(self) -> Scalar {
86 Scalar {
87 dtype: self.dtype.clone(),
88 value: self
89 .value
90 .map(|x| ScalarValue(InnerScalarValue::Bool(x)))
91 .unwrap_or_else(|| ScalarValue(InnerScalarValue::Null)),
92 }
93 }
94}
95
96impl Scalar {
97 pub fn bool(value: bool, nullability: Nullability) -> Self {
99 Self {
100 dtype: DType::Bool(nullability),
101 value: ScalarValue(InnerScalarValue::Bool(value)),
102 }
103 }
104}
105
106impl<'a> TryFrom<&'a Scalar> for BoolScalar<'a> {
107 type Error = VortexError;
108
109 fn try_from(value: &'a Scalar) -> Result<Self, Self::Error> {
110 if !matches!(value.dtype(), DType::Bool(_)) {
111 vortex_bail!("Expected bool scalar, found {}", value.dtype())
112 }
113 Ok(Self {
114 dtype: value.dtype(),
115 value: value.value.as_bool()?,
116 })
117 }
118}
119
120impl TryFrom<&Scalar> for bool {
121 type Error = VortexError;
122
123 fn try_from(value: &Scalar) -> VortexResult<Self> {
124 <Option<bool>>::try_from(value)?
125 .ok_or_else(|| vortex_err!("Can't extract present value from null scalar"))
126 }
127}
128
129impl TryFrom<&Scalar> for Option<bool> {
130 type Error = VortexError;
131
132 fn try_from(value: &Scalar) -> VortexResult<Self> {
133 Ok(BoolScalar::try_from(value)?.value())
134 }
135}
136
137impl TryFrom<Scalar> for bool {
138 type Error = VortexError;
139
140 fn try_from(value: Scalar) -> VortexResult<Self> {
141 Self::try_from(&value)
142 }
143}
144
145impl TryFrom<Scalar> for Option<bool> {
146 type Error = VortexError;
147
148 fn try_from(value: Scalar) -> VortexResult<Self> {
149 Self::try_from(&value)
150 }
151}
152
153impl From<bool> for Scalar {
154 fn from(value: bool) -> Self {
155 Self {
156 dtype: DType::Bool(NonNullable),
157 value: value.into(),
158 }
159 }
160}
161
162impl From<bool> for ScalarValue {
163 fn from(value: bool) -> Self {
164 ScalarValue(InnerScalarValue::Bool(value))
165 }
166}
167
168#[cfg(test)]
169mod test {
170 use vortex_dtype::Nullability::*;
171
172 use super::*;
173
174 #[test]
175 fn into_from() {
176 let scalar: Scalar = false.into();
177 assert!(!bool::try_from(&scalar).unwrap());
178 }
179
180 #[test]
181 fn equality() {
182 assert_eq!(&Scalar::bool(true, Nullable), &Scalar::bool(true, Nullable));
183 assert_eq!(
185 &Scalar::bool(true, Nullable),
186 &Scalar::bool(true, NonNullable)
187 );
188 }
189}