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