Skip to main content

nxtquic_sim/
channel.rs

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