rust/hedgewars-server/src/core/events.rs
author alfadur
Thu, 09 Sep 2021 21:06:45 +0300
changeset 15818 0c21cdbc5207
parent 15800 6af892a0a4b8
permissions -rw-r--r--
use array map in timer constructor
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     1
use slab::Slab;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     2
use std::{
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     3
    convert::TryInto,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     4
    iter,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     5
    num::NonZeroU32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     6
    time::{Duration, Instant},
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     7
};
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     8
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
     9
struct Event<Data> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    10
    event_id: u32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    11
    data: Data,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    12
}
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    13
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    14
#[derive(Clone)]
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    15
pub struct Timeout {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    16
    tick_index: u32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    17
    event_index: u32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    18
    event_id: u32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    19
}
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    20
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    21
pub struct TimedEvents<Data, const MAX_TIMEOUT: usize> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    22
    events: [Slab<Event<Data>>; MAX_TIMEOUT],
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    23
    current_time: Instant,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    24
    current_tick_index: u32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    25
    next_event_id: u32,
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    26
    events_count: u32,
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    27
}
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    28
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    29
impl<Data, const MAX_TIMEOUT: usize> TimedEvents<Data, MAX_TIMEOUT> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    30
    pub fn new() -> Self {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    31
        Self {
15818
0c21cdbc5207 use array map in timer constructor
alfadur
parents: 15800
diff changeset
    32
            events: [0; MAX_TIMEOUT].map(|_| Slab::new()),
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    33
            current_time: Instant::now(),
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    34
            current_tick_index: 0,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    35
            next_event_id: 0,
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    36
            events_count: 0,
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    37
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    38
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    39
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    40
    pub fn set_timeout(&mut self, seconds_delay: NonZeroU32, data: Data) -> Timeout {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    41
        let tick_index = (self.current_tick_index
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    42
            + std::cmp::min(seconds_delay.get(), MAX_TIMEOUT as u32))
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    43
            % MAX_TIMEOUT as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    44
        let event_id = self.next_event_id;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    45
        self.next_event_id += 1;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    46
        let event = Event { event_id, data };
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    47
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    48
        let entry = self.events[tick_index as usize].vacant_entry();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    49
        let event_index = entry.key() as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    50
        entry.insert(event);
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    51
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    52
        self.events_count += 1;
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    53
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    54
        Timeout {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    55
            tick_index,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    56
            event_index,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    57
            event_id,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    58
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    59
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    60
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    61
    pub fn cancel_timeout(&mut self, timeout: Timeout) -> Option<Data> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    62
        let events = &mut self.events[timeout.tick_index as usize];
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    63
        if matches!(events.get(timeout.event_index as usize), Some(Event { event_id: id, ..}) if *id == timeout.event_id)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    64
        {
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    65
            self.events_count -= 1;
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    66
            Some(events.remove(timeout.event_index as usize).data)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    67
        } else {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    68
            None
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    69
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    70
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    71
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    72
    pub fn poll(&mut self, time: Instant) -> Vec<Data> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    73
        let mut result = vec![];
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    74
        let second = Duration::from_secs(1);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    75
        while time - self.current_time > second {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    76
            self.current_time += second;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    77
            self.current_tick_index = (self.current_tick_index + 1) % MAX_TIMEOUT as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    78
            result.extend(
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    79
                self.events[self.current_tick_index as usize]
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    80
                    .drain()
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    81
                    .map(|e| e.data),
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    82
            );
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    83
        }
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    84
        self.events_count -= result.len() as u32;
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    85
        result
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    86
    }
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    87
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    88
    pub fn is_empty(&self) -> bool {
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    89
        self.events_count == 0
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    90
    }
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    91
}
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    92
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    93
mod test {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    94
    use super::TimedEvents;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    95
    use std::{
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    96
        num::NonZeroU32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    97
        time::{Duration, Instant},
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    98
    };
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    99
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   100
    #[test]
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   101
    fn events_test() {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   102
        let mut events = TimedEvents::<u32, 30>::new();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   103
        let now = Instant::now();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   104
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   105
        let timeouts = (1..=3)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   106
            .map(|n| events.set_timeout(NonZeroU32::new(n).unwrap(), n))
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   107
            .collect::<Vec<_>>();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   108
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   109
        let second = Duration::from_secs(1);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   110
        assert_eq!(events.cancel_timeout(timeouts[1].clone()), Some(2));
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   111
        assert_eq!(events.poll(now + second), vec![1]);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   112
        assert!(events.poll(now + second).is_empty());
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   113
        assert!(events.poll(now + 2 * second).is_empty());
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   114
        assert_eq!(events.poll(now + 3 * second), vec![3]);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   115
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   116
}