use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, RwLock};
pub struct BroadcastChannel<T: Clone> {
value: Arc<RwLock<Option<T>>>,
version: Arc<AtomicUsize>,
subscribers: Arc<AtomicUsize>,
}
impl<T: Clone> BroadcastChannel<T> {
pub fn new() -> Self {
Self {
value: Arc::new(RwLock::new(None)),
version: Arc::new(AtomicUsize::new(0)),
subscribers: Arc::new(AtomicUsize::new(0)),
}
}
pub fn broadcast(&self, value: T) {
{
let mut guard = self.value.write().unwrap();
*guard = Some(value);
}
self.version.fetch_add(1, Ordering::Release);
}
pub fn subscribe(&self) -> BroadcastReceiver<T> {
self.subscribers.fetch_add(1, Ordering::Relaxed);
BroadcastReceiver {
channel: self.clone(),
last_version: 0,
}
}
pub fn subscriber_count(&self) -> usize {
self.subscribers.load(Ordering::Relaxed)
}
}
impl<T: Clone> Default for BroadcastChannel<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone> Clone for BroadcastChannel<T> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
version: self.version.clone(),
subscribers: self.subscribers.clone(),
}
}
}
pub struct BroadcastReceiver<T: Clone> {
channel: BroadcastChannel<T>,
last_version: usize,
}
impl<T: Clone> BroadcastReceiver<T> {
pub fn try_recv(&mut self) -> Option<T> {
let current_version = self.channel.version.load(Ordering::Acquire);
if current_version > self.last_version {
self.last_version = current_version;
let guard = self.channel.value.read().unwrap();
guard.clone()
} else {
None
}
}
}
impl<T: Clone> Drop for BroadcastReceiver<T> {
fn drop(&mut self) {
self.channel.subscribers.fetch_sub(1, Ordering::Relaxed);
}
}