pub mod sys;
use std::fmt;
use std::fmt::Display;
use std::io::Read;
use std::io::Write;
use std::net;
use std::num::ParseIntError;
use std::os::raw::*;
use std::str::FromStr;
use base::AsRawDescriptor;
use base::Error as SysError;
use base::RawDescriptor;
use remain::sorted;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
pub use sys::TapT;
use thiserror::Error as ThisError;
#[cfg(feature = "slirp")]
pub mod slirp;
#[cfg(all(feature = "slirp", windows))]
pub use slirp::Slirp;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
    #[error("failed to clone tap interface: {0}")]
    CloneTap(SysError),
    #[error("failed to create a socket: {0}")]
    CreateSocket(SysError),
    #[error("failed to create tap interface: {0}")]
    CreateTap(SysError),
    #[error("ioctl failed: {0}")]
    IoctlError(SysError),
    #[error("failed to open /dev/net/tun: {0}")]
    OpenTun(SysError),
    #[cfg(all(feature = "slirp", windows))]
    #[error("slirp related error")]
    Slirp(slirp::SlirpError),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
    pub fn sys_error(&self) -> SysError {
        match self {
            Error::CreateSocket(e) => *e,
            Error::OpenTun(e) => *e,
            Error::CreateTap(e) => *e,
            Error::CloneTap(e) => *e,
            Error::IoctlError(e) => *e,
            #[cfg(all(feature = "slirp", windows))]
            Error::Slirp(e) => e.sys_error(),
        }
    }
}
#[sorted]
#[derive(ThisError, Debug, PartialEq, Eq)]
pub enum MacAddressError {
    #[error("invalid number of octets: {0}")]
    InvalidNumOctets(usize),
    #[error("failed to parse octet: {0}")]
    ParseOctet(ParseIntError),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct MacAddress {
    addr: [u8; 6],
}
impl MacAddress {
    pub fn octets(&self) -> [u8; 6] {
        self.addr
    }
}
impl FromStr for MacAddress {
    type Err = MacAddressError;
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        let octets: Vec<&str> = s.split(':').collect();
        if octets.len() != 6usize {
            return Err(MacAddressError::InvalidNumOctets(octets.len()));
        }
        let mut result = MacAddress::default();
        for (i, octet) in octets.iter().enumerate() {
            result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?;
        }
        Ok(result)
    }
}
impl Display for MacAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5]
        )
    }
}
impl<'de> Deserialize<'de> for MacAddress {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        FromStr::from_str(&s).map_err(serde::de::Error::custom)
    }
}
impl Serialize for MacAddress {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.collect_str(&self)
    }
}
pub trait TapTCommon: Read + Write + AsRawDescriptor + Send + Sized {
    fn new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
    fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
    fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>;
    fn ip_addr(&self) -> Result<net::Ipv4Addr>;
    fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>;
    fn netmask(&self) -> Result<net::Ipv4Addr>;
    fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>;
    fn mtu(&self) -> Result<u16>;
    fn set_mtu(&self, mtu: u16) -> Result<()>;
    fn mac_address(&self) -> Result<MacAddress>;
    fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>;
    fn set_offload(&self, flags: c_uint) -> Result<()>;
    fn enable(&self) -> Result<()>;
    fn try_clone(&self) -> Result<Self>;
    unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>;
}
#[cfg(test)]
mod tests {
    use serde_json::*;
    use super::*;
    #[test]
    fn json_serialize_deserialize() {
        let mac_address = MacAddress {
            addr: [0x3d, 0x70, 0xeb, 0x61, 0x1a, 0x91],
        };
        const SERIALIZED_ADDRESS: &str = "\"3D:70:EB:61:1A:91\"";
        assert_eq!(to_string(&mac_address).unwrap(), SERIALIZED_ADDRESS);
        assert_eq!(
            from_str::<MacAddress>(SERIALIZED_ADDRESS).unwrap(),
            mac_address
        );
    }
}