internet 0.1.0

Network library for rust
Documentation
//!

use crate::{Buf, BufError, BufMut, BufResult, ietf::igmp::Checksum, ietf::ipv4::Address};

/// IGMPv1 header mapping following [RFC 1112].
///
/// [RFC 1112]: https://datatracker.ietf.org/doc/html/rfc1112
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HeaderMapping<T: Buf> {
    buffer: T,
}

impl<T: Buf> HeaderMapping<T> {
    /// Creates a new header mapping.
    pub fn new(buffer: T) -> Self {
        Self { buffer }
    }

    /// Consumes the mapping and returns the underlying buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }

    /// Returns a reference to the underlying buffer.
    pub fn as_inner(&self) -> &T {
        &self.buffer
    }

    /// Reads the type and version.
    pub fn read_type_and_version(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
    }

    /// Reads the unused field.
    pub fn read_unused(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) & 0xff) as u8 }
    }

    /// Reads the checksum.
    pub fn read_checksum(&self) -> Checksum {
        unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
    }

    /// Reads the group address.
    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> {
    /// Writes the type and version.
    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(())
    }

    /// Writes the unused field.
    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(())
    }

    /// Writes the checksum.
    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(())
    }

    /// Writes the group address.
    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(())
    }
}