Skip to main content

reifydb_engine/expression/cast/
boolean.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::{fmt::Display, sync::Arc};
5
6use reifydb_core::value::column::buffer::ColumnBuffer;
7use reifydb_type::{
8	error::TypeError,
9	fragment::{Fragment, LazyFragment},
10	value::{
11		boolean::parse::parse_bool,
12		container::{number::NumberContainer, utf8::Utf8Container},
13		is::IsNumber,
14		r#type::Type,
15	},
16};
17
18use crate::Result;
19
20pub fn to_boolean(data: &ColumnBuffer, lazy_fragment: impl LazyFragment) -> Result<ColumnBuffer> {
21	match data {
22		ColumnBuffer::Int1(container) => from_int1(container, lazy_fragment),
23		ColumnBuffer::Int2(container) => from_int2(container, lazy_fragment),
24		ColumnBuffer::Int4(container) => from_int4(container, lazy_fragment),
25		ColumnBuffer::Int8(container) => from_int8(container, lazy_fragment),
26		ColumnBuffer::Int16(container) => from_int16(container, lazy_fragment),
27		ColumnBuffer::Uint1(container) => from_uint1(container, lazy_fragment),
28		ColumnBuffer::Uint2(container) => from_uint2(container, lazy_fragment),
29		ColumnBuffer::Uint4(container) => from_uint4(container, lazy_fragment),
30		ColumnBuffer::Uint8(container) => from_uint8(container, lazy_fragment),
31		ColumnBuffer::Uint16(container) => from_uint16(container, lazy_fragment),
32		ColumnBuffer::Float4(container) => from_float4(container, lazy_fragment),
33		ColumnBuffer::Float8(container) => from_float8(container, lazy_fragment),
34		ColumnBuffer::Utf8 {
35			container,
36			..
37		} => from_utf8(container, lazy_fragment),
38		_ => {
39			let from = data.get_type();
40			Err(TypeError::UnsupportedCast {
41				from,
42				to: Type::Boolean,
43				fragment: lazy_fragment.fragment(),
44			}
45			.into())
46		}
47	}
48}
49
50fn to_bool<T>(
51	container: &NumberContainer<T>,
52	lazy_fragment: impl LazyFragment,
53	validate: impl Fn(T) -> Option<bool>,
54) -> Result<ColumnBuffer>
55where
56	T: Copy + Display + IsNumber + Default,
57{
58	let mut out = ColumnBuffer::with_capacity(Type::Boolean, container.len());
59	for idx in 0..container.len() {
60		if container.is_defined(idx) {
61			match validate(container[idx]) {
62				Some(b) => out.push::<bool>(b),
63				None => {
64					let base_fragment = lazy_fragment.fragment();
65					let error_fragment = Fragment::Statement {
66						text: Arc::from(container[idx].to_string()),
67						line: base_fragment.line(),
68						column: base_fragment.column(),
69					};
70					return Err(TypeError::InvalidNumberBoolean {
71						fragment: error_fragment,
72					}
73					.into());
74				}
75			}
76		} else {
77			out.push_none();
78		}
79	}
80	Ok(out)
81}
82
83macro_rules! impl_integer_to_bool {
84	($fn_name:ident, $type:ty) => {
85		#[inline]
86		fn $fn_name(
87			container: &NumberContainer<$type>,
88			lazy_fragment: impl LazyFragment,
89		) -> Result<ColumnBuffer> {
90			to_bool(container, lazy_fragment, |val| match val {
91				0 => Some(false),
92				1 => Some(true),
93				_ => None,
94			})
95		}
96	};
97}
98
99macro_rules! impl_float_to_bool {
100	($fn_name:ident, $type:ty) => {
101		#[inline]
102		fn $fn_name(
103			container: &NumberContainer<$type>,
104			lazy_fragment: impl LazyFragment,
105		) -> Result<ColumnBuffer> {
106			to_bool(container, lazy_fragment, |val| {
107				if val == 0.0 {
108					Some(false)
109				} else if val == 1.0 {
110					Some(true)
111				} else {
112					None
113				}
114			})
115		}
116	};
117}
118
119impl_integer_to_bool!(from_int1, i8);
120impl_integer_to_bool!(from_int2, i16);
121impl_integer_to_bool!(from_int4, i32);
122impl_integer_to_bool!(from_int8, i64);
123impl_integer_to_bool!(from_int16, i128);
124impl_integer_to_bool!(from_uint1, u8);
125impl_integer_to_bool!(from_uint2, u16);
126impl_integer_to_bool!(from_uint4, u32);
127impl_integer_to_bool!(from_uint8, u64);
128impl_integer_to_bool!(from_uint16, u128);
129impl_float_to_bool!(from_float4, f32);
130impl_float_to_bool!(from_float8, f64);
131
132fn from_utf8(container: &Utf8Container, lazy_fragment: impl LazyFragment) -> Result<ColumnBuffer> {
133	let mut out = ColumnBuffer::with_capacity(Type::Boolean, container.len());
134	for idx in 0..container.len() {
135		if container.is_defined(idx) {
136			let temp_fragment = Fragment::internal(container.get(idx).unwrap());
137			match parse_bool(temp_fragment) {
138				Ok(b) => out.push(b),
139				Err(mut e) => {
140					e.0.with_fragment(lazy_fragment.fragment());
141					return Err(e);
142				}
143			}
144		} else {
145			out.push_none();
146		}
147	}
148	Ok(out)
149}