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