1use bigdecimal::Signed;
2use num_bigint::BigInt;
3
4use crate::error::{DogeError, DogeResult};
5use crate::value::Value;
6
7fn int_pair<'a>(sym: &str, a: &'a Value, b: &'a Value) -> DogeResult<(&'a BigInt, &'a BigInt)> {
10 match (a, b) {
11 (Value::Int(x), Value::Int(y)) => Ok((x, y)),
12 _ => Err(DogeError::type_error(format!(
13 "cannot {sym} {} and {} (bitwise operators need Ints)",
14 a.describe(),
15 b.describe()
16 ))),
17 }
18}
19
20fn shift_count(y: &BigInt) -> DogeResult<usize> {
25 if y.is_negative() {
26 return Err(DogeError::value_error(format!(
27 "cannot shift by {y} — the shift count must be 0 or more"
28 )));
29 }
30 usize::try_from(y).map_err(|_| {
31 DogeError::value_error(format!(
32 "cannot shift by {y} — the shift count is too large"
33 ))
34 })
35}
36
37pub fn bitand(a: Value, b: Value) -> DogeResult {
39 let (x, y) = int_pair("&", &a, &b)?;
40 Ok(Value::int(x & y))
41}
42
43pub fn bitor(a: Value, b: Value) -> DogeResult {
45 let (x, y) = int_pair("|", &a, &b)?;
46 Ok(Value::int(x | y))
47}
48
49pub fn bitxor(a: Value, b: Value) -> DogeResult {
51 let (x, y) = int_pair("^", &a, &b)?;
52 Ok(Value::int(x ^ y))
53}
54
55pub fn shl(a: Value, b: Value) -> DogeResult {
58 let (x, y) = int_pair("<<", &a, &b)?;
59 let n = shift_count(y)?;
60 Ok(Value::int(x << n))
61}
62
63pub fn shr(a: Value, b: Value) -> DogeResult {
67 let (x, y) = int_pair(">>", &a, &b)?;
68 if y.is_negative() {
69 return Err(DogeError::value_error(format!(
70 "cannot shift by {y} — the shift count must be 0 or more"
71 )));
72 }
73 match usize::try_from(y) {
76 Ok(n) => Ok(Value::int(x >> n)),
77 Err(_) => Ok(Value::int(if x.is_negative() {
78 BigInt::from(-1)
79 } else {
80 BigInt::from(0)
81 })),
82 }
83}
84
85pub fn bitnot(a: Value) -> DogeResult {
87 match &a {
88 Value::Int(n) => Ok(Value::int(!n)),
89 _ => Err(DogeError::type_error(format!(
90 "cannot ~ {} (bitwise NOT needs an Int)",
91 a.describe()
92 ))),
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::error::ErrorKind;
100 use crate::ops::compare::values_equal;
101
102 fn int(n: i64) -> Value {
103 Value::int(n)
104 }
105
106 #[test]
107 fn basic_bitwise() {
108 assert!(values_equal(
109 &bitand(int(0b1100), int(0b1010)).unwrap(),
110 &int(0b1000)
111 ));
112 assert!(values_equal(
113 &bitor(int(0b1100), int(0b1010)).unwrap(),
114 &int(0b1110)
115 ));
116 assert!(values_equal(
117 &bitxor(int(0b1100), int(0b1010)).unwrap(),
118 &int(0b0110)
119 ));
120 assert!(values_equal(&bitnot(int(0)).unwrap(), &int(-1)));
121 assert!(values_equal(&bitnot(int(5)).unwrap(), &int(-6)));
122 }
123
124 #[test]
125 fn shifts() {
126 assert!(values_equal(&shl(int(1), int(4)).unwrap(), &int(16)));
127 assert!(values_equal(&shr(int(16), int(4)).unwrap(), &int(1)));
128 assert!(values_equal(&shr(int(-8), int(1)).unwrap(), &int(-4)));
130 assert!(values_equal(&shr(int(-8), int(200)).unwrap(), &int(-1)));
132 assert!(values_equal(&shr(int(8), int(200)).unwrap(), &int(0)));
133 }
134
135 #[test]
136 fn left_shift_grows_instead_of_overflowing() {
137 let two_pow_64: BigInt = BigInt::from(1) << 64u32;
139 assert!(values_equal(
140 &shl(int(1), int(64)).unwrap(),
141 &Value::int(two_pow_64)
142 ));
143 }
144
145 #[test]
146 fn shift_errors() {
147 assert_eq!(
148 shl(int(-1), int(-1)).unwrap_err().kind,
149 ErrorKind::ValueError
150 );
151 assert_eq!(
152 shr(int(1), int(-1)).unwrap_err().kind,
153 ErrorKind::ValueError
154 );
155 }
156
157 #[test]
158 fn non_int_is_a_type_error() {
159 assert_eq!(
160 bitand(int(1), Value::str("x")).unwrap_err().kind,
161 ErrorKind::TypeError
162 );
163 assert_eq!(
164 bitnot(Value::str("x")).unwrap_err().kind,
165 ErrorKind::TypeError
166 );
167 }
168}