1use core::fmt;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct FenceEpoch(u64);
11
12impl FenceEpoch {
13 pub fn new(value: u64) -> Self {
15 Self(value)
16 }
17
18 pub fn zero() -> Self {
20 Self(0)
21 }
22
23 pub fn is_stale(&self, current: &FenceEpoch) -> bool {
25 self.0 < current.0
26 }
27
28 pub fn is_current(&self, current: &FenceEpoch) -> bool {
30 self.0 == current.0
31 }
32
33 pub fn is_newer(&self, other: &FenceEpoch) -> bool {
35 self.0 > other.0
36 }
37
38 pub fn from_generation(generation: u64) -> Self {
45 FenceEpoch(generation)
46 }
47
48 pub fn bump(&self) -> FenceEpoch {
50 FenceEpoch(self.0 + 1)
51 }
52
53 pub fn value(&self) -> u64 {
55 self.0
56 }
57}
58
59impl fmt::Display for FenceEpoch {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "epoch({})", self.0)
62 }
63}
64
65pub fn bump_epoch(old: FenceEpoch) -> FenceEpoch {
67 old.bump()
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn zero_is_zero() {
76 assert_eq!(FenceEpoch::zero().value(), 0);
77 }
78
79 #[test]
80 fn stale_current_newer() {
81 let e0 = FenceEpoch::new(0);
82 let e1 = FenceEpoch::new(1);
83 let e2 = FenceEpoch::new(2);
84
85 assert!(e0.is_stale(&e1));
86 assert!(!e1.is_stale(&e1));
87 assert!(!e2.is_stale(&e1));
88
89 assert!(!e0.is_current(&e1));
90 assert!(e1.is_current(&e1));
91 assert!(!e2.is_current(&e1));
92
93 assert!(!e0.is_newer(&e1));
94 assert!(!e1.is_newer(&e1));
95 assert!(e2.is_newer(&e1));
96 }
97
98 #[test]
99 fn bump_increments() {
100 let e = FenceEpoch::new(41);
101 let bumped = e.bump();
102 assert_eq!(bumped.value(), 42);
103 }
104
105 #[test]
106 fn bump_epoch_free_fn() {
107 let e = FenceEpoch::new(9);
108 assert_eq!(bump_epoch(e).value(), 10);
109 }
110
111 #[test]
112 fn ordering() {
113 let mut epochs: Vec<FenceEpoch> =
114 vec![FenceEpoch::new(3), FenceEpoch::new(1), FenceEpoch::new(2)];
115 epochs.sort();
116 assert_eq!(
117 epochs.iter().map(|e| e.value()).collect::<Vec<_>>(),
118 vec![1, 2, 3]
119 );
120 }
121
122 #[test]
123 fn display() {
124 assert_eq!(format!("{}", FenceEpoch::new(7)), "epoch(7)");
125 }
126
127 #[test]
128 fn from_generation_roundtrip() {
129 let from_gen = FenceEpoch::from_generation(42);
130 let direct = FenceEpoch::new(42);
131 assert!(from_gen.is_current(&direct));
132 assert_eq!(from_gen.value(), direct.value());
133 }
134
135 #[test]
136 fn from_generation_stale_check() {
137 let e1 = FenceEpoch::from_generation(1);
138 let e2 = FenceEpoch::from_generation(2);
139 assert!(e1.is_stale(&e2));
140 assert!(!e2.is_stale(&e1));
141 }
142
143 #[test]
144 fn from_generation_with_fence_guard() {
145 use crate::FenceGuard;
146
147 let mut guard = FenceGuard::new(FenceEpoch::zero());
148
149 let e1 = guard.advance();
151 assert_eq!(e1, FenceEpoch::from_generation(1));
152
153 assert!(guard.check(FenceEpoch::from_generation(1)).is_ok());
155
156 let e2 = guard.advance();
158 assert_eq!(e2, FenceEpoch::from_generation(2));
159
160 assert!(guard.check(FenceEpoch::from_generation(1)).is_err());
162
163 assert!(guard.check(FenceEpoch::from_generation(2)).is_ok());
165 }
166}