1use std::fmt::{Display, Formatter};
2use std::num::TryFromIntError;
3use std::ops::{Deref, DerefMut};
4
5use serde::{Deserialize, Serialize};
6
7use crate::entities::BlockNumberOffset;
8use crate::entities::arithmetic_operation_wrapper::{
9 impl_add_to_wrapper, impl_div_to_wrapper, impl_mul_to_wrapper, impl_partial_eq_to_wrapper,
10 impl_rem_to_wrapper, impl_sub_to_wrapper,
11};
12
13#[derive(
15 Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash,
16)]
17pub struct BlockNumber(pub u64);
18
19impl Display for BlockNumber {
20 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21 write!(f, "{}", self.0)
22 }
23}
24
25impl Deref for BlockNumber {
26 type Target = u64;
27
28 fn deref(&self) -> &Self::Target {
29 &self.0
30 }
31}
32
33impl DerefMut for BlockNumber {
34 fn deref_mut(&mut self) -> &mut Self::Target {
35 &mut self.0
36 }
37}
38
39impl TryFrom<BlockNumber> for i64 {
41 type Error = TryFromIntError;
42
43 fn try_from(value: BlockNumber) -> Result<Self, Self::Error> {
44 value.0.try_into()
45 }
46}
47
48impl_add_to_wrapper!(BlockNumber, u64);
49impl_sub_to_wrapper!(BlockNumber, u64);
50impl_mul_to_wrapper!(BlockNumber, u64);
51impl_div_to_wrapper!(BlockNumber, u64);
52impl_rem_to_wrapper!(BlockNumber, u64);
53impl_partial_eq_to_wrapper!(BlockNumber, u64);
54
55impl Add<BlockNumberOffset> for BlockNumber {
56 type Output = Self;
57
58 fn add(self, rhs: BlockNumberOffset) -> Self::Output {
59 self + *rhs
60 }
61}
62
63impl AddAssign<BlockNumberOffset> for BlockNumber {
64 fn add_assign(&mut self, rhs: BlockNumberOffset) {
65 *self = *self + rhs;
66 }
67}
68
69impl Sub<BlockNumberOffset> for BlockNumber {
70 type Output = Self;
71
72 fn sub(self, rhs: BlockNumberOffset) -> Self::Output {
73 self - *rhs
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use crate::entities::arithmetic_operation_wrapper::tests::test_op_assign;
80
81 use super::*;
82
83 #[test]
84 fn test_display() {
85 assert_eq!(format!("{}", BlockNumber(72)), "72");
86 assert_eq!(format!("{}", &BlockNumber(13224)), "13224");
87 }
88
89 #[test]
90 fn test_serialize() {
91 assert_eq!(serde_json::to_string(&BlockNumber(72)).unwrap(), "72");
92 }
93
94 #[test]
95 fn test_deserialize() {
96 let block_number: BlockNumber = serde_json::from_str("13224").unwrap();
97 assert_eq!(block_number, BlockNumber(13224));
98 }
99
100 #[test]
101 #[allow(clippy::op_ref)]
102 fn test_add() {
103 assert_eq!(BlockNumber(4), BlockNumber(1) + BlockNumber(3));
104 assert_eq!(BlockNumber(4), BlockNumber(1) + 3_u64);
105 assert_eq!(BlockNumber(4), BlockNumber(1) + &3_u64);
106
107 assert_eq!(BlockNumber(4), 3_u64 + BlockNumber(1));
108 assert_eq!(BlockNumber(4), 3_u64 + &BlockNumber(1));
109 assert_eq!(BlockNumber(4), &3_u64 + BlockNumber(1));
110 assert_eq!(BlockNumber(4), &3_u64 + &BlockNumber(1));
111
112 test_op_assign!(BlockNumber(1), +=, BlockNumber(3) => BlockNumber(4));
113 test_op_assign!(BlockNumber(1), +=, 3_u64 => BlockNumber(4));
114 test_op_assign!(BlockNumber(1), +=, &3_u64 => BlockNumber(4));
115
116 test_op_assign!(1_u64, +=, BlockNumber(3) => 4_u64);
117 test_op_assign!(1_u64, +=, &BlockNumber(3) => 4_u64);
118 }
119
120 #[test]
121 #[allow(clippy::op_ref)]
122 fn test_sub() {
123 assert_eq!(BlockNumber(8), BlockNumber(14) - BlockNumber(6));
124 assert_eq!(BlockNumber(8), BlockNumber(14) - 6_u64);
125 assert_eq!(BlockNumber(8), BlockNumber(14) - &6_u64);
126
127 assert_eq!(BlockNumber(8), 6_u64 - BlockNumber(14));
128 assert_eq!(BlockNumber(8), 6_u64 - &BlockNumber(14));
129 assert_eq!(BlockNumber(8), &6_u64 - BlockNumber(14));
130 assert_eq!(BlockNumber(8), &6_u64 - &BlockNumber(14));
131
132 test_op_assign!(BlockNumber(14), -=, BlockNumber(6) => BlockNumber(8));
133 test_op_assign!(BlockNumber(14), -=, 6_u64 => BlockNumber(8));
134 test_op_assign!(BlockNumber(14), -=, &6_u64 => BlockNumber(8));
135
136 test_op_assign!(14_u64, -=, BlockNumber(6) => 8_u64);
137 test_op_assign!(14_u64, -=, &BlockNumber(6) => 8_u64);
138 }
139
140 #[test]
141 fn saturating_sub() {
142 assert_eq!(BlockNumber(0), BlockNumber(1) - BlockNumber(5));
143 assert_eq!(BlockNumber(0), BlockNumber(1) - 5_u64);
144 }
145
146 #[test]
147 #[allow(clippy::op_ref)]
148 fn test_mul() {
149 assert_eq!(BlockNumber(6), BlockNumber(2) * BlockNumber(3));
150 assert_eq!(BlockNumber(6), BlockNumber(2) * 3_u64);
151 assert_eq!(BlockNumber(6), BlockNumber(2) * &3_u64);
152
153 assert_eq!(BlockNumber(6), 3_u64 * BlockNumber(2));
154 assert_eq!(BlockNumber(6), 3_u64 * &BlockNumber(2));
155 assert_eq!(BlockNumber(6), &3_u64 * BlockNumber(2));
156 assert_eq!(BlockNumber(6), &3_u64 * &BlockNumber(2));
157
158 test_op_assign!(BlockNumber(2), *=, BlockNumber(3) => BlockNumber(6));
159 test_op_assign!(BlockNumber(2), *=, 3_u64 => BlockNumber(6));
160 test_op_assign!(BlockNumber(2), *=, &3_u64 => BlockNumber(6));
161
162 test_op_assign!(2_u64, *=, BlockNumber(3) => 6_u64);
163 test_op_assign!(2_u64, *=, &BlockNumber(3) => 6_u64);
164 }
165
166 #[test]
167 #[allow(clippy::op_ref)]
168 fn test_div() {
169 assert_eq!(BlockNumber(6), BlockNumber(18) / BlockNumber(3));
170 assert_eq!(BlockNumber(6), BlockNumber(18) / 3_u64);
171 assert_eq!(BlockNumber(6), BlockNumber(18) / &3_u64);
172
173 assert_eq!(BlockNumber(6), 12_u64 / BlockNumber(2));
174 assert_eq!(BlockNumber(6), 12_u64 / &BlockNumber(2));
175 assert_eq!(BlockNumber(6), &12_u64 / BlockNumber(2));
176 assert_eq!(BlockNumber(6), &12_u64 / &BlockNumber(2));
177
178 test_op_assign!(BlockNumber(18), /=, BlockNumber(3) => BlockNumber(6));
179 test_op_assign!(BlockNumber(18), /=, 3_u64 => BlockNumber(6));
180 test_op_assign!(BlockNumber(18), /=, &3_u64 => BlockNumber(6));
181
182 test_op_assign!(18_u64, /=, BlockNumber(3) => 6_u64);
183 test_op_assign!(18_u64, /=, &BlockNumber(3) => 6_u64);
184 }
185
186 #[test]
187 #[allow(clippy::op_ref)]
188 fn test_rem() {
189 assert_eq!(BlockNumber(3), BlockNumber(18) % BlockNumber(5));
190 assert_eq!(BlockNumber(3), BlockNumber(18) % 5_u64);
191 assert_eq!(BlockNumber(3), BlockNumber(18) % &5_u64);
192
193 assert_eq!(BlockNumber(6), 20_u64 % BlockNumber(7));
194 assert_eq!(BlockNumber(6), 20_u64 % &BlockNumber(7));
195 assert_eq!(BlockNumber(6), &20_u64 % BlockNumber(7));
196 assert_eq!(BlockNumber(6), &20_u64 % &BlockNumber(7));
197
198 test_op_assign!(BlockNumber(18), %=, BlockNumber(5) => BlockNumber(3));
199 test_op_assign!(BlockNumber(18), %=, 5_u64 => BlockNumber(3));
200 test_op_assign!(BlockNumber(18), %=, &5_u64 => BlockNumber(3));
201
202 test_op_assign!(18_u64, %=, BlockNumber(5) => 3_u64);
203 test_op_assign!(18_u64, %=, &BlockNumber(5) => 3_u64);
204 }
205
206 #[test]
207 fn test_eq() {
208 assert_eq!(BlockNumber(1), BlockNumber(1));
209 assert_eq!(BlockNumber(2), &BlockNumber(2));
210 assert_eq!(&BlockNumber(3), BlockNumber(3));
211 assert_eq!(&BlockNumber(4), &BlockNumber(4));
212
213 assert_eq!(BlockNumber(5), 5);
214 assert_eq!(BlockNumber(6), &6);
215 assert_eq!(&BlockNumber(7), 7);
216 assert_eq!(&BlockNumber(8), &8);
217
218 assert_eq!(9, BlockNumber(9));
219 assert_eq!(10, &BlockNumber(10));
220 assert_eq!(&11, BlockNumber(11));
221 assert_eq!(&12, &BlockNumber(12));
222 }
223
224 #[test]
225 fn test_add_block_number_offset_to_block_number() {
226 assert_eq!(BlockNumber(4), BlockNumber(1) + BlockNumberOffset(3));
227 }
228
229 #[test]
230 fn test_sub_block_number_offset_from_block_number() {
231 assert_eq!(BlockNumber(1), BlockNumber(4) - BlockNumberOffset(3));
232 }
233
234 #[test]
235 fn test_add_asign_block_number_offset() {
236 test_op_assign!(BlockNumber(1), +=, BlockNumberOffset(3) => BlockNumber(4));
237 test_op_assign!(BlockNumber(1), +=, BlockNumberOffset(3) => &BlockNumber(4));
238 test_op_assign!(BlockNumber(1), +=, 3 => BlockNumber(4));
239 test_op_assign!(BlockNumber(1), +=, &3 => BlockNumber(4));
240 }
241
242 #[test]
243 fn test_add_asign_block_number_to_block_number_offset() {
244 test_op_assign!(BlockNumberOffset(1), +=, BlockNumber(3) => BlockNumberOffset(4));
245 test_op_assign!(BlockNumberOffset(1), +=, BlockNumber(3) => &BlockNumberOffset(4));
246 }
247}