Skip to main content

mithril_common/entities/
block_number.rs

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/// BlockNumber is the block number of a Cardano transaction.
14#[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
39// Useful for conversion to sqlite number (that use i64)
40impl 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}