rust/hedgewars-server/src/core/events.rs
changeset 15939 4a8e6f9d5133
parent 15938 ce47259d5c86
child 15940 ea370bfda705
equal deleted inserted replaced
15938:ce47259d5c86 15939:4a8e6f9d5133
     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     events_count: u32,
       
    27 }
       
    28 
       
    29 impl<Data, const MAX_TIMEOUT: usize> TimedEvents<Data, MAX_TIMEOUT> {
       
    30     pub fn new() -> Self {
       
    31         Self {
       
    32             events: [0; MAX_TIMEOUT].map(|_| Slab::new()),
       
    33             current_time: Instant::now(),
       
    34             current_tick_index: 0,
       
    35             next_event_id: 0,
       
    36             events_count: 0,
       
    37         }
       
    38     }
       
    39 
       
    40     pub fn set_timeout(&mut self, seconds_delay: NonZeroU32, data: Data) -> Timeout {
       
    41         let tick_index = (self.current_tick_index
       
    42             + std::cmp::min(seconds_delay.get(), MAX_TIMEOUT as u32))
       
    43             % MAX_TIMEOUT as u32;
       
    44         let event_id = self.next_event_id;
       
    45         self.next_event_id += 1;
       
    46         let event = Event { event_id, data };
       
    47 
       
    48         let entry = self.events[tick_index as usize].vacant_entry();
       
    49         let event_index = entry.key() as u32;
       
    50         entry.insert(event);
       
    51 
       
    52         self.events_count += 1;
       
    53 
       
    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             self.events_count -= 1;
       
    66             Some(events.remove(timeout.event_index as usize).data)
       
    67         } else {
       
    68             None
       
    69         }
       
    70     }
       
    71 
       
    72     pub fn poll(&mut self, time: Instant) -> Vec<Data> {
       
    73         let mut result = vec![];
       
    74         let second = Duration::from_secs(1);
       
    75         while time - self.current_time > second {
       
    76             self.current_time += second;
       
    77             self.current_tick_index = (self.current_tick_index + 1) % MAX_TIMEOUT as u32;
       
    78             result.extend(
       
    79                 self.events[self.current_tick_index as usize]
       
    80                     .drain()
       
    81                     .map(|e| e.data),
       
    82             );
       
    83         }
       
    84         self.events_count -= result.len() as u32;
       
    85         result
       
    86     }
       
    87 
       
    88     pub fn is_empty(&self) -> bool {
       
    89         self.events_count == 0
       
    90     }
       
    91 }
       
    92 
       
    93 mod test {
       
    94     use super::TimedEvents;
       
    95     use std::{
       
    96         num::NonZeroU32,
       
    97         time::{Duration, Instant},
       
    98     };
       
    99 
       
   100     #[test]
       
   101     fn events_test() {
       
   102         let mut events = TimedEvents::<u32, 30>::new();
       
   103         let now = Instant::now();
       
   104 
       
   105         let timeouts = (1..=3)
       
   106             .map(|n| events.set_timeout(NonZeroU32::new(n).unwrap(), n))
       
   107             .collect::<Vec<_>>();
       
   108 
       
   109         let second = Duration::from_secs(1);
       
   110         assert_eq!(events.cancel_timeout(timeouts[1].clone()), Some(2));
       
   111         assert_eq!(events.poll(now + second), vec![1]);
       
   112         assert!(events.poll(now + second).is_empty());
       
   113         assert!(events.poll(now + 2 * second).is_empty());
       
   114         assert_eq!(events.poll(now + 3 * second), vec![3]);
       
   115     }
       
   116 }