mithril_common/entities/
time_point.rs

1use std::cmp::Ordering;
2use std::fmt::{Display, Formatter};
3
4use crate::entities::{ChainPoint, Epoch, ImmutableFileNumber};
5
6/// TimePoint aggregates all types of point in the Cardano chain and is used by the state machines
7/// for their computations.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct TimePoint {
10    /// Cardano chain epoch number
11    pub epoch: Epoch,
12
13    /// Number of the last immutable files used for the digest computation
14    pub immutable_file_number: ImmutableFileNumber,
15
16    /// Chain point
17    pub chain_point: ChainPoint,
18}
19
20impl TimePoint {
21    /// [TimePoint] factory
22    pub fn new(
23        epoch: u64,
24        immutable_file_number: ImmutableFileNumber,
25        chain_point: ChainPoint,
26    ) -> TimePoint {
27        TimePoint {
28            epoch: Epoch(epoch),
29            immutable_file_number,
30            chain_point,
31        }
32    }
33
34    cfg_test_tools! {
35        /// Create a dummy TimePoint
36        pub fn dummy() -> Self {
37            Self::new(10, 100, ChainPoint::dummy())
38        }
39    }
40}
41
42impl PartialOrd for TimePoint {
43    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
44        Some(self.cmp(other))
45    }
46}
47
48impl Ord for TimePoint {
49    fn cmp(&self, other: &Self) -> Ordering {
50        self.epoch
51            .cmp(&other.epoch)
52            .then(self.immutable_file_number.cmp(&other.immutable_file_number))
53            .then(self.chain_point.cmp(&other.chain_point))
54    }
55}
56
57impl Display for TimePoint {
58    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "TimePoint (epoch: {}, immutable_file_number: {}, chain_point: {})",
62            self.epoch, self.immutable_file_number, self.chain_point
63        )
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use std::cmp::Ordering;
70
71    use crate::entities::{BlockNumber, SlotNumber};
72
73    use super::*;
74
75    #[test]
76    fn time_point_ord_cmp_epochs_take_precedence_over_other_fields() {
77        let time_point1 = TimePoint {
78            epoch: Epoch(5),
79            immutable_file_number: 0,
80            chain_point: ChainPoint {
81                slot_number: SlotNumber(10),
82                block_number: BlockNumber(20),
83                block_hash: "hash1".to_string(),
84            },
85        };
86        let time_point2 = TimePoint {
87            epoch: Epoch(0),
88            immutable_file_number: 1,
89            chain_point: ChainPoint {
90                slot_number: SlotNumber(15),
91                block_number: BlockNumber(25),
92                block_hash: "hash2".to_string(),
93            },
94        };
95
96        assert_eq!(Ordering::Greater, time_point1.cmp(&time_point2));
97    }
98
99    #[test]
100    fn time_point_ord_cmp_if_epoch_equals_then_immutable_take_precedence_over_chain_point() {
101        let time_point1 = TimePoint {
102            epoch: Epoch(0),
103            immutable_file_number: 5,
104            chain_point: ChainPoint {
105                slot_number: SlotNumber(10),
106                block_number: BlockNumber(20),
107                block_hash: "hash1".to_string(),
108            },
109        };
110        let time_point2 = TimePoint {
111            epoch: Epoch(0),
112            immutable_file_number: 0,
113            chain_point: ChainPoint {
114                slot_number: SlotNumber(15),
115                block_number: BlockNumber(25),
116                block_hash: "hash2".to_string(),
117            },
118        };
119
120        assert_eq!(Ordering::Greater, time_point1.cmp(&time_point2));
121    }
122
123    #[test]
124    fn time_point_ord_cmp_if_epoch_and_immutables_equals_then_compare_over_chain_points() {
125        let time_point1 = TimePoint {
126            epoch: Epoch(0),
127            immutable_file_number: 0,
128            chain_point: ChainPoint {
129                slot_number: SlotNumber(10),
130                block_number: BlockNumber(20),
131                block_hash: "hash1".to_string(),
132            },
133        };
134        let time_point2 = TimePoint {
135            epoch: Epoch(0),
136            immutable_file_number: 0,
137            chain_point: ChainPoint {
138                slot_number: SlotNumber(15),
139                block_number: BlockNumber(25),
140                block_hash: "hash2".to_string(),
141            },
142        };
143
144        assert_eq!(Ordering::Less, time_point1.cmp(&time_point2));
145    }
146}