net-pool 0.1.3

A set of types for network connection pool.
Documentation
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::net::{AddrParseError, IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::str::FromStr;

#[derive(Clone, Debug)]
pub enum Address {
    Ori(String),
    Addr(SocketAddr),
}

impl Address {
    pub fn hash_code(&self) -> u64 {
        match self {
            Address::Ori(ori) => crate::utils::bytes_to_hash_code(ori.as_bytes()),
            Address::Addr(addr) => crate::utils::socketaddr_to_hash_code(addr),
        }
    }
}

impl From<String> for Address {
    fn from(ori: String) -> Self {
        Address::Ori(ori)
    }
}

impl From<&str> for Address {
    fn from(ori: &str) -> Self {
        Address::Ori(ori.to_string())
    }
}

impl From<SocketAddr> for Address {
    fn from(addr: SocketAddr) -> Self {
        Address::Addr(addr)
    }
}

impl<I: Into<IpAddr>> From<(I, u16)> for Address {
    fn from(value: (I, u16)) -> Self {
        Address::from(SocketAddr::from(value))
    }
}

impl From<SocketAddrV4> for Address {
    fn from(value: SocketAddrV4) -> Self {
        Address::from(SocketAddr::from(value))
    }
}

impl From<SocketAddrV6> for Address {
    fn from(value: SocketAddrV6) -> Self {
        Address::from(SocketAddr::from(value))
    }
}

impl FromStr for Address {
    type Err = AddrParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let a = SocketAddr::from_str(s)?;
        Ok(Address::from(a))
    }
}

#[derive(Clone, Debug)]
pub struct BackendState {
    hash_code: u64,
    valid: bool,
    address: Address,
}

impl BackendState {
    pub fn new(addr: Address) -> BackendState {
        let hash_code = addr.hash_code();
        BackendState {
            hash_code,
            valid: true,
            address: addr,
        }
    }

    pub fn hash_code(&self) -> u64 {
        self.hash_code
    }

    pub fn set_valid(&mut self, valid: bool) {
        self.valid = valid;
    }

    pub fn get_valid(&self) -> bool {
        self.valid
    }

    pub fn get_address(&self) -> &Address {
        &self.address
    }
}

impl Hash for BackendState {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u64(self.hash_code)
    }
}

impl Eq for BackendState {}

impl PartialEq for BackendState {
    fn eq(&self, other: &Self) -> bool {
        self.hash_code.eq(&other.hash_code)
    }
}

impl PartialOrd for BackendState {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.hash_code.partial_cmp(&other.hash_code)
    }
}

impl Ord for BackendState {
    fn cmp(&self, other: &Self) -> Ordering {
        self.hash_code.cmp(&other.hash_code)
    }
}

impl From<Address> for BackendState {
    fn from(addr: Address) -> Self {
        BackendState::new(addr)
    }
}

#[derive(Default)]
pub struct BackendStates(Vec<BackendState>);

impl BackendStates {
    pub fn new() -> Self {
        BackendStates(Vec::new())
    }

    pub fn contain(&self, hash_code: u64) -> bool {
        self.0
            .iter()
            .find(|bs| bs.hash_code() == hash_code)
            .is_some()
    }

    pub fn add_backend(&mut self, addr: Address) {
        let hash_code = addr.hash_code();
        if self.0.iter().any(|bs| bs.hash_code == hash_code) {
            return;
        }

        self.0.push(BackendState::new(addr));
        self.sort_backends();
    }

    pub fn remove_backend(&mut self, addr: &Address) -> bool {
        let c = self.0.len();
        let hash_code = addr.hash_code();
        self.0.retain(|bs| bs.hash_code != hash_code);
        self.0.len() != c
    }

    pub fn set_backend_valid(&mut self, addr: &Address, valid: bool) {
        if let Some(bs) = self.get_backend_mut(addr) {
            bs.valid = valid;
        }
    }

    pub fn get_backend_valid(&self, addr: &Address) -> Option<bool> {
        self.get_backend(addr).map(|bs| bs.valid)
    }

    pub fn get_backend(&self, addr: &Address) -> Option<&BackendState> {
        let hash_code = addr.hash_code();
        self.0.iter().find(|bs| bs.hash_code == hash_code)
    }

    pub fn get_backend_mut(&mut self, addr: &Address) -> Option<&mut BackendState> {
        let hash_code = addr.hash_code();
        self.0.iter_mut().find(|bs| bs.hash_code == hash_code)
    }

    pub fn get_backends(&self) -> &[BackendState] {
        self.0.as_slice()
    }

    pub fn get_backends_mut(&mut self) -> &mut [BackendState] {
        self.0.as_mut_slice()
    }

    fn sort_backends(&mut self) {
        self.0.sort_by(|bs1, bs2| bs1.hash_code.cmp(&bs2.hash_code));
    }
}