rigz_vm/value/
shl.rs

1use crate::number::Number;
2use crate::value::Value;
3use crate::VMError;
4use std::ops::Shl;
5
6impl Shl for &Value {
7    type Output = Value;
8
9    #[inline]
10    fn shl(self, rhs: Self) -> Self::Output {
11        match (self, rhs) {
12            (Value::Error(v), _) | (_, Value::Error(v)) => Value::Error(v.clone()),
13            (Value::Type(t), a) | (a, Value::Type(t)) => Value::Error(
14                VMError::UnsupportedOperation(format!("Invalid Operation (<<): {t} and {a}")),
15            ),
16            (Value::None, _) => Value::None,
17            (lhs, Value::None) => lhs.clone(),
18            (rhs, &Value::Bool(b)) => {
19                if b {
20                    rhs << &Value::Number(Number::Int(1))
21                } else {
22                    rhs.clone()
23                }
24            }
25            (&Value::Bool(lhs), Value::Number(rhs)) => {
26                if lhs {
27                    Value::Number(&Number::Int(1) >> rhs)
28                } else {
29                    Value::Number(Number::Int(0))
30                }
31            }
32            (Value::Number(lhs), Value::Number(rhs)) => Value::Number(lhs << rhs),
33            (Value::Number(a), Value::String(b)) => {
34                let s = Value::String(b.clone());
35                match s.to_number() {
36                    Err(_) => VMError::UnsupportedOperation(format!("{} << {}", a, b)).to_value(),
37                    Ok(r) => Value::Number(a << &r),
38                }
39            }
40            (Value::String(lhs), Value::Number(rhs)) => {
41                let lhs = lhs.as_str();
42                let s = if rhs.is_negative() {
43                    lhs[..=rhs.to_int().unsigned_abs() as usize].to_string()
44                } else {
45                    lhs[rhs.to_usize().unwrap()..].to_string()
46                };
47                Value::String(s)
48            }
49            (Value::String(lhs), Value::String(rhs)) => {
50                let mut res = lhs.clone();
51                res.push_str(rhs.as_str());
52                Value::String(res)
53            }
54            (Value::Tuple(a), Value::Tuple(b)) => {
55                Value::Tuple(a.iter().zip(b).map(|(a, b)| a << b).collect())
56            }
57            (Value::Tuple(a), b) => Value::Tuple(a.iter().map(|a| a << b).collect()),
58            (b, Value::Tuple(a)) => Value::Tuple(a.iter().map(|a| b << a).collect()),
59            (lhs, rhs) => {
60                VMError::UnsupportedOperation(format!("Not supported: {lhs} << {rhs}")).into()
61            }
62        }
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::define_value_tests;
69
70    define_value_tests! {
71        << {
72            test_none_shl_none => ((), ()) = ();
73            test_none_bool_false_shl_none => (false, ()) = false;
74            test_bool_true_shl_none => (true, ()) = true;
75            test_none_bool_true_shl_true => ((), true) = ();
76            test_false_bool_true_shl_true => (false, true) = 0;
77            test_false_0_shl_true => (false, 0) = false;
78            test_true_0_shl_true => (true, 0) = 1;
79            push_to_end => ("abc", "123") = "abc123";
80            int_like => (1, 2.0) = (1 << 2);
81        }
82    }
83}