sbpf_common/
inst_param.rs1use {
2 core::fmt,
3 serde::{Deserialize, Serialize},
4};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct Register {
8 pub n: u8,
9}
10
11impl fmt::Display for Register {
12 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13 write!(f, "r{}", self.n)
14 }
15}
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub enum Number {
19 Int(i64),
20 Addr(i64),
21}
22
23impl Number {
24 pub fn to_i16(&self) -> i16 {
25 match self {
26 Number::Int(v) => *v as i16,
27 Number::Addr(a) => *a as i16,
28 }
29 }
30
31 pub fn to_i64(&self) -> i64 {
32 match self {
33 Number::Int(v) => *v,
34 Number::Addr(a) => *a,
35 }
36 }
37
38 fn retag(&self, other: &Number, value: i64) -> Number {
39 match (self, other) {
40 (Number::Int(_), Number::Int(_)) => Number::Int(value),
41 _ => Number::Addr(value),
42 }
43 }
44
45 pub fn checked_add(&self, other: &Number) -> Option<Number> {
46 Some(self.retag(other, self.to_i64().checked_add(other.to_i64())?))
47 }
48
49 pub fn checked_sub(&self, other: &Number) -> Option<Number> {
50 Some(self.retag(other, self.to_i64().checked_sub(other.to_i64())?))
51 }
52
53 pub fn checked_mul(&self, other: &Number) -> Option<Number> {
54 Some(self.retag(other, self.to_i64().checked_mul(other.to_i64())?))
55 }
56
57 pub fn checked_div(&self, other: &Number) -> Option<Number> {
58 Some(self.retag(other, self.to_i64().checked_div(other.to_i64())?))
59 }
60}
61
62impl fmt::Display for Number {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 match self {
65 Number::Int(i) => write!(f, "{}", i),
66 Number::Addr(a) => write!(f, "{}", a),
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_register_display() {
77 let reg = Register { n: 5 };
78 assert_eq!(reg.to_string(), "r5");
79
80 let reg0 = Register { n: 0 };
81 assert_eq!(reg0.to_string(), "r0");
82
83 let reg10 = Register { n: 10 };
84 assert_eq!(reg10.to_string(), "r10");
85 }
86
87 #[test]
88 fn test_number_to_i16() {
89 assert_eq!(Number::Int(42).to_i16(), 42i16);
90 assert_eq!(Number::Addr(100).to_i16(), 100i16);
91 assert_eq!(Number::Int(-5).to_i16(), -5i16);
92 }
93
94 #[test]
95 fn test_number_to_i64() {
96 assert_eq!(Number::Int(42).to_i64(), 42i64);
97 assert_eq!(Number::Addr(100).to_i64(), 100i64);
98 assert_eq!(Number::Int(-5).to_i64(), -5i64);
99 }
100
101 #[test]
102 fn test_number_display() {
103 assert_eq!(Number::Int(42).to_string(), "42");
104 assert_eq!(Number::Addr(100).to_string(), "100");
105 assert_eq!(Number::Int(-5).to_string(), "-5");
106 }
107
108 #[test]
109 fn test_number_checked_add() {
110 assert_eq!(
112 Number::Int(10).checked_add(&Number::Int(20)),
113 Some(Number::Int(30))
114 );
115 assert_eq!(
117 Number::Addr(10).checked_add(&Number::Addr(20)),
118 Some(Number::Addr(30))
119 );
120 assert_eq!(
122 Number::Int(10).checked_add(&Number::Addr(20)),
123 Some(Number::Addr(30))
124 );
125 assert_eq!(
126 Number::Addr(10).checked_add(&Number::Int(20)),
127 Some(Number::Addr(30))
128 );
129 }
130
131 #[test]
132 fn test_number_checked_sub() {
133 assert_eq!(
134 Number::Int(30).checked_sub(&Number::Int(10)),
135 Some(Number::Int(20))
136 );
137 assert_eq!(
138 Number::Addr(30).checked_sub(&Number::Int(10)),
139 Some(Number::Addr(20))
140 );
141 }
142
143 #[test]
144 fn test_number_checked_mul() {
145 assert_eq!(
146 Number::Int(5).checked_mul(&Number::Int(4)),
147 Some(Number::Int(20))
148 );
149 assert_eq!(
150 Number::Addr(5).checked_mul(&Number::Int(4)),
151 Some(Number::Addr(20))
152 );
153 }
154
155 #[test]
156 fn test_number_checked_div() {
157 assert_eq!(
158 Number::Int(20).checked_div(&Number::Int(4)),
159 Some(Number::Int(5))
160 );
161 assert_eq!(
162 Number::Addr(20).checked_div(&Number::Int(4)),
163 Some(Number::Addr(5))
164 );
165 }
166
167 #[test]
168 fn test_number_checked_arithmetic_reports_overflow() {
169 assert_eq!(Number::Int(i64::MAX).checked_add(&Number::Int(1)), None);
171 assert_eq!(Number::Int(i64::MIN).checked_sub(&Number::Int(1)), None);
172 assert_eq!(Number::Int(i64::MAX).checked_mul(&Number::Int(2)), None);
173 assert_eq!(Number::Int(i64::MIN).checked_div(&Number::Int(-1)), None);
175 }
176
177 #[test]
178 fn test_number_checked_div_by_zero() {
179 assert_eq!(Number::Int(8).checked_div(&Number::Int(0)), None);
180 assert_eq!(Number::Addr(8).checked_div(&Number::Int(0)), None);
181 }
182}