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