1use crate::FenceEpoch;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct Fenced<T> {
10 epoch: FenceEpoch,
11 value: T,
12}
13
14impl<T> Fenced<T> {
15 pub fn new(epoch: FenceEpoch, value: T) -> Self {
17 Self { epoch, value }
18 }
19
20 pub fn at_zero(value: T) -> Self {
22 Self {
23 epoch: FenceEpoch::zero(),
24 value,
25 }
26 }
27
28 pub fn epoch(&self) -> FenceEpoch {
30 self.epoch
31 }
32
33 pub fn value(&self) -> &T {
35 &self.value
36 }
37
38 pub fn into_value(self) -> T {
40 self.value
41 }
42
43 pub fn is_stale(&self, current_epoch: &FenceEpoch) -> bool {
45 self.epoch.is_stale(current_epoch)
46 }
47
48 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Fenced<U> {
50 Fenced {
51 epoch: self.epoch,
52 value: f(self.value),
53 }
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn create_and_access() {
63 let f = Fenced::new(FenceEpoch::new(3), "hello");
64 assert_eq!(f.epoch(), FenceEpoch::new(3));
65 assert_eq!(*f.value(), "hello");
66 assert_eq!(f.into_value(), "hello");
67 }
68
69 #[test]
70 fn at_zero_convenience() {
71 let f = Fenced::at_zero(42u32);
72 assert_eq!(f.epoch(), FenceEpoch::zero());
73 assert_eq!(*f.value(), 42);
74 }
75
76 #[test]
77 fn staleness_check() {
78 let current = FenceEpoch::new(5);
79 let old = Fenced::new(FenceEpoch::new(3), ());
80 let fresh = Fenced::new(FenceEpoch::new(5), ());
81 let future = Fenced::new(FenceEpoch::new(7), ());
82
83 assert!(old.is_stale(¤t));
84 assert!(!fresh.is_stale(¤t));
85 assert!(!future.is_stale(¤t));
86 }
87
88 #[test]
89 fn map_transforms_value_keeps_epoch() {
90 let f = Fenced::new(FenceEpoch::new(2), 10u32);
91 let mapped = f.map(|v| v * 3);
92 assert_eq!(mapped.epoch(), FenceEpoch::new(2));
93 assert_eq!(*mapped.value(), 30);
94 }
95}