pub(crate) mod forward;
use std::time::Duration;
use tokio::time::Instant;
use crate::behavior::Address;
use crate::calculus::UserEvent;
use crate::{Crash, CreationKind, Exit};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimerId(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimerGeneration(pub u64);
impl From<u64> for TimerId {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<TimerId> for u64 {
fn from(value: TimerId) -> Self {
value.0
}
}
impl From<u64> for TimerGeneration {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<TimerGeneration> for u64 {
fn from(value: TimerGeneration) -> Self {
value.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ScheduleAt {
pub id: TimerId,
pub generation: TimerGeneration,
pub at: Instant,
}
impl ScheduleAt {
#[must_use]
pub const fn new(id: TimerId, generation: TimerGeneration, at: Instant) -> Self {
Self { id, generation, at }
}
}
impl From<(TimerId, TimerGeneration, Instant)> for ScheduleAt {
fn from((id, generation, at): (TimerId, TimerGeneration, Instant)) -> Self {
Self::new(id, generation, at)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ScheduleAfter {
pub id: TimerId,
pub generation: TimerGeneration,
pub after: Duration,
}
impl ScheduleAfter {
#[must_use]
pub const fn new(id: TimerId, generation: TimerGeneration, after: Duration) -> Self {
Self {
id,
generation,
after,
}
}
}
impl From<(TimerId, TimerGeneration, Duration)> for ScheduleAfter {
fn from((id, generation, after): (TimerId, TimerGeneration, Duration)) -> Self {
Self::new(id, generation, after)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimerElapsed {
pub id: TimerId,
pub generation: TimerGeneration,
}
impl TimerElapsed {
#[must_use]
pub const fn new(id: TimerId, generation: TimerGeneration) -> Self {
Self { id, generation }
}
}
impl From<(TimerId, TimerGeneration)> for TimerElapsed {
fn from((id, generation): (TimerId, TimerGeneration)) -> Self {
Self::new(id, generation)
}
}
pub trait TimeEvent: UserEvent {
fn time_reached(event: TimerElapsed) -> Option<Self>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObservePeer<A> {
pub peer: A,
}
impl<A> From<A> for ObservePeer<A> {
fn from(peer: A) -> Self {
Self { peer }
}
}
impl<A> ObservePeer<A> {
#[must_use]
pub const fn new(peer: A) -> Self {
Self { peer }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnwatchPeer<A> {
pub peer: A,
}
impl<A> UnwatchPeer<A> {
#[must_use]
pub const fn new(peer: A) -> Self {
Self { peer }
}
}
impl<A> From<A> for UnwatchPeer<A> {
fn from(peer: A) -> Self {
Self::new(peer)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PeerStopped<A: Address> {
pub peer: A,
pub outcome: Result<Exit<A>, Crash>,
}
impl<A: Address> PeerStopped<A> {
#[must_use]
pub fn new(peer: A, outcome: Result<Exit<A>, Crash>) -> Self {
Self { peer, outcome }
}
}
pub trait PeerEvent: UserEvent {
fn peer_stopped(event: PeerStopped<Self::Addr>) -> Option<Self>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChildStopped<A: Address> {
pub nonce: A::Nonce,
pub outcome: Result<Exit<A>, Crash>,
pub at: Instant,
}
impl<A: Address> ChildStopped<A> {
#[must_use]
pub fn new(nonce: A::Nonce, outcome: Result<Exit<A>, Crash>, at: Instant) -> Self {
Self { nonce, outcome, at }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObserveChild<N> {
pub nonce: N,
}
impl<N> ObserveChild<N> {
#[must_use]
pub const fn new(nonce: N) -> Self {
Self { nonce }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReportWorkerStopped<A: Address> {
pub worker: A::Nonce,
pub outcome: Result<Exit<A>, Crash>,
pub at: Instant,
}
impl<A: Address> ReportWorkerStopped<A> {
#[must_use]
pub fn new(worker: A::Nonce, outcome: Result<Exit<A>, Crash>, at: Instant) -> Self {
Self {
worker,
outcome,
at,
}
}
}
impl<A: Address> From<ChildStopped<A>> for ReportWorkerStopped<A> {
fn from(stopped: ChildStopped<A>) -> Self {
Self::new(stopped.nonce, stopped.outcome, stopped.at)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkerStopped<A: Address> {
pub proxy: A::Nonce,
pub worker: A::Nonce,
pub outcome: Result<Exit<A>, Crash>,
pub at: Instant,
}
impl<A: Address> WorkerStopped<A> {
#[must_use]
pub fn new(
proxy: A::Nonce,
worker: A::Nonce,
outcome: Result<Exit<A>, Crash>,
at: Instant,
) -> Self {
Self {
proxy,
worker,
outcome,
at,
}
}
}
impl<A: Address> From<(A::Nonce, ReportWorkerStopped<A>)> for WorkerStopped<A> {
fn from((proxy, stopped): (A::Nonce, ReportWorkerStopped<A>)) -> Self {
Self::new(proxy, stopped.worker, stopped.outcome, stopped.at)
}
}
pub trait ChildEvent: UserEvent {
fn child_stopped(event: ChildStopped<Self::Addr>) -> Option<Self>;
}
pub trait WorkerEvent: UserEvent {
fn worker_stopped(event: WorkerStopped<Self::Addr>) -> Option<Self>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CreationRejection {
NonceAlreadyBound,
InitializationFailed,
EnvironmentFailed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CreationResolved<N> {
pub nonce: N,
pub kind: CreationKind<N>,
pub result: Result<(), CreationRejection>,
}
impl<N> CreationResolved<N> {
#[must_use]
pub const fn new(
nonce: N,
kind: CreationKind<N>,
result: Result<(), CreationRejection>,
) -> Self {
Self {
nonce,
kind,
result,
}
}
#[must_use]
pub const fn installed(nonce: N, kind: CreationKind<N>) -> Self {
Self::new(nonce, kind, Ok(()))
}
#[must_use]
pub const fn birth(nonce: N) -> Self {
Self::installed(nonce, CreationKind::Birth)
}
#[must_use]
pub const fn replacement_incarnation(nonce: N, replaces: N) -> Self {
Self::installed(nonce, CreationKind::ReplacementIncarnation { replaces })
}
#[must_use]
pub const fn rejected(nonce: N, kind: CreationKind<N>, rejection: CreationRejection) -> Self {
Self::new(nonce, kind, Err(rejection))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObserveCreation<N> {
pub nonce: N,
}
impl<N> ObserveCreation<N> {
#[must_use]
pub const fn new(nonce: N) -> Self {
Self { nonce }
}
}
pub trait CreationEvent: UserEvent {
fn creation_resolved(event: CreationResolved<<Self::Addr as Address>::Nonce>) -> Option<Self>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReportWorkerCreationResolved<N> {
pub worker: N,
pub kind: CreationKind<N>,
pub result: Result<(), CreationRejection>,
}
impl<N> ReportWorkerCreationResolved<N> {
#[must_use]
pub const fn new(
worker: N,
kind: CreationKind<N>,
result: Result<(), CreationRejection>,
) -> Self {
Self {
worker,
kind,
result,
}
}
}
impl<N> From<CreationResolved<N>> for ReportWorkerCreationResolved<N> {
fn from(resolved: CreationResolved<N>) -> Self {
Self::new(resolved.nonce, resolved.kind, resolved.result)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WorkerCreationResolved<N> {
pub proxy: N,
pub worker: N,
pub kind: CreationKind<N>,
pub result: Result<(), CreationRejection>,
}
impl<N> WorkerCreationResolved<N> {
#[must_use]
pub const fn new(
proxy: N,
worker: N,
kind: CreationKind<N>,
result: Result<(), CreationRejection>,
) -> Self {
Self {
proxy,
worker,
kind,
result,
}
}
}
impl<N> From<(N, ReportWorkerCreationResolved<N>)> for WorkerCreationResolved<N> {
fn from((proxy, resolved): (N, ReportWorkerCreationResolved<N>)) -> Self {
Self::new(proxy, resolved.worker, resolved.kind, resolved.result)
}
}
pub trait WorkerCreationEvent: UserEvent {
fn worker_creation_resolved(
event: WorkerCreationResolved<<Self::Addr as Address>::Nonce>,
) -> Option<Self>;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct ShutdownRequested;
pub trait ShutdownEvent: UserEvent {
fn shutdown_requested(event: ShutdownRequested) -> Option<Self>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MailAddr;
#[test]
fn lifecycle_conversions_preserve_every_semantic_field() {
let at = Instant::now();
let child = ChildStopped::<MailAddr>::new(3, Err(Crash::Failed), at);
let report = ReportWorkerStopped::from(child);
let worker = WorkerStopped::from((7, report));
assert_eq!(worker.proxy, 7);
assert_eq!(worker.worker, 3);
assert_eq!(worker.outcome, Err(Crash::Failed));
assert_eq!(worker.at, at);
let creation = CreationResolved::<u64>::rejected(
4,
CreationKind::replacement_of(3),
CreationRejection::EnvironmentFailed,
);
let report = ReportWorkerCreationResolved::from(creation);
let worker = WorkerCreationResolved::from((7, report));
assert_eq!(worker.proxy, 7);
assert_eq!(worker.worker, 4);
assert_eq!(worker.kind, CreationKind::replacement_of(3));
assert_eq!(worker.result, Err(CreationRejection::EnvironmentFailed));
}
#[test]
fn timer_newtypes_and_requests_have_lossless_construction() {
let id = TimerId::from(2);
let generation = TimerGeneration::from(5);
assert_eq!(u64::from(id), 2);
assert_eq!(u64::from(generation), 5);
assert_eq!(
TimerElapsed::from((id, generation)),
TimerElapsed::new(id, generation)
);
}
}