Skip to main content

reifydb_engine/expression/arith/
mul.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::{BinaryOp, TypeError},
7	fragment::LazyFragment,
8	value::{
9		container::number::NumberContainer,
10		is::IsNumber,
11		number::{promote::Promote, safe::mul::SafeMul},
12		r#type::{Type, get::GetType},
13	},
14};
15
16use crate::{
17	Result,
18	expression::{context::EvalContext, option::binary_op_unwrap_option},
19};
20
21pub(crate) fn mul_columns(
22	ctx: &EvalContext,
23	left: &Column,
24	right: &Column,
25	fragment: impl LazyFragment + Copy,
26) -> Result<Column> {
27	binary_op_unwrap_option(left, right, fragment.fragment(), |left, right| {
28		let target = Type::promote(left.get_type(), right.get_type());
29
30		dispatch_arith!(
31			&left.data(), &right.data();
32			fixed: mul_numeric, arb: mul_numeric_clone (ctx, target, fragment);
33
34			_ => return Err(TypeError::BinaryOperatorNotApplicable {
35				operator: BinaryOp::Mul,
36				left: left.get_type(),
37				right: right.get_type(),
38				fragment: fragment.fragment(),
39			}.into()),
40		)
41	})
42}
43
44fn mul_numeric<'a, L, R>(
45	ctx: &EvalContext,
46	l: &NumberContainer<L>,
47	r: &NumberContainer<R>,
48	target: Type,
49	fragment: impl LazyFragment + Copy,
50) -> Result<Column>
51where
52	L: GetType + Promote<R> + IsNumber,
53	R: GetType + IsNumber,
54	<L as Promote<R>>::Output: IsNumber,
55	<L as Promote<R>>::Output: SafeMul,
56	ColumnData: Push<<L as Promote<R>>::Output>,
57{
58	debug_assert_eq!(l.len(), r.len());
59
60	let mut data = ColumnData::with_capacity(target, l.len());
61	let l_data = l.data();
62	let r_data = r.data();
63	for i in 0..l.len() {
64		if let Some(value) = ctx.mul(&l_data[i], &r_data[i], fragment)? {
65			data.push(value);
66		} else {
67			data.push_none()
68		}
69	}
70	Ok(Column {
71		name: fragment.fragment(),
72		data,
73	})
74}
75
76fn mul_numeric_clone<'a, L, R>(
77	ctx: &EvalContext,
78	l: &NumberContainer<L>,
79	r: &NumberContainer<R>,
80	target: Type,
81	fragment: impl LazyFragment + Copy,
82) -> Result<Column>
83where
84	L: Clone + GetType + Promote<R> + IsNumber,
85	R: Clone + GetType + IsNumber,
86	<L as Promote<R>>::Output: IsNumber,
87	<L as Promote<R>>::Output: SafeMul,
88	ColumnData: Push<<L as Promote<R>>::Output>,
89{
90	debug_assert_eq!(l.len(), r.len());
91
92	let mut data = ColumnData::with_capacity(target, l.len());
93	let l_data = l.data();
94	let r_data = r.data();
95	for i in 0..l.len() {
96		let l_clone = l_data[i].clone();
97		let r_clone = r_data[i].clone();
98		if let Some(value) = ctx.mul(&l_clone, &r_clone, fragment)? {
99			data.push(value);
100		} else {
101			data.push_none()
102		}
103	}
104	Ok(Column {
105		name: fragment.fragment(),
106		data,
107	})
108}