use stun_types::{attribute::*, message::StunParseError};
#[derive(Debug, Clone)]
pub struct Data<'a> {
data: stun_types::data::Data<'a>,
}
impl AttributeStaticType for Data<'_> {
const TYPE: AttributeType = AttributeType::new(0x0013);
}
impl Attribute for Data<'_> {
fn get_type(&self) -> AttributeType {
Self::TYPE
}
fn length(&self) -> u16 {
self.data.len() as u16
}
}
impl AttributeWrite for Data<'_> {
fn to_raw(&self) -> RawAttribute<'_> {
RawAttribute::new(self.get_type(), &self.data)
}
fn write_into_unchecked(&self, dest: &mut [u8]) {
self.write_header_unchecked(dest);
dest[4..4 + self.data.len()].copy_from_slice(&self.data);
dest[4 + self.data.len()..self.padded_len()].fill(0);
}
}
impl<'a> AttributeFromRaw<'a> for Data<'a> {
fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
where
Self: Sized,
{
raw.check_type_and_len(Self::TYPE, ..)?;
Ok(Self {
data: raw.value.clone().into_owned(),
})
}
fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
where
Self: Sized,
{
Self::try_from(raw)
}
}
impl<'a> TryFrom<RawAttribute<'a>> for Data<'a> {
type Error = StunParseError;
fn try_from(raw: RawAttribute<'a>) -> Result<Self, Self::Error> {
raw.check_type_and_len(Self::TYPE, ..)?;
Ok(Self { data: raw.value })
}
}
impl<'a> Data<'a> {
pub fn new(data: &'a [u8]) -> Self {
if data.len() > u16::MAX as usize {
panic!(
"Attempt made to create a Data attribute larger than {}",
u16::MAX
);
}
Self {
data: stun_types::data::Data::from(data),
}
}
pub fn data(&self) -> &[u8] {
&self.data
}
}
impl core::fmt::Display for Data<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}: len:{}", self.get_type(), self.data.len())
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
use alloc::vec::Vec;
use byteorder::{BigEndian, ByteOrder};
use tracing::trace;
#[test]
fn data() {
let _log = crate::tests::test_init_log();
let bytes = vec![0, 1, 2, 3, 4, 5];
let data = Data::new(&bytes);
assert_eq!(data.get_type(), Data::TYPE);
assert_eq!(data.data(), &bytes);
}
#[test]
fn data_raw() {
let _log = crate::tests::test_init_log();
let bytes = vec![0, 1, 2, 3, 4, 5];
let data = Data::new(&bytes);
let raw: RawAttribute = data.to_raw();
trace!("{}", raw);
assert_eq!(raw.get_type(), Data::TYPE);
let data2 = Data::try_from(raw.clone()).unwrap();
assert_eq!(data2.get_type(), Data::TYPE);
assert_eq!(data2.data(), &bytes);
}
#[test]
fn data_raw_wrong_type() {
let _log = crate::tests::test_init_log();
let bytes = vec![0, 1, 2, 3, 4, 5];
let data = Data::new(&bytes);
let raw: RawAttribute = data.to_raw();
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Data::try_from(RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongAttributeImplementation)
));
}
#[test]
fn data_write_into() {
let _log = crate::tests::test_init_log();
let bytes = vec![0, 1, 2, 3];
let data = Data::new(&bytes);
let raw: RawAttribute = data.to_raw();
let mut dest = vec![0; raw.padded_len()];
data.write_into(&mut dest).unwrap();
let raw = RawAttribute::from_bytes(&dest).unwrap();
let data2 = Data::try_from(raw.clone()).unwrap();
assert_eq!(data2.get_type(), Data::TYPE);
assert_eq!(data2.data(), &bytes);
}
#[test]
#[should_panic = "out of range"]
fn data_write_into_unchecked() {
let _log = crate::tests::test_init_log();
let bytes = vec![0, 1, 2, 3, 4, 5];
let data = Data::new(&bytes);
let raw: RawAttribute = data.to_raw();
let mut dest = vec![0; raw.padded_len() - 1];
data.write_into_unchecked(&mut dest);
}
}