pipecircuit 0.0.19

Correct. Robust. Fast. Portable. Pick four.
Documentation
mod wake_after;

use core::{marker::PhantomData, num::NonZeroU64};

use crate::Pipe;

pub use wake_after::{WakeAfter, WakePrecision};

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TimerToken(NonZeroU64);

impl TimerToken {
    pub const MIN: Self = Self(NonZeroU64::MIN);

    pub const fn from_nonzero(value: NonZeroU64) -> Self {
        Self(value)
    }

    pub const fn value(self) -> NonZeroU64 {
        self.0
    }
}

impl From<NonZeroU64> for TimerToken {
    fn from(value: NonZeroU64) -> Self {
        Self::from_nonzero(value)
    }
}

impl From<TimerToken> for NonZeroU64 {
    fn from(token: TimerToken) -> Self {
        token.value()
    }
}

#[cfg(feature = "storage")]
impl crate::storage::warp_table::IndexKey for TimerToken {
    fn index_word(self) -> u64 {
        crate::storage::warp_table::integer_index_word(self.value().get())
    }
}

pub enum Timer<Token> {
    _Token(PhantomData<fn() -> Token>),
}

impl<Token: 'static> Pipe for Timer<Token> {
    type In<'message> = TimerIn<Token>;
    type Out<'message> = TimerOut<'message, Token>;
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TimerIn<Token> {
    Arm { token: Token, after: WakeAfter },
    Cancel { token: Token },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TimerArmRefusal {
    AlreadyArmed,
    AtCapacity { maximum_deadlines: u32 },
    WakeTickOutsideRange,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TimerCancellationRefusal {
    NotArmed,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct EmptyElapsedTimerTokens;

#[derive(Debug, Eq, PartialEq)]
pub struct ElapsedTimerTokens<'tokens, Token> {
    tokens: &'tokens [Token],
}

impl<'tokens, Token> ElapsedTimerTokens<'tokens, Token> {
    pub const fn try_new(tokens: &'tokens [Token]) -> Result<Self, EmptyElapsedTimerTokens> {
        if tokens.is_empty() {
            return Err(EmptyElapsedTimerTokens);
        }
        Ok(Self { tokens })
    }

    pub const fn tokens(&self) -> &'tokens [Token] {
        self.tokens
    }
}

#[derive(Debug, Eq, PartialEq)]
#[must_use = "timer outcomes must be routed or settled"]
pub enum TimerOut<'message, Token> {
    Armed {
        token: Token,
    },
    Elapsed {
        tokens: ElapsedTimerTokens<'message, Token>,
    },
    Cancelled {
        token: Token,
    },
    ArmRefused {
        token: Token,
        after: WakeAfter,
        reason: TimerArmRefusal,
    },
    CancellationRefused {
        token: Token,
        reason: TimerCancellationRefusal,
    },
}

pub struct TimerArmOutcome<Token> {
    decision: TimerArmDecision<Token>,
}

pub struct TimerCancellationOutcome<Token> {
    decision: TimerCancellationDecision<Token>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TimerArmDecision<Token> {
    Armed {
        token: Token,
    },
    Refused {
        token: Token,
        after: WakeAfter,
        reason: TimerArmRefusal,
    },
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TimerCancellationDecision<Token> {
    Cancelled {
        token: Token,
    },
    Refused {
        token: Token,
        reason: TimerCancellationRefusal,
    },
}

impl<Token> TimerArmOutcome<Token> {
    pub fn into_decision(self) -> TimerArmDecision<Token> {
        self.decision
    }
}

impl<Token> TimerCancellationOutcome<Token> {
    pub fn into_decision(self) -> TimerCancellationDecision<Token> {
        self.decision
    }
}

impl<'message, Token> TimerOut<'message, Token> {
    pub fn into_arm_outcome(self) -> Result<TimerArmOutcome<Token>, Self> {
        match self {
            Self::Armed { token } => Ok(TimerArmOutcome {
                decision: TimerArmDecision::Armed { token },
            }),
            Self::ArmRefused {
                token,
                after,
                reason,
            } => Ok(TimerArmOutcome {
                decision: TimerArmDecision::Refused {
                    token,
                    after,
                    reason,
                },
            }),
            Self::Elapsed { .. } | Self::Cancelled { .. } | Self::CancellationRefused { .. } => {
                Err(self)
            }
        }
    }

    pub fn into_cancellation_outcome(self) -> Result<TimerCancellationOutcome<Token>, Self> {
        match self {
            Self::Cancelled { token } => Ok(TimerCancellationOutcome {
                decision: TimerCancellationDecision::Cancelled { token },
            }),
            Self::CancellationRefused { token, reason } => Ok(TimerCancellationOutcome {
                decision: TimerCancellationDecision::Refused { token, reason },
            }),
            Self::Armed { .. } | Self::Elapsed { .. } | Self::ArmRefused { .. } => Err(self),
        }
    }
}

#[cfg(test)]
mod tests;