use crate::{Buf, BufError, BufMut, BufResult, ietf::igmp::Checksum, ietf::ipv4::Address};
#[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
}
pub fn read_type_and_version(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
}
pub fn read_unused(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) & 0xff) as u8 }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_group_address(&self) -> Address {
let hi = unsafe { self.buffer.get_u16_be_unchecked(4) };
let lo = unsafe { self.buffer.get_u16_be_unchecked(6) };
Address::from([
(hi >> 8) as u8,
(hi & 0xff) as u8,
(lo >> 8) as u8,
(lo & 0xff) as u8,
])
}
}
impl<T: BufMut> HeaderMapping<T> {
pub fn write_type_and_version(&mut self, val: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
word = (word & 0x00ff) | ((val as u16) << 8);
unsafe { self.buffer.set_u16_be_unchecked(0, word) }
Ok(())
}
pub fn write_unused(&mut self, val: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
word = (word & 0xff00) | (val as u16);
unsafe { self.buffer.set_u16_be_unchecked(0, word) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_group_address(&mut self, address: Address) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
let bytes: [u8; 4] = address.into();
let hi = ((bytes[0] as u16) << 8) | (bytes[1] as u16);
let lo = ((bytes[2] as u16) << 8) | (bytes[3] as u16);
unsafe {
self.buffer.set_u16_be_unchecked(4, hi);
self.buffer.set_u16_be_unchecked(6, lo);
}
Ok(())
}
}