multisql/data/value/methods/
binary.rs

1#![allow(clippy::should_implement_trait)] // TODO
2
3use {
4	super::ValueCore,
5	crate::{Convert, ConvertFrom, Result, Value, ValueError},
6};
7
8// These were using references, they now consume their variables. See ::recipe.
9macro_rules! natural_binary_op {
10    ($name: ident, $trait: ident, $op: tt) => {
11        pub fn $name<Core>(self, other: Self) -> Result<Self>
12        where
13            Core: ValueCore + $trait<Output = Core>,
14        {
15            let (left, right) = (Core::convert_from(self)?, Core::convert_from(other)?);
16            let result = left $op right;
17            Ok(result.into())
18        }
19    };
20}
21macro_rules! natural_binary_ops {
22    ($(($name: ident, $trait: ident, $op: tt, $generic_name: ident)),+) => {
23        use std::ops::{$($trait),+};
24        impl Value {
25            $(
26                natural_binary_op!($name, $trait, $op);
27                generic!($name, $generic_name);
28            )+
29        }
30    }
31}
32
33macro_rules! boolean_binary_op {
34    ($name: ident, $op: tt) => {
35        pub fn $name(self, other: Self) -> Result<Self>
36        {
37            let (left, right): (bool, bool) = (self.convert()?, other.convert()?);
38            let result = left $op right;
39            Ok(result.into())
40        }
41    };
42}
43macro_rules! boolean_binary_ops {
44    ($(($name: ident, $op: tt)),+) => {
45        impl Value {
46            $(boolean_binary_op!($name, $op);)+
47        }
48    }
49}
50
51macro_rules! comparative_binary_op {
52    ($name: ident, $op: tt) => {
53        pub fn $name(self, other: Self) -> Result<Self> {
54            Ok(Value::Bool(self $op other))
55        }
56    };
57}
58macro_rules! comparative_binary_ops {
59    ($(($name: ident, $op: tt)),+) => {
60        impl Value {
61            $(comparative_binary_op!($name, $op);)+
62        }
63    }
64}
65
66macro_rules! generic {
67	($name: ident, $generic_name: ident) => {
68		pub fn $generic_name(self, other: Self) -> Result<Self> {
69			if matches!(self, Value::Null) || matches!(other, Value::Null) {
70				Ok(Value::Null)
71			} else if !i64::convert_from(self.clone()).is_err()
72				&& !i64::convert_from(other.clone()).is_err()
73			{
74				self.$name::<i64>(other)
75			} else if !f64::convert_from(self.clone()).is_err()
76				&& !f64::convert_from(other.clone()).is_err()
77			{
78				self.$name::<f64>(other)
79			} else {
80				Err(ValueError::OnlySupportsNumeric(
81					if f64::convert_from(self.clone()).is_err() {
82						self
83					} else {
84						other
85					},
86					stringify!($name),
87				)
88				.into())
89			}
90		}
91	};
92}
93
94natural_binary_ops!(
95	(add, Add, +, generic_add),
96	(subtract, Sub, -, generic_subtract),
97	(multiply, Mul, *, generic_multiply),
98	(divide, Div, /, generic_divide),
99	(modulus, Rem, %, generic_modulus)
100);
101
102boolean_binary_ops!(
103	(and, &),
104	(or, |),
105	(xor, ^)
106);
107
108comparative_binary_ops!(
109	(eq, ==),
110	(not_eq, !=),
111	(gt, >),
112	(gt_eq, >=),
113	(lt, <),
114	(lt_eq, <=)
115);
116
117impl Value {
118	pub fn string_concat(self, other: Self) -> Result<Self> {
119		if matches!(self, Value::Null) || matches!(other, Value::Null) {
120			Ok(Value::Null)
121		} else {
122			Ok(format!(
123				"{}{}",
124				String::convert_from(self)?,
125				String::convert_from(other)?
126			)
127			.into())
128		}
129	}
130}