How about this one implemented using tokio::sync::watch
?
use tokio::sync::watch::{self, Sender};
pub struct Flag {
sender: Sender<bool>,
}
impl Flag {
/// Creates a new flag object.
pub fn new(enabled: bool) -> Self {
Self {
sender: watch::channel(enabled).0,
}
}
/// Enables the flag.
pub fn enable(&self) {
self.sender.send_if_modified(|value| {
if *value {
false
} else {
*value = true;
true
}
});
}
/// Disables the flag.
pub fn disable(&self) {
self.sender.send_if_modified(|value| {
*value = false;
false
});
}
/// Waits the flag to become enabled.
pub async fn wait_enabled(&self) {
if !*self.sender.borrow() {
let mut receiver = self.sender.subscribe();
if !*receiver.borrow() {
receiver.changed().await.ok();
}
}
}
}
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ecdac1b2db1edfe25cbed0599198c990.
This one has two disadvantages:
- The boolean value is protected by a lock, so the performance could be affected.
- There is no way to name the
wait_enabled
Future
, since theFuture
returned byreceiver.changed()
cannot be named.
I still prefer the one with AtomicBool
, if its correctness can be justified.