dsq_shared/ops/
utils.rs

1//! Operation utilities
2//!
3//! This module contains helper functions used by multiple operation types.
4
5#![allow(clippy::cast_precision_loss)]
6
7use crate::value::Value;
8use crate::Result;
9
10/// Compare two values for ordering
11pub 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        // Cross-type numeric comparisons
27        (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        // For complex types, compare string representations
35        _ => 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
43/// Add two values
44pub 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            // Add scalar to series
53            let result = s + *y;
54            Ok(Value::Series(result))
55        }
56        (Value::Series(s), Value::Float(y)) => {
57            // Add scalar to series
58            let result = s + *y;
59            Ok(Value::Series(result))
60        }
61        (Value::Int(x), Value::Series(s)) => {
62            // Add scalar to series
63            let result = s + *x;
64            Ok(Value::Series(result))
65        }
66        (Value::Float(x), Value::Series(s)) => {
67            // Add scalar to series
68            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
79/// Subtract two values
80pub 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
94/// Multiply two values
95pub 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
109/// Divide two values
110pub 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}