1#![allow(clippy::cast_precision_loss)]
6
7use crate::value::Value;
8use crate::Result;
9
10pub fn compare_values(a: &Value, b: &Value) -> Result<std::cmp::Ordering> {
12 use std::cmp::Ordering;
13
14 match (a, b) {
15 (Value::Null, Value::Null) => Ok(Ordering::Equal),
16 (Value::Null, _) => Ok(Ordering::Less),
17 (_, Value::Null) => Ok(Ordering::Greater),
18
19 (Value::Bool(a), Value::Bool(b)) => Ok(a.cmp(b)),
20 (Value::Int(a), Value::Int(b)) => Ok(a.cmp(b)),
21 (Value::Float(a), Value::Float(b)) => a
22 .partial_cmp(b)
23 .ok_or_else(|| crate::error::operation_error("Cannot compare NaN values")),
24 (Value::String(a), Value::String(b)) => Ok(a.cmp(b)),
25
26 (Value::Int(a), Value::Float(b)) => (*a as f64)
28 .partial_cmp(b)
29 .ok_or_else(|| crate::error::operation_error("Cannot compare NaN values")),
30 (Value::Float(a), Value::Int(b)) => a
31 .partial_cmp(&(*b as f64))
32 .ok_or_else(|| crate::error::operation_error("Cannot compare NaN values")),
33
34 _ => Err(crate::error::operation_error(format!(
36 "Cannot compare values of types {} and {}",
37 a.type_name(),
38 b.type_name()
39 ))),
40 }
41}
42
43pub fn add_values(a: &Value, b: &Value) -> Result<Value> {
45 match (a, b) {
46 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
47 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
48 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 + *y)),
49 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(*x + *y as f64)),
50 (Value::String(x), Value::String(y)) => Ok(Value::String(format!("{}{}", x, y))),
51 (Value::Series(s), Value::Int(y)) => {
52 let result = s + *y;
54 Ok(Value::Series(result))
55 }
56 (Value::Series(s), Value::Float(y)) => {
57 let result = s + *y;
59 Ok(Value::Series(result))
60 }
61 (Value::Int(x), Value::Series(s)) => {
62 let result = s + *x;
64 Ok(Value::Series(result))
65 }
66 (Value::Float(x), Value::Series(s)) => {
67 let result = s + *x;
69 Ok(Value::Series(result))
70 }
71 _ => Err(crate::error::operation_error(format!(
72 "Cannot add {} and {}",
73 a.type_name(),
74 b.type_name()
75 ))),
76 }
77}
78
79pub fn sub_values(a: &Value, b: &Value) -> Result<Value> {
81 match (a, b) {
82 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
83 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
84 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 - *y)),
85 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(*x - *y as f64)),
86 _ => Err(crate::error::operation_error(format!(
87 "Cannot subtract {} and {}",
88 a.type_name(),
89 b.type_name()
90 ))),
91 }
92}
93
94pub fn mul_values(a: &Value, b: &Value) -> Result<Value> {
96 match (a, b) {
97 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
98 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
99 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 * *y)),
100 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(*x * *y as f64)),
101 _ => Err(crate::error::operation_error(format!(
102 "Cannot multiply {} and {}",
103 a.type_name(),
104 b.type_name()
105 ))),
106 }
107}
108
109pub fn div_values(a: &Value, b: &Value) -> Result<Value> {
111 let b_float = match b {
112 Value::Int(y) if *y == 0 => return Err(crate::error::operation_error("Division by zero")),
113 Value::Float(y) if *y == 0.0 => {
114 return Err(crate::error::operation_error("Division by zero"));
115 }
116 Value::Int(y) => *y as f64,
117 Value::Float(y) => *y,
118 _ => {
119 return Err(crate::error::operation_error(format!(
120 "Cannot divide by {}",
121 b.type_name()
122 )));
123 }
124 };
125 match a {
126 Value::Int(x) => Ok(Value::Float(*x as f64 / b_float)),
127 Value::Float(x) => Ok(Value::Float(*x / b_float)),
128 _ => Err(crate::error::operation_error(format!(
129 "Cannot divide {} by number",
130 a.type_name()
131 ))),
132 }
133}