1use num_traits::{FromPrimitive, Zero};
2use crate::error::*;
3use crate::function::{
4 Associativity, BinaryFunction, Function, Notation, Precedence, UnaryFunction,
5};
6use crate::num::checked::{CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub};
7use crate::Result;
8
9#[cfg(feature = "docs")]
10use crate::descriptions::Description;
11
12pub struct AddOperator;
13impl<N: CheckedAdd> BinaryFunction<N> for AddOperator {
14 fn name(&self) -> &str {
15 "+"
16 }
17
18 fn precedence(&self) -> Precedence {
19 Precedence::LOW
20 }
21
22 fn associativity(&self) -> Associativity {
23 Associativity::Left
24 }
25
26 fn call(&self, left: N, right: N) -> Result<N> {
27 left.checked_add(&right)
28 .ok_or_else(|| Error::from(ErrorKind::Overflow))
29 }
30
31 #[cfg(feature="docs")]
32 fn description(&self) -> Option<&str> {
33 Some(Description::Add.into())
34 }
35}
36
37pub struct SubOperator;
38impl<N: CheckedSub> BinaryFunction<N> for SubOperator {
39 fn name(&self) -> &str {
40 "-"
41 }
42
43 fn precedence(&self) -> Precedence {
44 Precedence::LOW
45 }
46
47 fn associativity(&self) -> Associativity {
48 Associativity::Left
49 }
50
51 fn call(&self, left: N, right: N) -> Result<N> {
52 left.checked_sub(&right)
53 .ok_or_else(|| Error::from(ErrorKind::Overflow))
54 }
55
56 #[cfg(feature="docs")]
57 fn description(&self) -> Option<&str> {
58 Some(Description::Sub.into())
59 }
60}
61
62pub struct MulOperator;
63impl<N: CheckedMul> BinaryFunction<N> for MulOperator {
64 fn name(&self) -> &str {
65 "*"
66 }
67
68 fn precedence(&self) -> Precedence {
69 Precedence::MEDIUM
70 }
71
72 fn associativity(&self) -> Associativity {
73 Associativity::Left
74 }
75
76 fn call(&self, left: N, right: N) -> Result<N> {
77 left.checked_mul(&right)
78 .ok_or_else(|| Error::from(ErrorKind::Overflow))
79 }
80
81 #[cfg(feature="docs")]
82 fn description(&self) -> Option<&str> {
83 Some(Description::Mul.into())
84 }
85}
86
87pub struct DivOperator;
88impl<N: CheckedDiv + Zero> BinaryFunction<N> for DivOperator {
89 fn name(&self) -> &str {
90 "/"
91 }
92
93 fn precedence(&self) -> Precedence {
94 Precedence::MEDIUM
95 }
96
97 fn associativity(&self) -> Associativity {
98 Associativity::Left
99 }
100
101 fn call(&self, left: N, right: N) -> Result<N> {
102 if right.is_zero() {
103 return Err(Error::from(ErrorKind::DivisionByZero));
104 }
105
106 left.checked_div(&right)
107 .ok_or_else(|| Error::from(ErrorKind::Overflow))
108 }
109
110 #[cfg(feature="docs")]
111 fn description(&self) -> Option<&str> {
112 Some(Description::Div.into())
113 }
114}
115
116pub struct ModOperator;
117impl<N: CheckedRem + Zero> BinaryFunction<N> for ModOperator {
118 fn name(&self) -> &str {
119 "mod"
120 }
121
122 fn precedence(&self) -> Precedence {
123 Precedence::MEDIUM
124 }
125
126 fn associativity(&self) -> Associativity {
127 Associativity::Left
128 }
129
130 fn call(&self, left: N, right: N) -> Result<N> {
131 if right.is_zero() {
132 return Err(Error::from(ErrorKind::DivisionByZero));
133 }
134
135 left.checked_rem(&right)
136 .ok_or_else(|| Error::from(ErrorKind::Overflow))
137 }
138
139 #[cfg(feature="docs")]
140 fn description(&self) -> Option<&str> {
141 Some(Description::Mod.into())
142 }
143}
144
145pub struct UnaryMinus;
146impl<N: CheckedNeg> UnaryFunction<N> for UnaryMinus {
147 fn name(&self) -> &str {
148 "-"
149 }
150
151 fn notation(&self) -> Notation {
152 Notation::Prefix
153 }
154
155 fn call(&self, value: N) -> Result<N> {
156 value.checked_neg().ok_or_else(|| Error::from(ErrorKind::Overflow))
157 }
158
159 #[cfg(feature="docs")]
160 fn description(&self) -> Option<&str> {
161 Some(Description::Neg.into())
162 }
163}
164
165pub struct AbsFunction;
166impl<N: Zero + PartialOrd + CheckedNeg + Clone> Function<N> for AbsFunction {
167 fn name(&self) -> &str {
168 "abs"
169 }
170
171 fn call(&self, args: &[N]) -> Result<N> {
172 if args.len() != 1 {
173 Err(Error::from(ErrorKind::InvalidArgumentCount))
174 } else if args[0] >= N::zero() {
175 Ok(args[0].clone())
176 } else {
177 args[0]
178 .checked_neg()
179 .ok_or_else(|| Error::from(ErrorKind::Overflow))
180 }
181 }
182
183 #[cfg(feature="docs")]
184 fn description(&self) -> Option<&str> {
185 Some(Description::Abs.into())
186 }
187}
188
189pub struct SumFunction;
190impl<N: CheckedAdd + Clone> Function<N> for SumFunction {
191 fn name(&self) -> &str {
192 "sum"
193 }
194
195 fn call(&self, args: &[N]) -> Result<N> {
196 let mut result = None;
197
198 for cur in args {
199 match result {
200 None => result = Some(cur.clone()),
201 Some(ref n) => {
202 result = Some(n.checked_add(cur)
203 .ok_or_else(|| Error::from(ErrorKind::Overflow))?);
204 }
205 }
206 }
207
208 result.ok_or_else(|| Error::from(ErrorKind::InvalidArgumentCount))
209 }
210
211 #[cfg(feature="docs")]
212 fn description(&self) -> Option<&str> {
213 Some(Description::Sum.into())
214 }
215}
216
217pub struct ProdFunction;
218impl<N: CheckedMul + Clone> Function<N> for ProdFunction {
219 fn name(&self) -> &str {
220 "product"
221 }
222
223 fn call(&self, args: &[N]) -> Result<N> {
224 let mut result = None;
225
226 for cur in args {
227 match result {
228 None => result = Some(cur.clone()),
229 Some(ref n) => {
230 result = Some(n.checked_mul(cur)
231 .ok_or_else(|| Error::from(ErrorKind::Overflow))?);
232 }
233 }
234 }
235
236 result.ok_or_else(|| Error::from(ErrorKind::InvalidArgumentCount))
237 }
238
239 #[cfg(feature="docs")]
240 fn description(&self) -> Option<&str> {
241 Some(Description::Prod.into())
242 }
243}
244
245pub struct AvgFunction;
246impl<N: CheckedAdd + CheckedDiv + FromPrimitive + Clone> Function<N> for AvgFunction {
247 fn name(&self) -> &str {
248 "avg"
249 }
250
251 fn call(&self, args: &[N]) -> Result<N> {
252 let mut sum = None;
253
254 for cur in args {
255 match sum {
256 None => sum = Some(cur.clone()),
257 Some(ref n) => {
258 sum = Some(n.checked_add(cur)
259 .ok_or_else(|| Error::from(ErrorKind::Overflow))?);
260 }
261 }
262 }
263
264 match sum {
265 Some(n) => {
266 let result = n
267 .checked_div(&N::from_usize(args.len()).unwrap())
268 .ok_or_else(|| Error::from(ErrorKind::Overflow))?;
269
270 Ok(result)
271 }
272 None => Err(Error::from(ErrorKind::InvalidArgumentCount)),
273 }
274 }
275
276 #[cfg(feature="docs")]
277 fn description(&self) -> Option<&str> {
278 Some(Description::Avg.into())
279 }
280}
281
282#[cfg(test)]
283mod tests{
284 use super::*;
285 fn empty_array<T>() -> Box<[T]>{
286 vec![].into_boxed_slice()
287 }
288
289 #[test]
290 fn add_test(){
291 let instance = AddOperator;
292
293 assert_eq!(instance.call(10_f64, 4_f64), Ok(14_f64));
294 assert_eq!(instance.call(3, 7), Ok(10));
295 assert!(instance.call(i32::MAX, 10).is_err());
296 }
297
298 #[test]
299 fn sub_test(){
300 let instance = SubOperator;
301
302 assert_eq!(instance.call(10_f64, 4_f64), Ok(6_f64));
303 assert_eq!(instance.call(3, 7), Ok(-4));
304 assert!(instance.call(i32::MIN, 10).is_err());
305 }
306
307 #[test]
308 fn mul_test(){
309 let instance = MulOperator;
310
311 assert_eq!(instance.call(10_f64, 4_f64), Ok(40_f64));
312 assert_eq!(instance.call(3, 7), Ok(21));
313 assert!(instance.call(i32::MAX, 10).is_err());
314 }
315
316 #[test]
317 fn div_test(){
318 let instance = DivOperator;
319
320 assert_eq!(instance.call(10_f64, 4_f64), Ok(2.5_f64));
321 assert_eq!(instance.call(20, 4), Ok(5));
322 assert!(instance.call(5, 0).is_err());
323 }
324
325 #[test]
326 fn mod_test(){
327 let instance = ModOperator;
328
329 assert_eq!(instance.call(10_f64, 4_f64), Ok(2_f64));
330 assert_eq!(instance.call(20, 4), Ok(0));
331 assert!(instance.call(5, 0).is_err());
332 }
333
334 #[test]
335 fn unary_minus_test(){
336 let instance = UnaryMinus;
337
338 assert_eq!(instance.call(10_f64), Ok(-10_f64));
339 assert_eq!(instance.call(-5), Ok(5));
340
341 assert!(instance.call(i32::MIN).is_err());
342 }
343
344 #[test]
345 fn abs_test(){
346 let instance = AbsFunction;
347
348 assert_eq!(instance.call(&[-5_f64]), Ok(5_f64));
349 assert_eq!(instance.call(&[3]), Ok(3));
350
351 assert!(instance.call(&[i32::MIN]).is_err());
352 }
353
354 #[test]
355 fn sum_test(){
356 let instance = SumFunction;
357
358 assert_eq!(instance.call(&[1_f64, 2_f64, 3_f64]), Ok(6_f64));
359 assert_eq!(instance.call(&[2, 4, 6]), Ok(12));
360
361 assert!(instance.call(&[2]).is_ok());
362 assert!(instance.call(empty_array::<i64>().as_ref()).is_err());
363 assert!(instance.call(&[i32::MAX, 10, 20]).is_err());
364 }
365
366 #[test]
367 fn prod_test(){
368 let instance = ProdFunction;
369
370 assert_eq!(instance.call(&[2_f64, 3_f64, 4_f64]), Ok(24_f64));
371 assert_eq!(instance.call(&[2, 4, 6]), Ok(48));
372
373 assert!(instance.call(&[2]).is_ok());
374 assert!(instance.call(empty_array::<i64>().as_ref()).is_err());
375 assert!(instance.call(&[i32::MAX, 10, 20]).is_err());
376 }
377
378 #[test]
379 fn avg_test(){
380 let instance = AvgFunction;
381
382 assert_eq!(instance.call(&[1_f64, 2_f64, 3_f64, 4_f64]), Ok(2.5_f64));
383 assert_eq!(instance.call(&[2, 4, 6]), Ok(4));
384
385 assert!(instance.call(&[2]).is_ok());
386 assert!(instance.call(empty_array::<i64>().as_ref()).is_err());
387 assert!(instance.call(&[i32::MAX, 10, 20, 30]).is_err());
388 }
389}