use crate::{Buf, BufError, BufMut, BufResult, ietf::igmp::Checksum, ietf::ipv4::Address};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct QueryMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> QueryMapping<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(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
}
pub fn read_max_response_code(&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,
])
}
pub fn read_s_flag(&self) -> bool {
unsafe { ((self.buffer.get_u16_be_unchecked(8) >> 8) & 0x08) != 0 }
}
pub fn read_qrv(&self) -> u8 {
unsafe { ((self.buffer.get_u16_be_unchecked(8) >> 8) & 0x07) as u8 }
}
pub fn read_qqic(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(8) & 0xff) as u8 }
}
pub fn read_number_of_sources(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(10) }
}
}
impl<T: BufMut> QueryMapping<T> {
pub fn write_type(&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_max_response_code(&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(())
}
pub fn write_s_flag(&mut self, val: bool) -> BufResult<()> {
if self.buffer.length() < 10 {
return Err(BufError::BufferTooSmall);
}
let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
let byte = (word >> 8) as u8;
let new_byte = if val { byte | 0x08 } else { byte & !0x08 };
word = ((new_byte as u16) << 8) | (word & 0x00ff);
unsafe { self.buffer.set_u16_be_unchecked(8, word) }
Ok(())
}
pub fn write_qrv(&mut self, val: u8) -> BufResult<()> {
if self.buffer.length() < 10 {
return Err(BufError::BufferTooSmall);
}
let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
let byte = (word >> 8) as u8;
let new_byte = (byte & !0x07) | (val & 0x07);
word = ((new_byte as u16) << 8) | (word & 0x00ff);
unsafe { self.buffer.set_u16_be_unchecked(8, word) }
Ok(())
}
pub fn write_qqic(&mut self, val: u8) -> BufResult<()> {
if self.buffer.length() < 10 {
return Err(BufError::BufferTooSmall);
}
let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
word = (word & 0xff00) | (val as u16);
unsafe { self.buffer.set_u16_be_unchecked(8, word) }
Ok(())
}
pub fn write_number_of_sources(&mut self, val: u16) -> BufResult<()> {
if self.buffer.length() < 12 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(10, val) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReportMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> ReportMapping<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(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_number_of_group_records(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
}
impl<T: BufMut> ReportMapping<T> {
pub fn write_type(&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_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_number_of_group_records(&mut self, val: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, val) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GroupRecordMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> GroupRecordMapping<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_record_type(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
}
pub fn read_aux_data_len(&self) -> u8 {
unsafe { (self.buffer.get_u16_be_unchecked(0) & 0xff) as u8 }
}
pub fn read_number_of_sources(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(2) }
}
pub fn read_multicast_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> GroupRecordMapping<T> {
pub fn write_record_type(&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_aux_data_len(&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_number_of_sources(&mut self, val: u16) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, val) }
Ok(())
}
pub fn write_multicast_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(())
}
}