use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use super::message::*;
use crate::error::RuntimeError;
pub enum State<S>
where
S: From<usize> + Into<usize>,
{
NotInitialized,
Initializing,
Ready,
Running(S),
Stopped,
}
const NOT_INITIALIZED: usize = usize::max_value();
const INITIALIZING: usize = usize::max_value() - 1;
const READY: usize = usize::max_value() - 2;
const STOPPED: usize = usize::max_value() - 3;
impl<S> From<State<S>> for usize
where
S: From<usize> + Into<usize>,
{
fn from(state: State<S>) -> Self {
match state {
State::NotInitialized => NOT_INITIALIZED,
State::Initializing => INITIALIZING,
State::Ready => READY,
State::Stopped => STOPPED,
State::Running(s) => s.into(),
}
}
}
impl<S> From<usize> for State<S>
where
S: From<usize> + Into<usize>,
{
fn from(state: usize) -> Self {
match state {
NOT_INITIALIZED => State::NotInitialized,
INITIALIZING => State::Initializing,
READY => State::Ready,
STOPPED => State::Stopped,
_ => State::Running(state.into()),
}
}
}
impl<S> Default for State<S>
where
S: From<usize> + Into<usize>,
{
fn default() -> Self {
Self::NotInitialized
}
}
#[derive(Clone, Default)]
pub struct StateFlag<S>
where
S: From<usize> + Into<usize>,
{
flag: Arc<AtomicUsize>,
ty: PhantomData<S>,
}
impl<S> StateFlag<S>
where
S: From<usize> + Into<usize>,
{
#[inline]
pub fn new_ready() -> Self {
Self {
flag: Arc::new(AtomicUsize::new(State::<S>::Ready.into())),
ty: PhantomData::default(),
}
}
#[inline]
pub fn new_running(state: S) -> Self {
Self {
flag: Arc::new(AtomicUsize::new(State::Running(state).into())),
ty: PhantomData::default(),
}
}
#[inline]
pub fn start_initialize(&self) -> Result<(), RuntimeError> {
match self
.flag
.swap(State::<S>::Initializing.into(), Ordering::Relaxed)
{
NOT_INITIALIZED => Ok(()),
_ => RuntimeError::expect(ERR_INIT),
}
}
#[inline]
pub fn stop_initialize(&self) -> Result<(), RuntimeError> {
match self.flag.swap(State::<S>::Ready.into(), Ordering::Relaxed) {
INITIALIZING => Ok(()),
_ => RuntimeError::expect(ERR_INIT),
}
}
#[inline]
pub fn skip_initialize(&self) -> Result<(), RuntimeError> {
match self.flag.swap(State::<S>::Ready.into(), Ordering::Relaxed) {
NOT_INITIALIZED | INITIALIZING => Ok(()),
_ => RuntimeError::expect(ERR_INIT),
}
}
#[inline]
pub fn start(&self, state: S) -> Result<(), RuntimeError> {
match self.flag.swap(state.into(), Ordering::Relaxed) {
NOT_INITIALIZED | INITIALIZING => RuntimeError::expect(ERR_NOT_INIT),
READY | STOPPED => Ok(()),
_ => RuntimeError::expect(ERR_STARTED),
}
}
#[inline]
pub fn status(&self) -> Result<S, RuntimeError> {
match self.flag.load(Ordering::Relaxed) {
NOT_INITIALIZED | INITIALIZING => RuntimeError::expect(ERR_NOT_INIT),
READY => RuntimeError::expect(ERR_NOT_STARTED),
STOPPED => RuntimeError::expect(ERR_STOPPED),
_state => Ok(_state.into()),
}
}
#[inline]
pub fn stop(&self) -> Result<(), RuntimeError> {
match self
.flag
.swap(State::<S>::Stopped.into(), Ordering::Relaxed)
{
NOT_INITIALIZED | INITIALIZING => RuntimeError::expect(ERR_NOT_INIT),
READY => RuntimeError::expect(ERR_NOT_STARTED),
STOPPED => RuntimeError::expect(ERR_STOPPED),
_ => Ok(()),
}
}
#[inline]
pub fn is_initialized(&self) -> bool {
match self.flag.load(Ordering::Relaxed) {
NOT_INITIALIZED => false,
_ => true,
}
}
#[inline]
pub fn is_running(&self) -> bool {
match self.flag.load(Ordering::Relaxed) {
NOT_INITIALIZED | INITIALIZING | READY | STOPPED => false,
_ => true,
}
}
#[inline]
pub fn assert_running(&self) -> Result<(), RuntimeError> {
match self.is_running() {
true => Ok(()),
false => RuntimeError::expect(ERR_NOT_STARTED),
}
}
#[inline]
pub fn assert_stopped(&self) -> Result<(), RuntimeError> {
match self.is_running() {
false => Ok(()),
true => RuntimeError::expect(ERR_STARTED),
}
}
}
pub struct NoExtraState;
impl From<usize> for NoExtraState {
#[inline]
fn from(_: usize) -> Self {
NoExtraState
}
}
impl Into<usize> for NoExtraState {
#[inline]
fn into(self) -> usize {
0
}
}