1use crate::{FenceEpoch, StaleEpochError};
2
3#[derive(Debug, Clone)]
9pub struct FenceGuard {
10 expected: FenceEpoch,
11}
12
13impl FenceGuard {
14 pub fn new(expected: FenceEpoch) -> Self {
16 Self { expected }
17 }
18
19 pub fn check(&self, incoming: FenceEpoch) -> Result<(), StaleEpochError> {
23 if incoming.is_stale(&self.expected) {
24 Err(StaleEpochError {
25 expected: self.expected,
26 received: incoming,
27 })
28 } else {
29 Ok(())
30 }
31 }
32
33 pub fn advance(&mut self) -> FenceEpoch {
35 self.expected = self.expected.bump();
36 self.expected
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn check_passes_for_current() {
46 let guard = FenceGuard::new(FenceEpoch::new(3));
47 assert!(guard.check(FenceEpoch::new(3)).is_ok());
48 }
49
50 #[test]
51 fn check_passes_for_newer() {
52 let guard = FenceGuard::new(FenceEpoch::new(3));
53 assert!(guard.check(FenceEpoch::new(5)).is_ok());
54 }
55
56 #[test]
57 fn check_fails_for_stale() {
58 let guard = FenceGuard::new(FenceEpoch::new(3));
59 let err = guard.check(FenceEpoch::new(1)).unwrap_err();
60 assert_eq!(err.expected, FenceEpoch::new(3));
61 assert_eq!(err.received, FenceEpoch::new(1));
62 }
63
64 #[test]
65 fn advance_bumps_and_returns_new() {
66 let mut guard = FenceGuard::new(FenceEpoch::zero());
67 let e1 = guard.advance();
68 assert_eq!(e1, FenceEpoch::new(1));
69
70 assert!(guard.check(FenceEpoch::zero()).is_err());
72 assert!(guard.check(e1).is_ok());
74
75 let e2 = guard.advance();
76 assert_eq!(e2, FenceEpoch::new(2));
77 assert!(guard.check(e1).is_err());
78 assert!(guard.check(e2).is_ok());
79 }
80}