-
Notifications
You must be signed in to change notification settings - Fork 1
/
safe_operations.rs
70 lines (68 loc) · 2.53 KB
/
safe_operations.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/// Has two variants Add and Multiply with no fields, used in the safe_math!() macro
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Operation {
Add,
Multiply
}
/// Allows conversion from bool to Operation and vice versa true means Add, false means Multiply
impl From<bool> for Operation {
fn from(value: bool) -> Self {
match value {
true => Operation::Add,
false => Operation::Multiply
}
}
}
/// Takes three expressions, two number inputs and one variant of the enum Operation. It combines the two numbers in whatever way was chosen or in the case of most errors evaluates to the Err variant with the field containing the larger of the two input numerical expressions
#[macro_export]
macro_rules! safe_math {
($in_x:expr, $in_y:expr, $operation:expr) => {
{
let mut error = false;
let mut set_error = || -> i128 {
error = true;
1
};
if $in_x > 9223372036854775807 || $in_y > 9223372036854775807 {
_ = set_error();
}
let result_x: Result<i128, _> = i128::try_from($in_x);
let x = match result_x {
Ok(v) => v,
Err(_) => set_error()
};
let result_y: Result<i128, _> = i128::try_from($in_y);
let y = match result_y {
Ok(v) => v,
Err(_) => set_error()
};
let returned_value = match x < y {
true => y,
false => x
};
// looks like shit but I don't know how I could do it otherwise with the restrictions of macros
if !error {
match $operation {
Operation::Add => {
let sum: i128 = x+y;
let result_sum = i64::try_from(sum);
match result_sum {
Ok(v) => Result::Ok(v),
Err(_) => Result::Err(returned_value)
}
},
Operation::Multiply => {
let product: i128 = x*y;
let result_product = i64::try_from(product);
match result_product {
Ok(v) => Result::Ok(v),
Err(_) => Result::Err(returned_value)
}
}
}
} else {
Result::Err(returned_value)
}
}
}
}