Skip to main content

reifydb_engine/expression/arith/
rem.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::{Column, data::ColumnData, push::Push};
5use reifydb_type::{
6	error::diagnostic::operator::rem_cannot_be_applied_to_incompatible_types,
7	fragment::LazyFragment,
8	return_error,
9	value::{
10		container::number::NumberContainer,
11		is::IsNumber,
12		number::{promote::Promote, safe::remainder::SafeRemainder},
13		r#type::{Type, get::GetType},
14	},
15};
16
17use crate::expression::context::EvalContext;
18
19pub(crate) fn rem_columns(
20	ctx: &EvalContext,
21	left: &Column,
22	right: &Column,
23	fragment: impl LazyFragment + Copy,
24) -> crate::Result<Column> {
25	crate::expression::option::binary_op_unwrap_option(left, right, fragment.fragment(), |left, right| {
26		let target = Type::promote(left.get_type(), right.get_type());
27
28		dispatch_arith!(
29			&left.data(), &right.data();
30			fixed: rem_numeric, arb: rem_numeric_clone (ctx, target, fragment);
31
32			_ => return_error!(rem_cannot_be_applied_to_incompatible_types(
33				fragment.fragment(),
34				left.get_type(),
35				right.get_type(),
36			)),
37		)
38	})
39}
40
41fn rem_numeric<'a, L, R>(
42	ctx: &EvalContext,
43	l: &NumberContainer<L>,
44	r: &NumberContainer<R>,
45	target: Type,
46	fragment: impl LazyFragment + Copy,
47) -> crate::Result<Column>
48where
49	L: GetType + Promote<R> + IsNumber,
50	R: GetType + IsNumber,
51	<L as Promote<R>>::Output: IsNumber,
52	<L as Promote<R>>::Output: SafeRemainder,
53	ColumnData: Push<<L as Promote<R>>::Output>,
54{
55	debug_assert_eq!(l.len(), r.len());
56
57	let mut data = ColumnData::with_capacity(target, l.len());
58	let l_data = l.data();
59	let r_data = r.data();
60	for i in 0..l.len() {
61		if let Some(value) = ctx.remainder(&l_data[i], &r_data[i], fragment)? {
62			data.push(value);
63		} else {
64			data.push_none()
65		}
66	}
67	Ok(Column {
68		name: fragment.fragment(),
69		data,
70	})
71}
72
73fn rem_numeric_clone<'a, L, R>(
74	ctx: &EvalContext,
75	l: &NumberContainer<L>,
76	r: &NumberContainer<R>,
77	target: Type,
78	fragment: impl LazyFragment + Copy,
79) -> crate::Result<Column>
80where
81	L: Clone + GetType + Promote<R> + IsNumber,
82	R: Clone + GetType + IsNumber,
83	<L as Promote<R>>::Output: IsNumber,
84	<L as Promote<R>>::Output: SafeRemainder,
85	ColumnData: Push<<L as Promote<R>>::Output>,
86{
87	debug_assert_eq!(l.len(), r.len());
88
89	let mut data = ColumnData::with_capacity(target, l.len());
90	let l_data = l.data();
91	let r_data = r.data();
92	for i in 0..l.len() {
93		let l_clone = l_data[i].clone();
94		let r_clone = r_data[i].clone();
95		if let Some(value) = ctx.remainder(&l_clone, &r_clone, fragment)? {
96			data.push(value);
97		} else {
98			data.push_none()
99		}
100	}
101	Ok(Column {
102		name: fragment.fragment(),
103		data,
104	})
105}