use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use event_listener::Event;
#[derive(Default)]
struct StopState {
requested: AtomicBool,
changed: Event,
}
#[derive(Clone, Default)]
pub struct StopSource {
state: Arc<StopState>,
}
impl StopSource {
pub fn new() -> Self {
Self::default()
}
pub fn token(&self) -> StopToken {
StopToken {
state: Arc::clone(&self.state),
}
}
pub fn request_stop(&self) {
if !self.state.requested.swap(true, Ordering::AcqRel) {
self.state.changed.notify(usize::MAX);
}
}
pub fn is_stop_requested(&self) -> bool {
self.state.requested.load(Ordering::Acquire)
}
}
impl std::fmt::Debug for StopSource {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("StopSource")
.field("requested", &self.is_stop_requested())
.finish()
}
}
#[derive(Clone, Default)]
pub struct StopToken {
state: Arc<StopState>,
}
impl StopToken {
pub fn never() -> Self {
Self::default()
}
pub fn should_stop(&self) -> bool {
self.state.requested.load(Ordering::Acquire)
}
pub async fn stopped(&self) {
loop {
if self.should_stop() {
return;
}
let changed = self.state.changed.listen();
if self.should_stop() {
return;
}
changed.await;
}
}
}
impl std::fmt::Debug for StopToken {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("StopToken")
.field("requested", &self.should_stop())
.finish()
}
}