use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct SyncToggle {
#[serde(default)]
inner: std::sync::Arc<std::sync::atomic::AtomicBool>,
}
const ORDERING: std::sync::atomic::Ordering = std::sync::atomic::Ordering::SeqCst;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum CurrentToggleState {
JustToggled,
AlreadyToggled,
Untoggled,
}
impl SyncToggle {
pub fn new() -> Self {
Self {
inner: Default::default(),
}
}
pub fn toggle_on_if_untoggled(&self) -> CurrentToggleState {
if self.inner.fetch_nand(false, ORDERING) {
CurrentToggleState::AlreadyToggled
} else {
CurrentToggleState::JustToggled
}
}
pub fn toggle_off(&self) {
self.inner.store(false, ORDERING)
}
pub fn get(&self) -> CurrentToggleState {
if self.inner.load(ORDERING) {
CurrentToggleState::AlreadyToggled
} else {
CurrentToggleState::Untoggled
}
}
}
#[cfg(test)]
mod tests {
use crate::sync_toggle::{CurrentToggleState, SyncToggle};
#[test]
fn test_sync_toggle() {
let toggle = SyncToggle::new();
assert_eq!(toggle.get(), CurrentToggleState::Untoggled);
assert_eq!(
toggle.toggle_on_if_untoggled(),
CurrentToggleState::JustToggled
);
toggle.toggle_off();
assert_eq!(toggle.get(), CurrentToggleState::Untoggled);
assert_eq!(
toggle.toggle_on_if_untoggled(),
CurrentToggleState::JustToggled
);
assert_eq!(toggle.get(), CurrentToggleState::AlreadyToggled);
assert_eq!(
toggle.toggle_on_if_untoggled(),
CurrentToggleState::AlreadyToggled
);
assert_eq!(toggle.get(), CurrentToggleState::AlreadyToggled);
assert_eq!(
toggle.toggle_on_if_untoggled(),
CurrentToggleState::AlreadyToggled
);
assert_eq!(toggle.get(), CurrentToggleState::AlreadyToggled);
toggle.toggle_off();
assert_eq!(toggle.get(), CurrentToggleState::Untoggled);
assert_eq!(
toggle.toggle_on_if_untoggled(),
CurrentToggleState::JustToggled
);
}
}