use core::fmt;
pub const FRAGMENT_HEADER_LENGTH: usize = 8;
pub struct FragmentHeaderWriter<'a> {
pub bytes: &'a mut [u8],
}
impl<'a> FragmentHeaderWriter<'a> {
#[inline]
pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
if bytes.len() < FRAGMENT_HEADER_LENGTH {
panic!("Slice is too short to contain a Fragment header.");
}
Ok(Self { bytes })
}
#[inline]
pub fn header_len(&self) -> usize {
FRAGMENT_HEADER_LENGTH
}
#[inline]
pub fn set_next_header(&mut self, next_header: u8) {
self.bytes[0] = next_header;
}
#[inline]
pub fn set_reserved(&mut self, reserved: u8) {
self.bytes[1] = reserved;
}
#[inline]
pub fn set_fragment_offset(&mut self, fragment_offset: u16) {
let value = fragment_offset & 0x1FFF;
self.bytes[2] = (value >> 5) as u8;
self.bytes[3] = (self.bytes[3] & 0xE0) | ((value & 0x1F) as u8);
}
#[inline]
pub fn set_res(&mut self, res: u8) {
let value = res & 0b11;
self.bytes[3] = (self.bytes[3] & 0x9F) | (value << 5);
}
#[inline]
pub fn set_m_flag(&mut self, m_flag: bool) {
if m_flag {
self.bytes[3] |= 0x80;
} else {
self.bytes[3] &= 0x7F;
}
}
#[inline]
pub fn set_identification(&mut self, identification: u32) {
self.bytes[4] = (identification >> 24) as u8;
self.bytes[5] = (identification >> 16) as u8;
self.bytes[6] = (identification >> 8) as u8;
self.bytes[7] = identification as u8;
}
}
pub struct FragmentHeaderReader<'a> {
pub bytes: &'a [u8],
}
impl<'a> FragmentHeaderReader<'a> {
#[inline]
pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
if bytes.len() < FRAGMENT_HEADER_LENGTH {
return Err("Slice is too short to contain a Fragment header.");
}
Ok(Self { bytes })
}
#[inline]
pub fn next_header(&self) -> u8 {
self.bytes[0]
}
#[inline]
pub fn reserved(&self) -> u8 {
self.bytes[1]
}
#[inline]
pub fn fragment_offset(&self) -> u16 {
((self.bytes[2] as u16) << 5) | ((self.bytes[3] & 0x1F) as u16)
}
#[inline]
pub fn res(&self) -> u8 {
(self.bytes[3] >> 5) & 0b11
}
#[inline]
pub fn m_flag(&self) -> bool {
(self.bytes[3] & 0x80) != 0
}
#[inline]
pub fn identification(&self) -> u32 {
((self.bytes[4] as u32) << 24)
| ((self.bytes[5] as u32) << 16)
| ((self.bytes[6] as u32) << 8)
| (self.bytes[7] as u32)
}
#[inline]
pub fn header_len(&self) -> usize {
FRAGMENT_HEADER_LENGTH
}
#[inline]
pub fn header(&self) -> &'a [u8] {
&self.bytes[..FRAGMENT_HEADER_LENGTH]
}
#[inline]
pub fn payload(&self) -> &'a [u8] {
&self.bytes[FRAGMENT_HEADER_LENGTH..]
}
}
impl fmt::Debug for FragmentHeaderReader<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FragmentHeader")
.field("next_header", &self.next_header())
.field("reserved", &self.reserved())
.field("fragment_offset", &self.fragment_offset())
.field("res", &self.res())
.field("m_flag", &self.m_flag())
.field("identification", &self.identification())
.finish()
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn getters_and_setters() {
let mut bytes = [0u8; 16];
let next_header = 6;
let reserved = 0;
let fragment_offset = 255;
let res = 0;
let m_flag = true;
let identification = 0x04050607;
let mut writer = FragmentHeaderWriter::new(&mut bytes).unwrap();
writer.set_next_header(next_header);
writer.set_reserved(reserved);
writer.set_fragment_offset(fragment_offset);
writer.set_res(res);
writer.set_m_flag(m_flag);
writer.set_identification(identification);
let reader = FragmentHeaderReader::new(&bytes).unwrap();
assert_eq!(reader.next_header(), next_header);
assert_eq!(reader.reserved(), reserved);
assert_eq!(reader.fragment_offset(), fragment_offset);
assert_eq!(reader.res(), res);
assert_eq!(reader.m_flag(), m_flag);
assert_eq!(reader.identification(), identification);
}
}