1#[cfg(loom)]
7use loom::sync::Arc;
8#[cfg(loom)]
9use loom::sync::atomic::{AtomicU64, Ordering};
10#[cfg(not(loom))]
11use std::sync::Arc;
12#[cfg(not(loom))]
13use std::sync::atomic::{AtomicU64, Ordering};
14
15pub struct SharedCounter {
17 inner: AtomicU64,
18}
19
20impl Default for SharedCounter {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl SharedCounter {
27 pub fn new() -> Self {
29 Self {
30 inner: AtomicU64::new(0),
31 }
32 }
33
34 pub fn with_value(value: u64) -> Self {
36 Self {
37 inner: AtomicU64::new(value),
38 }
39 }
40
41 pub fn increment(&self) -> u64 {
43 self.inner.fetch_add(1, Ordering::Relaxed) + 1
44 }
45
46 pub fn increment_by(&self, n: u64) -> u64 {
48 self.inner.fetch_add(n, Ordering::Relaxed) + n
49 }
50
51 pub fn decrement(&self) -> u64 {
53 self.inner.fetch_sub(1, Ordering::Relaxed) - 1
54 }
55
56 pub fn get(&self) -> u64 {
58 self.inner.load(Ordering::Relaxed)
59 }
60
61 pub fn reset(&self) -> u64 {
63 self.inner.swap(0, Ordering::Relaxed)
64 }
65}
66
67impl SharedCounter {
68 pub fn into_shared(self) -> Arc<Self> {
70 Arc::new(self)
71 }
72}
73
74#[cfg(test)]
75#[allow(clippy::unwrap_used)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn increment_decrement() {
82 let c = SharedCounter::new();
83 assert_eq!(c.increment(), 1);
84 assert_eq!(c.increment(), 2);
85 assert_eq!(c.decrement(), 1);
86 assert_eq!(c.get(), 1);
87 }
88
89 #[test]
90 fn increment_by() {
91 let c = SharedCounter::new();
92 assert_eq!(c.increment_by(10), 10);
93 assert_eq!(c.increment_by(5), 15);
94 }
95
96 #[test]
97 fn reset() {
98 let c = SharedCounter::with_value(42);
99 assert_eq!(c.reset(), 42);
100 assert_eq!(c.get(), 0);
101 }
102
103 #[tokio::test]
104 async fn concurrent_increment() {
105 let counter = SharedCounter::new().into_shared();
106 let mut handles = vec![];
107 for _ in 0..100 {
108 let c = counter.clone();
109 handles.push(tokio::spawn(async move {
110 c.increment();
111 }));
112 }
113 for h in handles {
114 h.await.unwrap();
115 }
116 assert_eq!(counter.get(), 100);
117 }
118}