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///
13/// Holds a sequence of bytes to transfer.
14///
15/// Reference: [RFC5766 Section 14.4](https://datatracker.ietf.org/doc/html/rfc5766#section-14.4).
16#[derive(Debug, Clone)]
17pub struct Data<'a> {
18    data: stun_types::data::Data<'a>,
19}
20
21impl AttributeStaticType for Data<'_> {
22    const TYPE: AttributeType = AttributeType::new(0x0013);
23}
24
25impl Attribute for Data<'_> {
26    fn get_type(&self) -> AttributeType {
27        Self::TYPE
28    }
29
30    fn length(&self) -> u16 {
31        self.data.len() as u16
32    }
33}
34
35impl AttributeWrite for Data<'_> {
36    fn to_raw(&self) -> RawAttribute<'_> {
37        RawAttribute::new(self.get_type(), &self.data)
38    }
39
40    fn write_into_unchecked(&self, dest: &mut [u8]) {
41        self.write_header_unchecked(dest);
42        dest[4..4 + self.data.len()].copy_from_slice(&self.data);
43    }
44}
45
46impl<'a> AttributeFromRaw<'a> for Data<'a> {
47    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
48    where
49        Self: Sized,
50    {
51        raw.check_type_and_len(Self::TYPE, ..)?;
52        Ok(Self {
53            data: raw.value.clone().into_owned(),
54        })
55    }
56
57    fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
58    where
59        Self: Sized,
60    {
61        Self::try_from(raw)
62    }
63}
64
65impl<'a> TryFrom<RawAttribute<'a>> for Data<'a> {
66    type Error = StunParseError;
67
68    fn try_from(raw: RawAttribute<'a>) -> Result<Self, Self::Error> {
69        raw.check_type_and_len(Self::TYPE, ..)?;
70        Ok(Self { data: raw.value })
71    }
72}
73
74impl<'a> Data<'a> {
75    /// Create a new Data [`Attribute`].
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// # use turn_types::attribute::*;
81    /// let bytes = vec![0, 1, 2];
82    /// let data = Data::new(&bytes);
83    /// assert_eq!(data.data(), &bytes);
84    /// ```
85    pub fn new(data: &'a [u8]) -> Self {
86        if data.len() > u16::MAX as usize {
87            panic!(
88                "Attempt made to create a Data attribute larger than {}",
89                u16::MAX
90            );
91        }
92        Self {
93            data: stun_types::data::Data::from(data),
94        }
95    }
96
97    /// Retrieve the data stored in a [`Data`].
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// # use turn_types::attribute::*;
103    /// let bytes = vec![0, 1, 2];
104    /// let data = Data::new(&bytes);
105    /// assert_eq!(data.data(), &bytes);
106    /// ```
107    pub fn data(&self) -> &[u8] {
108        &self.data
109    }
110}
111
112impl core::fmt::Display for Data<'_> {
113    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
114        write!(f, "{}: len:{}", self.get_type(), self.data.len())
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use alloc::vec;
122    use alloc::vec::Vec;
123    use byteorder::{BigEndian, ByteOrder};
124    use std::println;
125
126    #[test]
127    fn data() {
128        let _log = crate::tests::test_init_log();
129        let bytes = vec![0, 1, 2, 3, 4, 5];
130        let data = Data::new(&bytes);
131        assert_eq!(data.get_type(), Data::TYPE);
132        assert_eq!(data.data(), &bytes);
133        let raw: RawAttribute = data.to_raw();
134        println!("{}", raw);
135        assert_eq!(raw.get_type(), Data::TYPE);
136        let data2 = Data::try_from(raw.clone()).unwrap();
137        assert_eq!(data2.get_type(), Data::TYPE);
138        assert_eq!(data2.data(), &bytes);
139        // provide incorrectly typed data
140        let mut data: Vec<_> = raw.into();
141        BigEndian::write_u16(&mut data[0..2], 0);
142        assert!(matches!(
143            Data::try_from(RawAttribute::from_bytes(data.as_ref()).unwrap()),
144            Err(StunParseError::WrongAttributeImplementation)
145        ));
146    }
147}