atm0s_sdn_identity/
conn_id.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::{Debug, Formatter};
3use std::hash::{Hash, Hasher};
4
5#[derive(Deserialize, Serialize, Copy, Clone)]
6pub struct ConnId {
7    protocol: u8,
8    direction: ConnDirection,
9    session: u64,
10}
11
12#[derive(Deserialize, Serialize, Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
13#[repr(u8)]
14pub enum ConnDirection {
15    Outgoing = 0,
16    Incoming = 1,
17}
18
19impl ConnId {
20    /// Creates a new `ConnId` from the given protocol, connection direction, and UUID.
21    ///
22    /// # Arguments
23    ///
24    /// * `protocol` - A `u8` representing the protocol used for the connection.
25    /// * `direction` - A `ConnDirection` enum representing the direction of the connection.
26    /// * `session` - A `u64` representing the UUID of the connection.
27    ///
28    /// # Returns
29    ///
30    /// A new `ConnId` instance.
31    pub fn from_raw(protocol: u8, direction: ConnDirection, session: u64) -> ConnId {
32        ConnId { protocol, direction, session }
33    }
34
35    /// Creates a new outgoing `ConnId` from the given `protocol` and `session`.
36    ///
37    /// # Arguments
38    ///
39    /// * `protocol` - An unsigned 8-bit integer representing the protocol.
40    /// * `session` - An unsigned 64-bit integer representing the UUID.
41    ///
42    /// # Returns
43    ///
44    /// A new `ConnId` instance.
45    pub fn from_out(protocol: u8, session: u64) -> ConnId {
46        Self::from_raw(protocol, ConnDirection::Outgoing, session)
47    }
48
49    /// Creates a new incoming `ConnId` from the given `protocol` and `session`.
50    ///
51    /// # Arguments
52    ///
53    /// * `protocol` - A `u8` representing the protocol.
54    /// * `session` - A `u64` representing the UUID.
55    ///
56    /// # Returns
57    ///
58    /// A new incoming `ConnId` instance.
59    ///
60    /// # Example
61    ///
62    /// ```
63    /// use atm0s_sdn_identity::ConnId;
64    ///
65    /// let conn_id = ConnId::from_in(1, 123456789);
66    /// ```
67    pub fn from_in(protocol: u8, session: u64) -> ConnId {
68        Self::from_raw(protocol, ConnDirection::Incoming, session)
69    }
70
71    /// Returns the protocol of the connection ID.
72    pub fn protocol(&self) -> u8 {
73        self.protocol
74    }
75
76    /// Returns the direction of the connection.
77    pub fn direction(&self) -> ConnDirection {
78        self.direction
79    }
80    /// Returns `true` if the connection is outgoing, `false` otherwise.
81    pub fn is_outgoing(&self) -> bool {
82        self.direction() == ConnDirection::Outgoing
83    }
84
85    /// Returns the UUID of the connection ID.
86    pub fn session(&self) -> u64 {
87        self.session
88    }
89}
90
91impl std::fmt::Display for ConnId {
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        let str = format!("Conn({:?},{},0x{:x})", self.direction(), self.protocol(), self.session());
94        std::fmt::Display::fmt(&str, f)
95    }
96}
97
98impl Debug for ConnId {
99    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100        let str = format!("Conn({:?},{},0x{:x})", self.direction(), self.protocol(), self.session());
101        Debug::fmt(&str, f)
102    }
103}
104
105impl PartialEq<Self> for ConnId {
106    fn eq(&self, other: &Self) -> bool {
107        //compare both session and direction
108        self.session == other.session && self.direction == other.direction
109    }
110}
111
112impl Eq for ConnId {}
113
114impl Hash for ConnId {
115    fn hash<H: Hasher>(&self, state: &mut H) {
116        state.write_u8(self.direction as u8);
117        state.write_u64(self.session);
118    }
119}
120
121impl PartialOrd<Self> for ConnId {
122    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
123        //compare both session and direction
124        Some(self.cmp(other))
125    }
126}
127
128impl Ord for ConnId {
129    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
130        //compare both session and direction
131        if self.session == other.session {
132            self.direction.cmp(&other.direction)
133        } else {
134            self.session.cmp(&other.session)
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_conn_id_from_out() {
145        let conn_id = ConnId::from_out(1, 123);
146        assert_eq!(conn_id.protocol(), 1);
147        assert_eq!(conn_id.direction(), ConnDirection::Outgoing);
148        assert_eq!(conn_id.session(), 123);
149    }
150
151    #[test]
152    fn test_conn_id_from_in() {
153        let conn_id = ConnId::from_in(2, 456);
154        assert_eq!(conn_id.protocol(), 2);
155        assert_eq!(conn_id.direction(), ConnDirection::Incoming);
156        assert_eq!(conn_id.session(), 456);
157    }
158
159    #[test]
160    fn test_conn_id_display() {
161        let conn_id = ConnId::from_out(3, 0x789);
162        assert_eq!(format!("{}", conn_id), "Conn(Outgoing,3,0x789)");
163    }
164
165    #[test]
166    fn test_conn_id_debug() {
167        let conn_id = ConnId::from_in(4, 0x101112);
168        assert_eq!(format!("{:?}", conn_id), "\"Conn(Incoming,4,0x101112)\"");
169    }
170
171    #[test]
172    fn test_conn_id_eq() {
173        let conn_id1 = ConnId::from_out(5, 131415);
174        let conn_id2 = ConnId::from_out(5, 131415);
175        let conn_id3 = ConnId::from_in(5, 131415);
176        assert_eq!(conn_id1, conn_id2);
177        assert_ne!(conn_id1, conn_id3);
178    }
179
180    #[test]
181    fn test_conn_id_hash() {
182        let conn_id1 = ConnId::from_out(6, 161718);
183        let conn_id2 = ConnId::from_out(6, 161718);
184        let conn_id3 = ConnId::from_in(6, 161718);
185        let mut set = std::collections::HashSet::new();
186        set.insert(conn_id1);
187        assert!(set.contains(&conn_id1));
188        assert!(set.contains(&conn_id2));
189        assert!(!set.contains(&conn_id3));
190    }
191}