internet 0.0.4

Network library for rust
Documentation
//! Encoding for IPv4 options following [RFC 791].
//!
//! [IETF RFC 791]: https://datatracker.ietf.org/doc/html/rfc791

use crate::{Buf, BufMut, BufResult, Codec, Cursor};

use core::str::FromStr;

/// An IPv4 Address.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Address(pub [u8; 4]);

impl Address {
    ///
    pub const UNSPECIFIED: Self = Self([0, 0, 0, 0]);
    ///
    pub const BROADCAST: Self = Self([255, 255, 255, 255]);
    ///
    pub const LOOPBACK: Self = Self([127, 0, 0, 1]);

    ///
    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Self([a, b, c, d])
    }

    ///
    pub const fn from_octets(octets: [u8; 4]) -> Self {
        Self(octets)
    }

    ///
    pub const fn octets(self) -> [u8; 4] {
        self.0
    }

    ///
    pub const fn from_bytes(octets: [u8; 4]) -> Self {
        Self(octets)
    }

    ///
    pub const fn bytes(self) -> [u8; 4] {
        self.0
    }

    ///
    pub const fn from_bits(bits: u32) -> Self {
        Self(bits.to_ne_bytes())
    }

    ///
    pub const fn to_bits(self) -> u32 {
        u32::from_be_bytes(self.0)
    }

    ///
    pub const fn is_private(self) -> bool {
        matches!(self.0[0], 10)
            || (self.0[0] == 172 && (self.0[1] & 0xF0) == 16)
            || (self.0[0] == 192 && self.0[1] == 168)
    }

    ///
    pub const fn is_link_local(self) -> bool {
        self.0[0] == 169 && self.0[1] == 254
    }

    ///
    pub const fn is_multicast(self) -> bool {
        (self.0[0] & 0xF0) == 224
    }

    ///
    pub const fn is_documentation(self) -> bool {
        // 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24
        matches!(
            (self.0[0], self.0[1], self.0[2]),
            (192, 0, 2) | (198, 51, 100) | (203, 0, 113)
        )
    }
}

impl From<[u8; 4]> for Address {
    fn from(octets: [u8; 4]) -> Self {
        Self(octets)
    }
}

impl From<Address> for [u8; 4] {
    fn from(addr: Address) -> Self {
        addr.0
    }
}

impl From<u32> for Address {
    fn from(value: u32) -> Self {
        Self(value.to_be_bytes())
    }
}

impl From<Address> for u32 {
    fn from(addr: Address) -> Self {
        addr.to_bits()
    }
}

impl Codec for Address {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        self.0.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        Ok(Self(reader.read_array::<4>()?))
    }
}

impl std::fmt::Display for Address {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])
    }
}

///
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Prefix(u8);

impl Prefix {
    const MAX: Self = Self(32);

    ///
    pub fn new(prefix: u8) -> Option<Self> {
        match prefix {
            x if Self(prefix) != Self::MAX => Some(Prefix(x)),
            _ => None,
        }
    }

    ///
    pub fn set(&mut self, prefix: u8) -> Result<(), ()> {
        match Self::is_valid(prefix) {
            true => Ok(self.0 = prefix),
            false => Err(()),
        }
    }

    ///
    pub fn is_valid(prefix: u8) -> bool {
        Self(prefix) <= Self::MAX
    }
}

impl From<Prefix> for String {
    fn from(_value: Prefix) -> Self {
        todo!()
    }
}

impl FromStr for Prefix {
    type Err = std::io::Error;

    fn from_str(_s: &str) -> Result<Self, Self::Err> {
        todo!()
    }
}

///
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ipv4Network {
    /// Address of the network.
    pub address: Address,
    /// CIDR prefix of the network.
    pub prefix: Prefix,
}

impl From<Ipv4Network> for String {
    fn from(_value: Ipv4Network) -> Self {
        todo!()
    }
}

impl FromStr for Ipv4Network {
    type Err = std::io::Error;

    fn from_str(_s: &str) -> Result<Self, Self::Err> {
        todo!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test() {}
}