turn_types/attribute/
connection.rs1use byteorder::{BigEndian, ByteOrder};
12use stun_types::{attribute::*, message::StunParseError};
13
14#[derive(Debug, Clone)]
20pub struct ConnectionId {
21 id: u32,
22}
23
24impl AttributeStaticType for ConnectionId {
25 const TYPE: AttributeType = AttributeType::new(0x002a);
26}
27
28impl Attribute for ConnectionId {
29 fn get_type(&self) -> AttributeType {
30 Self::TYPE
31 }
32
33 fn length(&self) -> u16 {
34 4
35 }
36}
37
38impl AttributeWrite for ConnectionId {
39 fn to_raw(&self) -> RawAttribute<'_> {
40 let mut data = [0; 4];
41 BigEndian::write_u32(&mut data, self.id);
42 RawAttribute::new(self.get_type(), &data).into_owned()
43 }
44
45 fn write_into_unchecked(&self, dest: &mut [u8]) {
46 self.write_header_unchecked(dest);
47 BigEndian::write_u32(&mut dest[4..8], self.id);
48 }
49}
50
51impl AttributeFromRaw<'_> for ConnectionId {
52 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
53 where
54 Self: Sized,
55 {
56 Self::try_from(raw)
57 }
58}
59
60impl TryFrom<&RawAttribute<'_>> for ConnectionId {
61 type Error = StunParseError;
62 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
63 raw.check_type_and_len(Self::TYPE, 4..=4)?;
64 Ok(Self {
65 id: BigEndian::read_u32(&raw.value[..4]),
66 })
67 }
68}
69
70impl ConnectionId {
71 pub fn new(id: u32) -> Self {
81 Self { id }
82 }
83
84 pub fn id(&self) -> u32 {
94 self.id
95 }
96}
97
98impl core::fmt::Display for ConnectionId {
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 write!(f, "{}: {:x?}", self.get_type(), self.id())
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use alloc::vec::Vec;
108 use byteorder::{BigEndian, ByteOrder};
109 use tracing::trace;
110
111 #[test]
112 fn requested_transport() {
113 let _log = crate::tests::test_init_log();
114 let trans = ConnectionId::new(17);
115 assert_eq!(trans.get_type(), ConnectionId::TYPE);
116 assert_eq!(trans.id(), 17);
117 }
118
119 #[test]
120 fn requested_transport_raw() {
121 let _log = crate::tests::test_init_log();
122 let trans = ConnectionId::new(17);
123 assert_eq!(trans.get_type(), ConnectionId::TYPE);
124 assert_eq!(trans.id(), 17);
125 let raw: RawAttribute = trans.to_raw();
126 trace!("raw: {raw:?}");
127 assert_eq!(raw.get_type(), ConnectionId::TYPE);
128 let trans2 = ConnectionId::try_from(&raw).unwrap();
129 assert_eq!(trans2.get_type(), ConnectionId::TYPE);
130 assert_eq!(trans2.id(), 17);
131 }
132
133 #[test]
134 fn requested_transport_raw_wrong_type() {
135 let _log = crate::tests::test_init_log();
136 let trans = ConnectionId::new(17);
137 assert_eq!(trans.get_type(), ConnectionId::TYPE);
138 assert_eq!(trans.id(), 17);
139 let raw: RawAttribute = trans.to_raw();
140 let mut data: Vec<_> = raw.into();
142 BigEndian::write_u16(&mut data[0..2], 0);
143 assert!(matches!(
144 ConnectionId::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
145 Err(StunParseError::WrongAttributeImplementation)
146 ));
147 }
148
149 #[test]
150 fn requested_transport_write_into() {
151 let _log = crate::tests::test_init_log();
152 let trans = ConnectionId::new(17);
153 assert_eq!(trans.get_type(), ConnectionId::TYPE);
154 assert_eq!(trans.id(), 17);
155 let mut data = [0; 8];
156 trans.write_into(&mut data).unwrap();
157 let raw = RawAttribute::from_bytes(&data).unwrap();
158 let trans2 = ConnectionId::from_raw_ref(&raw).unwrap();
159 assert_eq!(trans.id(), trans2.id());
160 }
161
162 #[test]
163 #[should_panic = "out of range"]
164 fn requested_transport_write_into_unchecked() {
165 let _log = crate::tests::test_init_log();
166 let trans = ConnectionId::new(17);
167 assert_eq!(trans.get_type(), ConnectionId::TYPE);
168 assert_eq!(trans.id(), 17);
169 let mut data = [0; 7];
170 trans.write_into_unchecked(&mut data);
171 }
172}