use std::time::Duration;
use tokio::time::Instant;
use crate::behavior::{Address, Behavior, BirthMode, Births};
use crate::deadlined::{At, AtId, AtReaction};
use crate::shutdown::{FinalizeOnShutdown, ShutdownReaction, StopOnShutdown};
use crate::stashing::{StashRoute, Stashing};
use crate::supervising::{RestartPolicy, Strategy, Supervising, SupervisionFailureReaction};
use crate::verdict::Never;
use crate::watching::{LinkReaction, Watching};
use crate::{Actions, Base, Exit, Fsm, Move, SendAlgebra, State};
const DEFAULT_STRATEGY: Strategy = Strategy::OneForOne;
const DEFAULT_POLICY: RestartPolicy = RestartPolicy::Transient;
const DEFAULT_BUDGET: (u32, Duration) = (1, Duration::from_secs(5));
fn identity_nonce<N: From<u64>>(index: usize) -> N {
N::from(u64::try_from(index).expect("fleet index fits u64"))
}
pub struct Spec<B> {
behavior: B,
next_timer: u64,
}
impl<S: State<O, Br, E>, O, Br: BirthMode, E> Spec<Base<S, O, Br, E>> {
#[must_use]
pub fn new(state: S) -> Self {
Self {
behavior: Base::new(state),
next_timer: 0,
}
}
}
impl<A, S, M, P, E> Spec<Fsm<A, S, M, P, E>>
where
A: Address,
P: Copy + PartialEq,
{
#[must_use]
pub fn machine(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
Self {
behavior: Fsm::new(state, phase, on),
next_timer: 0,
}
}
}
impl<B: Behavior> Spec<B> {
#[must_use]
pub fn from_behavior(behavior: B) -> Self {
Self {
behavior,
next_timer: 0,
}
}
#[must_use]
pub fn build(self) -> B {
self.behavior
}
#[must_use]
pub fn behavior(&self) -> &B {
&self.behavior
}
#[must_use]
pub fn stop_on_shutdown(self) -> Spec<StopOnShutdown<B>> {
Spec {
behavior: StopOnShutdown::new(self.behavior),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn finalize_on_shutdown(
self,
finalize: ShutdownReaction<B>,
) -> Spec<FinalizeOnShutdown<B>> {
Spec {
behavior: FinalizeOnShutdown::new(self.behavior, finalize),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Spec<Watching<B>> {
Spec {
behavior: Watching::new(self.behavior, peer, on_stopped),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn at(self, when: Option<Instant>, on_reached: AtReaction<B>) -> Spec<At<B>> {
Spec {
behavior: At::new(self.behavior, AtId(self.next_timer), when, on_reached),
next_timer: self
.next_timer
.checked_add(1)
.expect("timer identity exhausted"),
}
}
#[must_use]
pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Spec<Stashing<B>>
where
B: Behavior<Ph = Never>,
{
Spec {
behavior: Stashing::new(self.behavior, route),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn children<C>(self, fleet: (usize, fn(usize) -> C)) -> Spec<Supervising<B, C>>
where
B: Behavior<Birth = Births<C>>,
C: Behavior<Ph = Never, Addr = B::Addr>,
<B::Addr as Address>::Nonce: From<u64>,
{
self.children_with_nonces(identity_nonce, fleet.0, fleet.1)
}
#[must_use]
pub fn children_with_nonces<C>(
self,
nonces: fn(usize) -> <B::Addr as Address>::Nonce,
count: usize,
build: fn(usize) -> C,
) -> Spec<Supervising<B, C>>
where
B: Behavior<Birth = Births<C>>,
C: Behavior<Ph = Never, Addr = B::Addr>,
{
Spec {
behavior: Supervising::new(
self.behavior,
nonces,
count,
build,
DEFAULT_STRATEGY,
DEFAULT_POLICY,
DEFAULT_BUDGET.0,
DEFAULT_BUDGET.1,
),
next_timer: self.next_timer,
}
}
}
impl<B, C> Spec<Supervising<B, C>>
where
B: Behavior<Birth = Births<C>>,
C: Behavior<Ph = Never, Addr = B::Addr>,
{
#[must_use]
pub fn restart(self, strategy: Strategy) -> Self {
Self {
behavior: self.behavior.with_strategy(strategy),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn when(self, policy: RestartPolicy) -> Self {
Self {
behavior: self.behavior.with_policy(policy),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn within(self, maximum: u32, window: Duration) -> Self {
Self {
behavior: self.behavior.with_budget(maximum, window),
next_timer: self.next_timer,
}
}
#[must_use]
pub fn on_supervision_failure(self, reaction: SupervisionFailureReaction<B>) -> Self {
Self {
behavior: self.behavior.with_failure_reaction(reaction),
next_timer: self.next_timer,
}
}
}
impl<B, A, Ph, Sends, Br> Behavior for Spec<B>
where
A: Address + Send,
Sends: SendAlgebra,
Br: BirthMode,
B: Behavior<
Addr = A,
Ph = Ph,
Sends = Sends,
Birth = Br,
Effect = Actions<A, Ph, Sends, Br>,
Done = Exit<A>,
> + Send,
A::Nonce: Send,
B::Msg: Send,
B::Event: Send,
{
type Addr = A;
type Msg = B::Msg;
type Event = B::Event;
type Sends = Sends;
type Ph = Ph;
type Error = B::Error;
type Birth = Br;
type Effect = B::Effect;
type Done = B::Done;
async fn init(&mut self) -> Result<Self::Effect, B::Error> {
self.behavior.init().await
}
async fn step(&mut self, event: B::Event) -> Result<Self::Effect, B::Error> {
self.behavior.step(event).await
}
}