aqt_sim/
packet.rs

1//! This module contains structs and types related to packets in the AQT model, including the
2//! Packet struct itself as well as a PacketFactory and PacketPath (which is just a vector of
3//! NodeIDs determining the route the Packet should follow).
4
5use std::fmt;
6use crate::network::NodeID;
7
8
9/// The `Packet` struct represents a packet in AQT. It includes:
10/// - An id, which is unique,
11/// - A `PacketPath` for the packet to follow in the network,
12/// - An index into the packet's path so we know where the packet currently is, and
13/// - The packet's injection round.
14///
15/// We enforce the ID uniqueness by *only* allowing packets to be created via the `PacketFactory`
16/// struct.
17#[derive(Clone)]
18pub struct Packet {
19    id: usize,
20    path: PacketPath,
21    path_idx: usize,
22    injection_rd: usize,
23}
24
25impl Packet {
26    /// Increment the index into the `PacketPath`. We need to keep this in sync with the packet's 
27    /// state in the `Network` so we can quickly forward packets.
28    pub fn increment_path_idx(&mut self) {
29        if self.is_absorbed() {
30            panic!("Packet has already been absorbed.");
31        }
32        self.path_idx += 1;
33    }
34
35    /// Decrement the index into the `PacketPath`. We need to keep this in sync with the packet's 
36    /// state in the `Network` so we can quickly forward packets.
37    pub fn decrement_path_idx(&mut self) {
38        if self.path_idx == 0 {
39            panic!("Packet is already at the beginning of its path.");
40        }
41        self.path_idx -= 1;
42    }
43
44    /// Check whether this packet is absorbed.
45    pub fn is_absorbed(&self) -> bool {
46        self.path_idx == self.path.len()
47    }
48
49    /// Check whether this packet should be absorbed the next time it is forwarded.
50    pub fn should_be_absorbed(&self) -> bool {
51        self.path_idx == self.path.len()-1
52    }
53
54    pub fn get_injection_rd(&self) -> usize {
55        self.injection_rd
56    }
57
58    /// Get the id of the current `Node` that this packet occupies. Returns `None` if the packet
59    /// has been absorbed.
60    pub fn cur_node(&self) -> Option<NodeID> {
61        match self.path.get(self.path_idx) {
62            Some(next_id) => Some(*next_id),
63            None => None,
64        }
65    }
66
67    /// Get the id of the next `Node` that this packet will occupy if forwarded in its path. 
68    /// Returns `None` if the packet has been absorbed or is about to be absorbed. 
69    pub fn next_node(&self) -> Option<NodeID> {
70        match self.path.get(self.path_idx + 1) {
71            Some(next_id) => Some(*next_id),
72            None => None,
73        }
74    }
75
76    /// Get the number of steps that this packet needs to travel in the network in order to be
77    /// absorbed, including the absorption step.
78    pub fn dist_to_go(&self) -> usize {
79        self.path.len() - self.path_idx + 1
80    }
81
82    /// Get the current index into the `PacketPath`.
83    pub fn get_path_idx(&self) -> usize {
84        self.path_idx
85    }
86
87    /// Get a reference to this packet's path.
88    pub fn get_path(&self) -> &PacketPath {
89        &self.path
90    }
91
92    /// Get a mutable reference to this packet's path.
93    pub fn get_path_mut(&mut self) -> &mut PacketPath {
94        &mut self.path
95    }
96}
97
98impl fmt::Debug for Packet {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        f.debug_struct("Packet")
101            .field("id", &self.id)
102            .field("cur_node", &self.cur_node())
103            .field("injection_rd", &self.injection_rd)
104            .finish()
105    }
106}
107
108impl PartialEq for Packet {
109    fn eq(&self, other: &Self) -> bool {
110        self.id == other.id
111    }
112}
113
114
115/// This struct allows for the creation of `Packet`s with unique ids. We thus require all `Packet`s
116/// to be created through a `PacketFactory`.
117pub struct PacketFactory {
118    cur_id: usize,
119}
120
121impl PacketFactory {
122    /// Create a new `PacketFactory`.
123    pub fn new() -> Self {
124        PacketFactory { cur_id: 0 }
125    }
126
127    /// Create a new `Packet`.
128    pub fn create_packet(
129        &mut self,
130        path: PacketPath,
131        injection_rd: usize,
132        path_idx: usize,
133    ) -> Packet {
134        let p = Packet {id: self.cur_id, path, path_idx, injection_rd };
135        self.cur_id += 1;
136        p
137    }
138}
139
140
141/// The path of `Node`s that a `Packet` will take through a `Network`.
142pub type PacketPath = Vec<NodeID>;
143
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    #[should_panic]
151    fn test_iter_through_path() {
152        let mut packet_factory = PacketFactory::new();
153        let mut p = packet_factory.create_packet(vec![1, 4, 9, 16], 0, 0);
154        assert_eq!(p.get_path_idx(), 0);
155        assert_eq!(p.cur_node().unwrap(), 1);
156        assert_eq!(p.next_node().unwrap(), 4);
157        assert_eq!(p.dist_to_go(), 4);
158
159        p.increment_path_idx();
160
161        assert_eq!(p.get_path_idx(), 1);
162        assert_eq!(p.cur_node().unwrap(), 4);
163        assert_eq!(p.next_node().unwrap(), 9);
164        assert_eq!(p.dist_to_go(), 3);
165
166        p.increment_path_idx();
167        p.increment_path_idx();
168
169        assert_eq!(p.dist_to_go(), 1);
170        assert_eq!(p.next_node(), None);
171        p.increment_path_idx();
172        assert_eq!(p.dist_to_go(), 0);
173        assert_eq!(p.cur_node(), None);
174        assert_eq!(p.next_node(), None);
175        assert!(p.is_absorbed());
176        
177        // Should panic here; we don't want to allow iteration if the packet is already absorbed.
178        p.increment_path_idx();
179    }
180
181}