use crate::ietf::udp::{Checksum, Port};
use crate::{Buf, BufError, BufMut, BufResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HeaderMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> HeaderMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
}
impl<T: Buf> HeaderMapping<T> {
pub fn read_source_port(&self) -> Port {
unsafe { Port::from(self.buffer.get_u16_be_unchecked(0)) }
}
pub fn read_destination_port(&self) -> Port {
unsafe { Port::from(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_length(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(6)) }
}
}
impl<T: BufMut> HeaderMapping<T> {
pub fn write_source_port(&mut self, port: Port) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(0, port.into()) }
Ok(())
}
pub fn write_destination_port(&mut self, port: Port) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, port.into()) }
Ok(())
}
pub fn write_length(&mut self, length: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, length) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, checksum.0) }
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{Checksum, HeaderMapping, Port};
#[test]
fn read_fields() {
let buffer = [
0x00, 0x35, 0xC3, 0x50, 0x00, 0x10, 0x12, 0x34, ];
let mapping = HeaderMapping::new(&buffer[..]);
assert_eq!(mapping.read_source_port(), Port::DNS);
assert_eq!(mapping.read_destination_port(), Port::from(50000));
assert_eq!(mapping.read_length(), 16);
assert_eq!(mapping.read_checksum(), Checksum(0x1234));
}
#[test]
fn write_fields() {
let mut buffer = [0u8; 8];
let mut mapping = HeaderMapping::new(&mut buffer[..]);
mapping.write_source_port(Port::DNS).unwrap();
mapping.write_destination_port(Port::from(50000)).unwrap();
mapping.write_length(16).unwrap();
mapping.write_checksum(Checksum(0x1234)).unwrap();
assert_eq!(buffer, [0x00, 0x35, 0xC3, 0x50, 0x00, 0x10, 0x12, 0x34,]);
}
#[test]
fn roundtrip() {
let mut buffer = [0u8; 8];
let mut mapping = HeaderMapping::new(&mut buffer[..]);
let source_port = Port::DNS;
let destination_port = Port::from(50000);
let length = 16u16;
let checksum = Checksum(0x1234);
mapping.write_source_port(source_port).unwrap();
mapping.write_destination_port(destination_port).unwrap();
mapping.write_length(length).unwrap();
mapping.write_checksum(checksum).unwrap();
let read_mapping = HeaderMapping::new(&buffer[..]);
assert_eq!(read_mapping.read_source_port(), source_port);
assert_eq!(read_mapping.read_destination_port(), destination_port);
assert_eq!(read_mapping.read_length(), length);
assert_eq!(read_mapping.read_checksum(), checksum);
}
#[test]
fn into_inner() {
let buffer = [0u8; 8];
let mapping = HeaderMapping::new(&buffer[..]);
let inner = mapping.into_inner();
assert_eq!(inner.len(), 8);
}
}