rust/hedgewars-server/src/core/events.rs
author alfadur
Tue, 22 Jun 2021 01:41:33 +0300
changeset 15800 6af892a0a4b8
parent 15799 ed3b510b860c
child 15818 0c21cdbc5207
permissions -rw-r--r--
update mio
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 {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    32
            events: iter::repeat_with(|| Slab::new())
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    33
                .take(MAX_TIMEOUT)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    34
                .collect::<Vec<_>>()
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    35
                .try_into()
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    36
                .ok()
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    37
                .unwrap(),
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    38
            current_time: Instant::now(),
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    39
            current_tick_index: 0,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    40
            next_event_id: 0,
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    41
            events_count: 0,
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    42
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    43
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    44
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    45
    pub fn set_timeout(&mut self, seconds_delay: NonZeroU32, data: Data) -> Timeout {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    46
        let tick_index = (self.current_tick_index
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    47
            + std::cmp::min(seconds_delay.get(), MAX_TIMEOUT as u32))
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    48
            % MAX_TIMEOUT as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    49
        let event_id = self.next_event_id;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    50
        self.next_event_id += 1;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    51
        let event = Event { event_id, data };
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    52
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    53
        let entry = self.events[tick_index as usize].vacant_entry();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    54
        let event_index = entry.key() as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    55
        entry.insert(event);
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    56
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    57
        self.events_count += 1;
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    58
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    59
        Timeout {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    60
            tick_index,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    61
            event_index,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    62
            event_id,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    63
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    64
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    65
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    66
    pub fn cancel_timeout(&mut self, timeout: Timeout) -> Option<Data> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    67
        let events = &mut self.events[timeout.tick_index as usize];
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    68
        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
    69
        {
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    70
            self.events_count -= 1;
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    71
            Some(events.remove(timeout.event_index as usize).data)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    72
        } else {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    73
            None
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    74
        }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    75
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    76
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    77
    pub fn poll(&mut self, time: Instant) -> Vec<Data> {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    78
        let mut result = vec![];
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    79
        let second = Duration::from_secs(1);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    80
        while time - self.current_time > second {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    81
            self.current_time += second;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    82
            self.current_tick_index = (self.current_tick_index + 1) % MAX_TIMEOUT as u32;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    83
            result.extend(
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    84
                self.events[self.current_tick_index as usize]
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    85
                    .drain()
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    86
                    .map(|e| e.data),
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    87
            );
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    88
        }
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    89
        self.events_count -= result.len() as u32;
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    90
        result
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    91
    }
15800
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    92
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    93
    pub fn is_empty(&self) -> bool {
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    94
        self.events_count == 0
6af892a0a4b8 update mio
alfadur
parents: 15799
diff changeset
    95
    }
15799
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    96
}
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    97
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    98
mod test {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
    99
    use super::TimedEvents;
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   100
    use std::{
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   101
        num::NonZeroU32,
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   102
        time::{Duration, Instant},
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   103
    };
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   104
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   105
    #[test]
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   106
    fn events_test() {
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   107
        let mut events = TimedEvents::<u32, 30>::new();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   108
        let now = Instant::now();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   109
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   110
        let timeouts = (1..=3)
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   111
            .map(|n| events.set_timeout(NonZeroU32::new(n).unwrap(), n))
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   112
            .collect::<Vec<_>>();
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   113
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   114
        let second = Duration::from_secs(1);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   115
        assert_eq!(events.cancel_timeout(timeouts[1].clone()), Some(2));
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   116
        assert_eq!(events.poll(now + second), vec![1]);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   117
        assert!(events.poll(now + second).is_empty());
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   118
        assert!(events.poll(now + 2 * second).is_empty());
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   119
        assert_eq!(events.poll(now + 3 * second), vec![3]);
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   120
    }
ed3b510b860c add polled timer
alfadur
parents:
diff changeset
   121
}