mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-07-23 18:52:50 +02:00
73 lines
1.5 KiB
Rust
73 lines
1.5 KiB
Rust
//! An SPSC broadcast channel.
|
|
//!
|
|
//! - The value can only be a `usize`.
|
|
//! - The consumer is only notified if the value is different.
|
|
//! - The value `0` is reserved for closed.
|
|
|
|
use futures_util::task::AtomicWaker;
|
|
use std::sync::{
|
|
atomic::{AtomicUsize, Ordering},
|
|
Arc,
|
|
};
|
|
use std::task;
|
|
|
|
type Value = usize;
|
|
|
|
pub(crate) const CLOSED: usize = 0;
|
|
|
|
pub(crate) fn channel(initial: Value) -> (Sender, Receiver) {
|
|
debug_assert!(
|
|
initial != CLOSED,
|
|
"watch::channel initial state of 0 is reserved"
|
|
);
|
|
|
|
let shared = Arc::new(Shared {
|
|
value: AtomicUsize::new(initial),
|
|
waker: AtomicWaker::new(),
|
|
});
|
|
|
|
(
|
|
Sender {
|
|
shared: shared.clone(),
|
|
},
|
|
Receiver { shared },
|
|
)
|
|
}
|
|
|
|
pub(crate) struct Sender {
|
|
shared: Arc<Shared>,
|
|
}
|
|
|
|
pub(crate) struct Receiver {
|
|
shared: Arc<Shared>,
|
|
}
|
|
|
|
struct Shared {
|
|
value: AtomicUsize,
|
|
waker: AtomicWaker,
|
|
}
|
|
|
|
impl Sender {
|
|
pub(crate) fn send(&mut self, value: Value) {
|
|
if self.shared.value.swap(value, Ordering::SeqCst) != value {
|
|
self.shared.waker.wake();
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for Sender {
|
|
fn drop(&mut self) {
|
|
self.send(CLOSED);
|
|
}
|
|
}
|
|
|
|
impl Receiver {
|
|
pub(crate) fn load(&mut self, cx: &mut task::Context<'_>) -> Value {
|
|
self.shared.waker.register(cx.waker());
|
|
self.shared.value.load(Ordering::SeqCst)
|
|
}
|
|
|
|
pub(crate) fn peek(&self) -> Value {
|
|
self.shared.value.load(Ordering::Relaxed)
|
|
}
|
|
}
|