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