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::arithmetic_operation_wrapper::{
8    impl_add_to_wrapper, impl_div_to_wrapper, impl_mul_to_wrapper, impl_partial_eq_to_wrapper,
9    impl_rem_to_wrapper, impl_sub_to_wrapper,
10};
11
12#[cfg(target_family = "wasm")]
13use wasm_bindgen::prelude::*;
14
15/// BlockNumber is the block number of a Cardano transaction.
16#[derive(
17    Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash,
18)]
19#[cfg_attr(target_family = "wasm", wasm_bindgen)]
20pub struct BlockNumber(pub u64);
21
22impl Display for BlockNumber {
23    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24        write!(f, "{}", self.0)
25    }
26}
27
28impl Deref for BlockNumber {
29    type Target = u64;
30
31    fn deref(&self) -> &Self::Target {
32        &self.0
33    }
34}
35
36impl DerefMut for BlockNumber {
37    fn deref_mut(&mut self) -> &mut Self::Target {
38        &mut self.0
39    }
40}
41
42// Useful for conversion to sqlite number (that use i64)
43impl TryFrom<BlockNumber> for i64 {
44    type Error = TryFromIntError;
45
46    fn try_from(value: BlockNumber) -> Result<Self, Self::Error> {
47        value.0.try_into()
48    }
49}
50
51impl_add_to_wrapper!(BlockNumber, u64);
52impl_sub_to_wrapper!(BlockNumber, u64);
53impl_mul_to_wrapper!(BlockNumber, u64);
54impl_div_to_wrapper!(BlockNumber, u64);
55impl_rem_to_wrapper!(BlockNumber, u64);
56impl_partial_eq_to_wrapper!(BlockNumber, u64);
57
58#[cfg(test)]
59mod tests {
60    use crate::entities::arithmetic_operation_wrapper::tests::test_op_assign;
61
62    use super::*;
63
64    #[test]
65    fn test_display() {
66        assert_eq!(format!("{}", BlockNumber(72)), "72");
67        assert_eq!(format!("{}", &BlockNumber(13224)), "13224");
68    }
69
70    #[test]
71    fn test_serialize() {
72        assert_eq!(serde_json::to_string(&BlockNumber(72)).unwrap(), "72");
73    }
74
75    #[test]
76    fn test_deserialize() {
77        let block_number: BlockNumber = serde_json::from_str("13224").unwrap();
78        assert_eq!(block_number, BlockNumber(13224));
79    }
80
81    #[test]
82    #[allow(clippy::op_ref)]
83    fn test_add() {
84        assert_eq!(BlockNumber(4), BlockNumber(1) + BlockNumber(3));
85        assert_eq!(BlockNumber(4), BlockNumber(1) + 3_u64);
86        assert_eq!(BlockNumber(4), BlockNumber(1) + &3_u64);
87
88        assert_eq!(BlockNumber(4), 3_u64 + BlockNumber(1));
89        assert_eq!(BlockNumber(4), 3_u64 + &BlockNumber(1));
90        assert_eq!(BlockNumber(4), &3_u64 + BlockNumber(1));
91        assert_eq!(BlockNumber(4), &3_u64 + &BlockNumber(1));
92
93        test_op_assign!(BlockNumber(1), +=, BlockNumber(3) => BlockNumber(4));
94        test_op_assign!(BlockNumber(1), +=, 3_u64 => BlockNumber(4));
95        test_op_assign!(BlockNumber(1), +=, &3_u64 => BlockNumber(4));
96
97        test_op_assign!(1_u64, +=, BlockNumber(3) => 4_u64);
98        test_op_assign!(1_u64, +=, &BlockNumber(3) => 4_u64);
99    }
100
101    #[test]
102    #[allow(clippy::op_ref)]
103    fn test_sub() {
104        assert_eq!(BlockNumber(8), BlockNumber(14) - BlockNumber(6));
105        assert_eq!(BlockNumber(8), BlockNumber(14) - 6_u64);
106        assert_eq!(BlockNumber(8), BlockNumber(14) - &6_u64);
107
108        assert_eq!(BlockNumber(8), 6_u64 - BlockNumber(14));
109        assert_eq!(BlockNumber(8), 6_u64 - &BlockNumber(14));
110        assert_eq!(BlockNumber(8), &6_u64 - BlockNumber(14));
111        assert_eq!(BlockNumber(8), &6_u64 - &BlockNumber(14));
112
113        test_op_assign!(BlockNumber(14), -=, BlockNumber(6) => BlockNumber(8));
114        test_op_assign!(BlockNumber(14), -=, 6_u64 => BlockNumber(8));
115        test_op_assign!(BlockNumber(14), -=, &6_u64 => BlockNumber(8));
116
117        test_op_assign!(14_u64, -=, BlockNumber(6) => 8_u64);
118        test_op_assign!(14_u64, -=, &BlockNumber(6) => 8_u64);
119    }
120
121    #[test]
122    fn saturating_sub() {
123        assert_eq!(BlockNumber(0), BlockNumber(1) - BlockNumber(5));
124        assert_eq!(BlockNumber(0), BlockNumber(1) - 5_u64);
125    }
126
127    #[test]
128    #[allow(clippy::op_ref)]
129    fn test_mul() {
130        assert_eq!(BlockNumber(6), BlockNumber(2) * BlockNumber(3));
131        assert_eq!(BlockNumber(6), BlockNumber(2) * 3_u64);
132        assert_eq!(BlockNumber(6), BlockNumber(2) * &3_u64);
133
134        assert_eq!(BlockNumber(6), 3_u64 * BlockNumber(2));
135        assert_eq!(BlockNumber(6), 3_u64 * &BlockNumber(2));
136        assert_eq!(BlockNumber(6), &3_u64 * BlockNumber(2));
137        assert_eq!(BlockNumber(6), &3_u64 * &BlockNumber(2));
138
139        test_op_assign!(BlockNumber(2), *=, BlockNumber(3) => BlockNumber(6));
140        test_op_assign!(BlockNumber(2), *=, 3_u64 => BlockNumber(6));
141        test_op_assign!(BlockNumber(2), *=, &3_u64 => BlockNumber(6));
142
143        test_op_assign!(2_u64, *=, BlockNumber(3) => 6_u64);
144        test_op_assign!(2_u64, *=, &BlockNumber(3) => 6_u64);
145    }
146
147    #[test]
148    #[allow(clippy::op_ref)]
149    fn test_div() {
150        assert_eq!(BlockNumber(6), BlockNumber(18) / BlockNumber(3));
151        assert_eq!(BlockNumber(6), BlockNumber(18) / 3_u64);
152        assert_eq!(BlockNumber(6), BlockNumber(18) / &3_u64);
153
154        assert_eq!(BlockNumber(6), 12_u64 / BlockNumber(2));
155        assert_eq!(BlockNumber(6), 12_u64 / &BlockNumber(2));
156        assert_eq!(BlockNumber(6), &12_u64 / BlockNumber(2));
157        assert_eq!(BlockNumber(6), &12_u64 / &BlockNumber(2));
158
159        test_op_assign!(BlockNumber(18), /=, BlockNumber(3) => BlockNumber(6));
160        test_op_assign!(BlockNumber(18), /=, 3_u64 => BlockNumber(6));
161        test_op_assign!(BlockNumber(18), /=, &3_u64 => BlockNumber(6));
162
163        test_op_assign!(18_u64, /=, BlockNumber(3) => 6_u64);
164        test_op_assign!(18_u64, /=, &BlockNumber(3) => 6_u64);
165    }
166
167    #[test]
168    #[allow(clippy::op_ref)]
169    fn test_rem() {
170        assert_eq!(BlockNumber(3), BlockNumber(18) % BlockNumber(5));
171        assert_eq!(BlockNumber(3), BlockNumber(18) % 5_u64);
172        assert_eq!(BlockNumber(3), BlockNumber(18) % &5_u64);
173
174        assert_eq!(BlockNumber(6), 20_u64 % BlockNumber(7));
175        assert_eq!(BlockNumber(6), 20_u64 % &BlockNumber(7));
176        assert_eq!(BlockNumber(6), &20_u64 % BlockNumber(7));
177        assert_eq!(BlockNumber(6), &20_u64 % &BlockNumber(7));
178
179        test_op_assign!(BlockNumber(18), %=, BlockNumber(5) => BlockNumber(3));
180        test_op_assign!(BlockNumber(18), %=, 5_u64 => BlockNumber(3));
181        test_op_assign!(BlockNumber(18), %=, &5_u64 => BlockNumber(3));
182
183        test_op_assign!(18_u64, %=, BlockNumber(5) => 3_u64);
184        test_op_assign!(18_u64, %=, &BlockNumber(5) => 3_u64);
185    }
186
187    #[test]
188    fn test_eq() {
189        assert_eq!(BlockNumber(1), BlockNumber(1));
190        assert_eq!(BlockNumber(2), &BlockNumber(2));
191        assert_eq!(&BlockNumber(3), BlockNumber(3));
192        assert_eq!(&BlockNumber(4), &BlockNumber(4));
193
194        assert_eq!(BlockNumber(5), 5);
195        assert_eq!(BlockNumber(6), &6);
196        assert_eq!(&BlockNumber(7), 7);
197        assert_eq!(&BlockNumber(8), &8);
198
199        assert_eq!(9, BlockNumber(9));
200        assert_eq!(10, &BlockNumber(10));
201        assert_eq!(&11, BlockNumber(11));
202        assert_eq!(&12, &BlockNumber(12));
203    }
204}