1use crate::ops::{Add, AsProxy};
2use crate::ops_macros::{impl_numeric_binary_op, impl_same_type_binary_op, impl_value_binary_op};
3use rbs::Value;
4
5fn op_add_u64(value: &Value, other: u64) -> u64 {
6 value.u64() + other
7}
8
9fn op_add_i64(value: &Value, other: i64) -> i64 {
10 value.i64() + other
11}
12
13fn op_add_f64(value: &Value, other: f64) -> f64 {
14 value.f64() + other
15}
16
17fn op_add_value(left: Value, rhs: Value) -> Value {
18 match left {
19 Value::String(s) => Value::String(s + rhs.as_str().unwrap_or("")),
20 Value::I32(s) => Value::I32(s + rhs.i32()),
21 Value::I64(s) => Value::I64(s + rhs.i64()),
22 Value::U32(s) => Value::U32(s + rhs.u32()),
23 Value::U64(s) => Value::U64(s + rhs.u64()),
24 Value::F64(s) => Value::F64(s + rhs.f64()),
25 Value::F32(v) => Value::F32(v + rhs.f64() as f32),
26 Value::Ext(_, e) => op_add_value(*e, rhs),
27 _ => Value::Null,
28 }
29}
30
31impl_value_binary_op!(Add, op_add, op_add_value);
32impl_numeric_binary_op!(
33 Add,
34 op_add,
35 op_add_u64,
36 op_add_u64,
37 [u8, u16, u32, u64],
38 u64
39);
40impl_numeric_binary_op!(
41 Add,
42 op_add,
43 op_add_i64,
44 op_add_i64,
45 [i8, i16, i32, i64, isize, usize],
46 i64
47);
48impl_numeric_binary_op!(Add, op_add, op_add_f64, op_add_f64, [f32, f64], f64);
49impl_same_type_binary_op!(
50 Add,
51 op_add,
52 +,
53 [
54 u8, u16, u32, u64, i8, i16, i32, i64, isize, usize, f32, f64
55 ]
56);
57
58macro_rules! impl_value_string_add {
59 ($($rhs:ty),* $(,)?) => {
60 $(
61 impl Add<$rhs> for Value {
62 type Output = Value;
63
64 fn op_add(self, rhs: $rhs) -> Self::Output {
65 Value::String(self.string() + &rhs.to_string())
66 }
67 }
68
69 impl Add<$rhs> for &Value {
70 type Output = Value;
71
72 fn op_add(self, rhs: $rhs) -> Self::Output {
73 Value::String(self.string() + &rhs.to_string())
74 }
75 }
76
77 impl Add<$rhs> for &&Value {
78 type Output = Value;
79
80 fn op_add(self, rhs: $rhs) -> Self::Output {
81 Value::String(self.string() + &rhs.to_string())
82 }
83 }
84 )*
85 };
86}
87
88impl_value_string_add!(&str, &&str, String, &String, &&String);
89
90macro_rules! impl_string_value_add {
91 ($($lhs:ty),* $(,)?) => {
92 $(
93 impl Add<Value> for $lhs {
94 type Output = String;
95
96 fn op_add(self, rhs: Value) -> Self::Output {
97 self.to_string() + &rhs.string()
98 }
99 }
100
101 impl Add<&Value> for $lhs {
102 type Output = String;
103
104 fn op_add(self, rhs: &Value) -> Self::Output {
105 self.to_string() + &rhs.string()
106 }
107 }
108
109 impl Add<&&Value> for $lhs {
110 type Output = String;
111
112 fn op_add(self, rhs: &&Value) -> Self::Output {
113 self.to_string() + &rhs.string()
114 }
115 }
116 )*
117 };
118}
119
120impl_string_value_add!(&str, &&str, String, &String, &&String);
121
122impl Add<&str> for String {
123 type Output = String;
124
125 fn op_add(self, rhs: &str) -> Self::Output {
126 self + rhs
127 }
128}
129
130impl Add<&&str> for String {
131 type Output = String;
132
133 fn op_add(self, rhs: &&str) -> Self::Output {
134 self + *rhs
135 }
136}
137
138impl Add<String> for String {
139 type Output = String;
140
141 fn op_add(self, rhs: String) -> Self::Output {
142 self + &rhs
143 }
144}
145
146impl Add<&String> for String {
147 type Output = String;
148
149 fn op_add(self, rhs: &String) -> Self::Output {
150 self + rhs.as_str()
151 }
152}
153
154impl Add<&&String> for String {
155 type Output = String;
156
157 fn op_add(self, rhs: &&String) -> Self::Output {
158 self + rhs.as_str()
159 }
160}
161
162impl Add<String> for &str {
163 type Output = String;
164
165 fn op_add(self, rhs: String) -> Self::Output {
166 self.to_string() + &rhs
167 }
168}
169
170impl Add<&String> for &str {
171 type Output = String;
172
173 fn op_add(self, rhs: &String) -> Self::Output {
174 self.to_string() + rhs.as_str()
175 }
176}
177
178impl Add<&&String> for &str {
179 type Output = String;
180
181 fn op_add(self, rhs: &&String) -> Self::Output {
182 self.to_string() + rhs.as_str()
183 }
184}
185
186impl Add<&str> for &str {
187 type Output = String;
188
189 fn op_add(self, rhs: &str) -> Self::Output {
190 self.to_string() + rhs
191 }
192}
193
194impl Add<&&str> for &str {
195 type Output = String;
196
197 fn op_add(self, rhs: &&str) -> Self::Output {
198 self.to_string() + rhs
199 }
200}
201
202impl Add<&str> for &&str {
203 type Output = String;
204
205 fn op_add(self, rhs: &str) -> Self::Output {
206 self.to_string() + rhs
207 }
208}
209
210impl Add<&&str> for &&str {
211 type Output = String;
212
213 fn op_add(self, rhs: &&str) -> Self::Output {
214 self.to_string() + rhs
215 }
216}
217
218#[cfg(test)]
219mod test {
220 use crate::ops::Add;
221 use rbs::{value, Value};
222
223 #[test]
224 fn test_add() {
225 let i: i64 = 1;
226 let v = value!(1);
227 assert_eq!((&v).op_add(&i), 2i64);
228 assert_eq!(v.op_add(&i), 2i64);
229 assert_eq!(Value::I32(1).op_add(&&Value::I32(2)), Value::I32(3));
230 }
231
232 #[test]
233 fn test_string_reference_matrix() {
234 let value = Value::String("left".to_string());
235 assert_eq!(
236 value.op_add("right"),
237 Value::String("leftright".to_string())
238 );
239 assert_eq!(
240 (&Value::String("left".to_string())).op_add("right"),
241 Value::String("leftright".to_string())
242 );
243 assert_eq!(
244 "left".op_add(&Value::String("right".to_string())),
245 "leftright"
246 );
247 }
248}