#[cfg(loom)]
use loom::sync::atomic::{AtomicU64, Ordering};
#[cfg(loom)]
use loom::sync::Arc;
#[cfg(not(loom))]
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(not(loom))]
use std::sync::Arc;
use crate::error::WsError;
#[derive(Clone)]
pub(crate) struct ConnectionCounter {
inner: Arc<AtomicU64>,
}
impl ConnectionCounter {
pub(crate) fn new() -> Self {
Self {
inner: Arc::new(AtomicU64::new(0)),
}
}
pub(crate) fn get(&self) -> u64 {
self.inner.load(Ordering::Relaxed)
}
pub(crate) fn increment(&self, max: Option<usize>) -> Result<u64, WsError> {
match max {
None => Ok(self.inner.fetch_add(1, Ordering::Relaxed) + 1),
Some(limit) => loop {
let current = self.inner.load(Ordering::Relaxed);
if current as usize >= limit {
return Err(WsError::TooManyConnections);
}
match self.inner.compare_exchange(
current,
current + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => return Ok(current + 1),
Err(_) => continue,
}
},
}
}
pub(crate) fn decrement(&self) -> u64 {
let _ = self
.inner
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
if v == 0 {
None
} else {
Some(v - 1)
}
});
self.inner.load(Ordering::Relaxed)
}
}