Skip to main content

naia_shared/connection/
ping_store.rs

1use std::collections::VecDeque;
2
3use crate::{sequence_greater_than, GameInstant};
4
5/// Monotone wrapping sequence number used to correlate pings and pongs.
6pub type PingIndex = u16;
7
8const SENT_PINGS_HISTORY_SIZE: u16 = 32;
9
10/// Circular buffer that records the send time of outstanding pings indexed by [`PingIndex`].
11pub struct PingStore {
12    ping_index: PingIndex,
13    // front big, back small
14    // front recent, back past
15    buffer: VecDeque<(PingIndex, GameInstant)>,
16}
17
18impl Default for PingStore {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl PingStore {
25    /// Creates an empty `PingStore`.
26    pub fn new() -> Self {
27        PingStore {
28            ping_index: 0,
29            buffer: VecDeque::new(),
30        }
31    }
32
33    /// Records a new ping sent at `now` and returns its assigned index.
34    pub fn push_new(&mut self, now: GameInstant) -> PingIndex {
35        // save current ping index and add a new ping instant associated with it
36        let ping_index = self.ping_index;
37        self.ping_index = self.ping_index.wrapping_add(1);
38        self.buffer.push_front((ping_index, now));
39
40        // a good time to prune down the size of this buffer
41        while self.buffer.len() > SENT_PINGS_HISTORY_SIZE.into() {
42            self.buffer.pop_back();
43        }
44
45        ping_index
46    }
47
48    /// Removes and returns the send-time for the given `ping_index`, or `None` if not found.
49    pub fn remove(&mut self, ping_index: PingIndex) -> Option<GameInstant> {
50        let mut vec_index = self.buffer.len();
51
52        if vec_index == 0 {
53            return None;
54        }
55
56        let mut found = false;
57
58        loop {
59            vec_index -= 1;
60
61            if let Some((old_index, _)) = self.buffer.get(vec_index) {
62                if *old_index == ping_index {
63                    //found it!
64                    found = true;
65                } else {
66                    // if old_index is bigger than ping_index, give up, it's only getting
67                    // bigger
68                    if sequence_greater_than(*old_index, ping_index) {
69                        return None;
70                    }
71                }
72            }
73
74            if found {
75                let (_, ping_instant) = self.buffer.remove(vec_index).unwrap();
76                return Some(ping_instant);
77            }
78
79            // made it to the front
80            if vec_index == 0 {
81                return None;
82            }
83        }
84    }
85
86    /// Clears all pending ping records.
87    pub fn clear(&mut self) {
88        self.buffer.clear();
89    }
90}