ping 0.7.1

Simple and naive ping implementation in Rust.
Documentation
use thiserror::Error;

#[derive(Debug, Error)]
pub enum Error {
    #[error("too small header")]
    TooSmallHeader,
    #[error("invalid header size")]
    InvalidHeaderSize,
    #[error("invalid version")]
    InvalidVersion,
    #[error("unknown protocol")]
    UnknownProtocol,
}

const MINIMUM_PACKET_SIZE: usize = 20;

#[derive(Debug, PartialEq)]
pub enum IpV4Protocol {
    Icmp,
}

impl IpV4Protocol {
    fn decode(data: u8) -> Option<Self> {
        match data {
            1 => Some(IpV4Protocol::Icmp),
            _ => None,
        }
    }
}

pub struct IpV4Packet<'a> {
    #[allow(unused)]
    pub protocol: IpV4Protocol,
    pub ttl: u8,
    pub data: &'a [u8],
}

impl<'a> IpV4Packet<'a> {
    pub fn decode(data: &'a [u8]) -> Result<Self, Error> {
        if data.len() < MINIMUM_PACKET_SIZE {
            return Err(Error::TooSmallHeader);
        }
        let byte0 = data[0];
        let version = (byte0 & 0xf0) >> 4;
        let header_size = 4 * ((byte0 & 0x0f) as usize);

        if version != 4 {
            return Err(Error::InvalidVersion);
        }

        if data.len() < header_size {
            return Err(Error::InvalidHeaderSize);
        }

        let protocol = match IpV4Protocol::decode(data[9]) {
            Some(protocol) => protocol,
            None => return Err(Error::UnknownProtocol),
        };

        let ttl = data[8];

        Ok(Self {
            protocol: protocol,
            ttl,
            data: &data[header_size..],
        })
    }
}