Skip to main content

nxtquic_sim/
channel.rs

1use std::collections::VecDeque;
2use std::net::SocketAddr;
3use std::time::Instant;
4
5/// Represents a datagram that has been queued for simulated delivery.
6#[derive(Debug, Clone)]
7pub struct QueuedDatagram {
8    /// The instant at which this datagram should be delivered.
9    pub delivery_time: Instant,
10    /// The raw payload of the datagram.
11    pub payload: Vec<u8>,
12    /// The source address of the datagram.
13    pub src: SocketAddr,
14    /// The destination address of the datagram.
15    pub dst: SocketAddr,
16}
17
18/// A simulated network channel that holds queued datagrams and delivers them at the scheduled `Instant`.
19#[derive(Debug, Default)]
20pub struct SimChannel {
21    queue: VecDeque<QueuedDatagram>,
22}
23
24impl SimChannel {
25    /// Creates a new `SimChannel`.
26    pub fn new() -> Self {
27        Self {
28            queue: VecDeque::new(),
29        }
30    }
31
32    /// Pushes a new datagram into the channel, maintaining delivery order.
33    pub fn push(&mut self, datagram: QueuedDatagram) {
34        // Keep the queue sorted by delivery_time
35        let idx = self
36            .queue
37            .binary_search_by_key(&datagram.delivery_time, |d| d.delivery_time)
38            .unwrap_or_else(|x| x);
39        self.queue.insert(idx, datagram);
40    }
41
42    /// Pops the next ready datagram from the channel, if its delivery time is <= `now`.
43    pub fn pop_ready(&mut self, now: Instant) -> Option<QueuedDatagram> {
44        if let Some(front) = self.queue.front() {
45            if front.delivery_time <= now {
46                return self.queue.pop_front();
47            }
48        }
49        None
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use std::time::Duration;
57
58    #[test]
59    fn test_sim_channel_ordering() {
60        let mut channel = SimChannel::new();
61        let now = Instant::now();
62        let src: SocketAddr = "127.0.0.1:1000".parse().unwrap();
63        let dst: SocketAddr = "127.0.0.1:2000".parse().unwrap();
64
65        channel.push(QueuedDatagram {
66            delivery_time: now + Duration::from_millis(20),
67            payload: vec![2],
68            src,
69            dst,
70        });
71
72        channel.push(QueuedDatagram {
73            delivery_time: now + Duration::from_millis(10),
74            payload: vec![1],
75            src,
76            dst,
77        });
78
79        // The one with 10ms delay should be popped first
80        assert!(channel.pop_ready(now).is_none());
81        assert!(channel.pop_ready(now + Duration::from_millis(15)).is_some());
82        assert!(channel.pop_ready(now + Duration::from_millis(15)).is_none());
83
84        let next = channel.pop_ready(now + Duration::from_millis(25)).unwrap();
85        assert_eq!(next.payload, vec![2]);
86    }
87}