use std::sync::atomic::AtomicU8;
use tokio::sync::OnceCell;
use crate::{Payload, SoftCycleController, SoftCycleListener};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SoftCycleMessage {
Shutdown,
Restart,
}
impl From<u8> for SoftCycleMessage {
fn from(value: u8) -> Self {
match value {
0 => Self::Shutdown,
1 => Self::Restart,
_ => panic!("Invalid soft cycle message: {}", value),
}
}
}
impl From<SoftCycleMessage> for u8 {
fn from(value: SoftCycleMessage) -> Self {
match value {
SoftCycleMessage::Shutdown => 0,
SoftCycleMessage::Restart => 1,
}
}
}
impl Payload for SoftCycleMessage {
type UnderlyingAtomic = AtomicU8;
}
static SHUTDOWN_CONTROLLER: OnceCell<SoftCycleController<SoftCycleMessage>> = OnceCell::const_new();
pub async fn get_lifetime_controller() -> &'static SoftCycleController<SoftCycleMessage> {
SHUTDOWN_CONTROLLER
.get_or_init(|| async { SoftCycleController::new() })
.await
}
#[must_use = "Caller must check if the operation was successful"]
pub async fn try_shutdown() -> bool {
get_lifetime_controller()
.await
.try_notify(SoftCycleMessage::Shutdown)
.is_ok()
}
#[must_use = "Caller must check if the operation was successful"]
pub async fn try_restart() -> bool {
get_lifetime_controller()
.await
.try_notify(SoftCycleMessage::Restart)
.is_ok()
}
#[must_use = "Caller must await the listener to receive the signal"]
pub async fn listener() -> SoftCycleListener<'static, SoftCycleMessage> {
get_lifetime_controller().await.listener()
}
pub async fn clear() {
let _ = get_lifetime_controller().await.try_clear();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn conversion_u8_to_message_valid_zero_is_shutdown() {
let m: SoftCycleMessage = 0u8.into();
assert_eq!(m, SoftCycleMessage::Shutdown);
}
#[test]
fn conversion_u8_to_message_valid_one_is_restart() {
let m: SoftCycleMessage = 1u8.into();
assert_eq!(m, SoftCycleMessage::Restart);
}
#[test]
fn conversion_message_to_u8_roundtrip() {
assert_eq!(u8::from(SoftCycleMessage::Shutdown), 0);
assert_eq!(u8::from(SoftCycleMessage::Restart), 1);
assert_eq!(
SoftCycleMessage::from(u8::from(SoftCycleMessage::Shutdown)),
SoftCycleMessage::Shutdown
);
assert_eq!(
SoftCycleMessage::from(u8::from(SoftCycleMessage::Restart)),
SoftCycleMessage::Restart
);
}
#[test]
#[should_panic(expected = "Invalid soft cycle message")]
fn conversion_u8_to_message_invalid_panics_two() {
let _: SoftCycleMessage = 2u8.into();
}
#[test]
#[should_panic(expected = "Invalid soft cycle message")]
fn conversion_u8_to_message_invalid_panics_255() {
let _: SoftCycleMessage = 255u8.into();
}
}