turn_types/attribute/
data.rs

1// Copyright (C) 2025 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use stun_types::{attribute::*, message::StunParseError};
10
11/// The Data [`Attribute`]
12#[derive(Debug, Clone)]
13pub struct Data<'a> {
14    data: stun_types::data::Data<'a>,
15}
16
17impl AttributeStaticType for Data<'_> {
18    const TYPE: AttributeType = AttributeType::new(0x0013);
19}
20
21impl Attribute for Data<'_> {
22    fn get_type(&self) -> AttributeType {
23        Self::TYPE
24    }
25
26    fn length(&self) -> u16 {
27        self.data.len() as u16
28    }
29}
30
31impl AttributeWrite for Data<'_> {
32    fn to_raw(&self) -> RawAttribute {
33        RawAttribute::new(self.get_type(), &self.data)
34    }
35
36    fn write_into_unchecked(&self, dest: &mut [u8]) {
37        self.write_header_unchecked(dest);
38        dest[4..4 + self.data.len()].copy_from_slice(&self.data);
39    }
40}
41
42impl<'a> AttributeFromRaw<'a> for Data<'a> {
43    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
44    where
45        Self: Sized,
46    {
47        raw.check_type_and_len(Self::TYPE, ..)?;
48        Ok(Self {
49            data: raw.value.clone().into_owned(),
50        })
51    }
52
53    fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
54    where
55        Self: Sized,
56    {
57        Self::try_from(raw)
58    }
59}
60
61impl<'a> TryFrom<RawAttribute<'a>> for Data<'a> {
62    type Error = StunParseError;
63
64    fn try_from(raw: RawAttribute<'a>) -> Result<Self, Self::Error> {
65        raw.check_type_and_len(Self::TYPE, ..)?;
66        Ok(Self { data: raw.value })
67    }
68}
69
70impl<'a> Data<'a> {
71    /// Create a new Data [`Attribute`]
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// # use turn_types::attribute::*;
77    /// let bytes = vec![0, 1, 2];
78    /// let data = Data::new(&bytes);
79    /// assert_eq!(data.data(), &bytes);
80    /// ```
81    pub fn new(data: &'a [u8]) -> Self {
82        if data.len() > u16::MAX as usize {
83            panic!(
84                "Attempt made to create a Data attribute larger than {}",
85                u16::MAX
86            );
87        }
88        Self {
89            data: stun_types::data::Data::from(data),
90        }
91    }
92
93    /// Retrieve the data stored in a [Data]
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// # use turn_types::attribute::*;
99    /// let bytes = vec![0, 1, 2];
100    /// let data = Data::new(&bytes);
101    /// assert_eq!(data.data(), &bytes);
102    /// ```
103    pub fn data(&self) -> &[u8] {
104        &self.data
105    }
106}
107
108impl std::fmt::Display for Data<'_> {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        write!(f, "{}: len:{}", self.get_type(), self.data.len())
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use byteorder::{BigEndian, ByteOrder};
118
119    #[test]
120    fn data() {
121        let _log = crate::tests::test_init_log();
122        let bytes = vec![0, 1, 2, 3, 4, 5];
123        let data = Data::new(&bytes);
124        assert_eq!(data.get_type(), Data::TYPE);
125        assert_eq!(data.data(), &bytes);
126        let raw: RawAttribute = data.to_raw();
127        println!("{}", raw);
128        assert_eq!(raw.get_type(), Data::TYPE);
129        let data2 = Data::try_from(raw.clone()).unwrap();
130        assert_eq!(data2.get_type(), Data::TYPE);
131        assert_eq!(data2.data(), &bytes);
132        // provide incorrectly typed data
133        let mut data: Vec<_> = raw.into();
134        BigEndian::write_u16(&mut data[0..2], 0);
135        assert!(matches!(
136            Data::try_from(RawAttribute::from_bytes(data.as_ref()).unwrap()),
137            Err(StunParseError::WrongAttributeImplementation)
138        ));
139    }
140}