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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//! Simulator's event and the event manager

use rand::distributions::{Distribution, Uniform, WeightedError, WeightedIndex};
use rand::Rng;

/// Timer for local
pub type LocalEventTime = u32;

/// can store event as Simulator's event
pub trait Event: Clone {}

/// Error for scheduled event
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScheduleEventError {
    /// user schedule event which scheduler will not fire.
    /// Not occurred in re-schedule event. If occurred at the time, scheduler is panic.
    /// for example, occurred when user schedule repeat count 0 repeat schedule.
    CannotFireEvent,
    WeightedError(WeightedError),
}

impl std::error::Error for ScheduleEventError {}

impl std::fmt::Display for ScheduleEventError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            ScheduleEventError::CannotFireEvent => write!(f, "Cannot fire the event"),
            ScheduleEventError::WeightedError(we) => write!(f, "{}", we),
        }
    }
}

impl From<WeightedError> for ScheduleEventError {
    fn from(we: WeightedError) -> Self {
        ScheduleEventError::WeightedError(we)
    }
}

/// timer for schedule
#[derive(Debug, Clone)]
pub enum EventTimer {
    /// fire after timeout
    Time(LocalEventTime),
    /// fire after random value by uniform select in range values.
    ///
    /// args is pair of low value, mas value and inclusive flag.
    /// it inclusive is true then low <= max, if false then low < max.
    Uniform(LocalEventTime, LocalEventTime, bool),
    /// fire after choice value with these weight as random.
    WeightedIndex(Vec<(LocalEventTime, u8)>),
}

impl EventTimer {
    /// calculate time for event timer as local time
    fn to_local_time<R: Rng + ?Sized>(
        &self,
        rng: &mut R,
    ) -> Result<LocalEventTime, ScheduleEventError> {
        match &self {
            EventTimer::Time(timeout) => Ok(*timeout),
            EventTimer::Uniform(low, max, inclusive) => Ok(if *inclusive {
                Uniform::from(*low..=*max).sample(rng)
            } else {
                Uniform::from(*low..*max).sample(rng)
            }),
            EventTimer::WeightedIndex(items) => {
                let dist = WeightedIndex::new(items.iter().map(|item| item.1))?;
                Ok(items
                    // always success because sampler is constructed from list of the (LocalEventTimer, weight)s.
                    .get(dist.sample(rng))
                    .unwrap()
                    .0)
            }
        }
    }
}

/// event schedule
#[derive(Debug, Clone)]
pub enum Schedule {
    /// fire at immediate timing
    Immediate,
    /// fire after specify time
    Timeout(EventTimer),
    /// fire everytime
    Everytime,
    /// fire every specify time
    EveryInterval(EventTimer),
    /// fire every specify time only specify count
    Repeat(u8, EventTimer),
}

impl Schedule {
    /// calculate time for fire timing
    fn to_local_timer<R: Rng + ?Sized>(
        &self,
        rng: &mut R,
    ) -> Result<LocalEventTime, ScheduleEventError> {
        match &self {
            Schedule::Immediate => Ok(1),
            Schedule::Timeout(timeout) => timeout.to_local_time(rng),
            Schedule::Everytime => Ok(1),
            Schedule::EveryInterval(interval) => interval.to_local_time(rng),
            Schedule::Repeat(count, interval) => {
                if *count == 0 {
                    return Err(ScheduleEventError::CannotFireEvent);
                }

                return interval.to_local_time(rng);
            }
        }
    }

    /// convert to next schedule
    /// if cannot calc next schedule time then return None else return Some(schedule).
    fn to_next(&self) -> Option<Schedule> {
        match &self {
            Schedule::Immediate
            | Schedule::Timeout(_)
            | Schedule::Repeat(0, _)
            | Schedule::Repeat(1, _) => None,
            Schedule::Everytime => Some(Schedule::Everytime),
            Schedule::EveryInterval(interval) => Some(Schedule::EveryInterval(interval.clone())),
            Schedule::Repeat(count, interval) => {
                Some(Schedule::Repeat(count - 1, interval.clone()))
            }
        }
    }
}

/// u8::MIN is the lowest priority, u8::MAX is the highest priority.
pub type Priority = u8;

/// event scheduler
#[derive(Debug, Clone)]
pub struct EventScheduler<E: Event> {
    /// event list with inserted order by LocalEventTime's asc.
    event_list: Vec<(LocalEventTime, Schedule, Priority, E)>,
}

impl<E: Event> EventScheduler<E> {
    /// initializer
    pub(crate) fn new() -> Self {
        EventScheduler { event_list: vec![] }
    }

    /// calc next state and fetch fired events
    pub(crate) fn next_time_and_fire<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
    ) -> Vec<(Priority, E)> {
        let mut removed: usize = 0;
        for event in self.event_list.iter_mut() {
            if event.0 > 0 {
                event.0 -= 1;
            }
            if event.0 == 0 {
                removed += 1;
            }
        }

        let fired_events: Vec<(Schedule, Priority, E)> = self
            .event_list
            .drain(0..removed)
            .map(|(_, s, pty, e)| (s, pty, e))
            .collect();

        // reschedule for calculated next event schedule
        for (schedule, pty, event) in fired_events.iter() {
            if let Some(next_schedule) = schedule.to_next() {
                // scheduled event's schedule is already validated
                self.schedule(rng, next_schedule, *pty, event.clone())
                    .unwrap();
            }
        }

        return fired_events.into_iter().map(|(_, p, e)| (p, e)).collect();
    }

    //
    // get state of scheduler state
    //

    /// judge exist scheduled event
    pub fn have_event(&self) -> bool {
        !self.event_list.is_empty()
    }

    /// get length of scheduled events
    pub fn count(&self) -> usize {
        self.event_list.len()
    }

    //
    // schedule event
    //

    /// clear all scheduled events
    pub fn clear(&mut self) {
        self.event_list.clear();
    }

    /// remove scheduled events when predicate function is true
    pub fn remove_when<P>(&mut self, mut predicate: P)
    where
        P: FnMut(&(LocalEventTime, Schedule, Priority, E)) -> bool,
    {
        self.event_list.retain(|state| !predicate(state))
    }

    /// retains only the scheduled events specified by the predicate.
    #[allow(unused_mut)]
    pub fn retain<P>(&mut self, mut predicate: P)
    where
        P: FnMut(&(LocalEventTime, Schedule, Priority, E)) -> bool,
    {
        self.event_list.retain(predicate)
    }

    /// store event with scheduling
    pub fn schedule<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        schedule: Schedule,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        let mut index: usize = 0;
        let timer: LocalEventTime = schedule.to_local_timer(rng)?;

        for (count, _, pty, _) in self.event_list.iter() {
            if (&timer == count && &priority > pty) || &timer < count {
                break;
            }
            index += 1;
        }
        self.event_list
            .insert(index, (timer, schedule, priority, event));
        Ok(())
    }

    /// store event with scheduling when user judge ok from all scheduled events
    pub fn schedule_when<R: Rng + ?Sized, P>(
        &mut self,
        rng: &mut R,
        schedule: Schedule,
        priority: Priority,
        event: E,
        predicate: P,
    ) -> Result<(), ScheduleEventError>
    where
        P: FnOnce(&Self) -> bool,
    {
        if !predicate(&self) {
            return Ok(());
        }
        self.schedule(rng, schedule, priority, event)
    }

    /// store event which fire at immediate timing
    pub fn immediate<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        self.schedule(rng, Schedule::Immediate, priority, event)
    }

    /// store event which fire after timeout
    pub fn timeout<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        timeout: EventTimer,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        self.schedule(rng, Schedule::Timeout(timeout), priority, event)
    }

    /// store event which fire every time
    pub fn everytime<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        self.schedule(rng, Schedule::Everytime, priority, event)
    }

    /// store event which fire every interval
    pub fn every_interval<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        interval: EventTimer,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        self.schedule(rng, Schedule::EveryInterval(interval), priority, event)
    }

    /// store event which fire every interval only count
    pub fn repeat<R: Rng + ?Sized>(
        &mut self,
        rng: &mut R,
        count: u8,
        interval: EventTimer,
        priority: Priority,
        event: E,
    ) -> Result<(), ScheduleEventError> {
        self.schedule(rng, Schedule::Repeat(count, interval), priority, event)
    }
}