1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use uuid::Uuid;

use hierarchical_hash_wheel_timer::{
    thread_timer::{TimerRef as GenericTimerRef, TimerWithThread as GenericTimerWithThread},
    OneshotState,
    PeriodicState,
    TimerEntry as GenericTimerEntry,
    TimerReturn as GenericTimerReturn,
};

pub use hierarchical_hash_wheel_timer::TimerError;

#[allow(clippy::type_complexity)]
pub(crate) mod timer_manager;
use timer_manager::{Timeout, TimerActorRef};

/// Indicate whether or not to reschedule a periodic timer
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TimerReturn {
    /// Reschedule the timer
    #[default]
    Reschedule,
    /// Do not reschedule the timer
    Cancel,
}
impl TimerReturn {
    /// Whether or not this timer should be rescheduled
    pub fn should_reschedule(&self) -> bool {
        match self {
            TimerReturn::Reschedule => true,
            TimerReturn::Cancel => false,
        }
    }
}
impl From<TimerReturn> for GenericTimerReturn<()> {
    fn from(tr: TimerReturn) -> Self {
        match tr {
            TimerReturn::Reschedule => GenericTimerReturn::Reschedule(()),
            TimerReturn::Cancel => GenericTimerReturn::Cancel,
        }
    }
}

/// A concrete entry for an outstanding timeout
pub type TimerEntry = GenericTimerEntry<Uuid, ActorRefState, ActorRefState>;

/// The reference type for the timer thread
pub type TimerRef = GenericTimerRef<Uuid, ActorRefState, ActorRefState>;

/// The concrete vairant of timer thread used in Kompact
pub type TimerWithThread = GenericTimerWithThread<Uuid, ActorRefState, ActorRefState>;

/// The necessary state for Kompact timers
#[derive(Debug)]
pub struct ActorRefState {
    id: Uuid,
    receiver: TimerActorRef,
}

impl ActorRefState {
    fn new(id: Uuid, receiver: TimerActorRef) -> Self {
        ActorRefState { id, receiver }
    }
}

impl OneshotState for ActorRefState {
    type Id = Uuid;

    fn id(&self) -> &Self::Id {
        &self.id
    }

    fn trigger(self) -> () {
        // Ignore the Result, as we are anyway not trying to reschedule this timer
        let _res = self.receiver.enqueue(Timeout(self.id));
    }
}

impl PeriodicState for ActorRefState {
    type Id = Uuid;

    fn id(&self) -> &Self::Id {
        &self.id
    }

    fn trigger(self) -> GenericTimerReturn<Self> {
        // Ignore the Result, as we are anyway not trying to reschedule this timer
        match self.receiver.enqueue(Timeout(self.id)) {
            Ok(_) => GenericTimerReturn::Reschedule(self),
            Err(_) => GenericTimerReturn::Cancel, // Queue has probably been deallocated, so no point in trying this over and over again
        }
    }
}