amaru_kernel/cardano/
epoch.rs1use std::{
16 fmt,
17 ops::{Add, Sub},
18 str::FromStr,
19};
20
21use minicbor::{Decode, Decoder, Encode};
22#[cfg(any(test, feature = "test-utils"))]
23use proptest::prelude::{Arbitrary, BoxedStrategy, Strategy};
24
25#[derive(Clone, Debug, Copy, PartialEq, PartialOrd, Ord, Eq, serde::Serialize, serde::Deserialize, Default)]
26#[repr(transparent)]
27pub struct Epoch(u64);
28
29impl Epoch {
30 pub fn new(epoch: u64) -> Self {
31 Self(epoch)
32 }
33
34 pub fn as_u64(&self) -> u64 {
35 self.0
36 }
37}
38
39#[cfg(any(test, feature = "test-utils"))]
40impl Arbitrary for Epoch {
41 type Parameters = ();
42 type Strategy = BoxedStrategy<Self>;
43
44 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
45 (0..u64::MAX).prop_map(Epoch::from).boxed()
46 }
47}
48
49impl fmt::Display for Epoch {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "{}", self.0)
52 }
53}
54
55impl FromStr for Epoch {
56 type Err = std::num::ParseIntError;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 s.parse::<u64>().map(Epoch)
60 }
61}
62
63impl From<u64> for Epoch {
64 fn from(epoch: u64) -> Epoch {
65 Epoch(epoch)
66 }
67}
68
69impl From<Epoch> for u64 {
70 fn from(epoch: Epoch) -> u64 {
71 epoch.0
72 }
73}
74
75impl<C> Encode<C> for Epoch {
76 fn encode<W: minicbor::encode::Write>(
77 &self,
78 e: &mut minicbor::Encoder<W>,
79 ctx: &mut C,
80 ) -> Result<(), minicbor::encode::Error<W::Error>> {
81 self.0.encode(e, ctx)
82 }
83}
84
85impl<'b, C> Decode<'b, C> for Epoch {
86 fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
87 d.u64().map(Epoch)
88 }
89}
90
91impl Add<u64> for Epoch {
92 type Output = Self;
93
94 fn add(self, rhs: u64) -> Self::Output {
95 Epoch(self.0 + rhs)
96 }
97}
98
99impl Sub<u64> for Epoch {
100 type Output = Self;
101
102 fn sub(self, rhs: u64) -> Self::Output {
103 Epoch(self.0 - rhs)
104 }
105}
106
107impl Epoch {
108 pub fn saturating_sub(self, rhs: u64) -> Self {
109 Self(self.0.saturating_sub(rhs))
110 }
111}
112
113impl Sub<Epoch> for Epoch {
114 type Output = u64;
115
116 fn sub(self, rhs: Epoch) -> Self::Output {
117 self.0 - rhs.0
118 }
119}
120
121#[cfg(any(test, feature = "test-utils"))]
122pub use tests::*;
123
124#[cfg(any(test, feature = "test-utils"))]
125mod tests {
126 use proptest::prelude::*;
127
128 use super::*;
129
130 prop_compose! {
131 pub fn any_epoch()(epoch in any::<u64>()) -> Epoch {
132 Epoch::from(epoch)
133 }
134 }
135}