net-pool 0.5.1

A set of types for network connection pool.
Documentation
use crate::{Address, BackendState};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, Clone, Default)]
pub(super) struct BackendStates {
    bbs: Vec<BackendState>,
    codes: HashMap<u64, usize>,
    ids: HashMap<u32, usize>,
}

impl BackendStates {
    pub fn new() -> Self {
        Self {
            bbs: vec![],
            codes: HashMap::new(),
            ids: HashMap::new(),
        }
    }

    /// 添加一个地址
    pub fn add(&mut self, id: Option<u32>, addr: Address) {
        let bs = BackendState::new(id, addr);
        let code = bs.hash_code();
        let index = match self.codes.entry(code) {
            Entry::Occupied(e) => {
                let index = *e.get();
                let old = &mut self.bbs[index];
                if old.id() != id {
                    if let Some(old) = old.id() {
                        // 删除掉旧id
                        if let Entry::Occupied(e) = self.ids.entry(old) {
                            if index == *e.get() {
                                e.remove();
                            }
                        }
                    }
                }
                // 替换掉新的bs
                *old = bs;
                index
            }
            Entry::Vacant(e) => {
                self.bbs.push(bs);
                let index = self.bbs.len() - 1;
                e.insert(index);
                index
            }
        };

        if let Some(id) = id {
            // 插入新id
            self.ids.insert(id, index);
        }
    }

    /// 移除一个地址
    pub fn remove(&mut self, addr: &Address) -> bool {
        let code = addr.hash_code();
        if let Some(index) = self.codes.remove(&code) {
            if let Some(id) = self.bbs.swap_remove(index).id() {
                // 移掉id
                if let Entry::Occupied(e) = self.ids.entry(id) {
                    if index == *e.get() {
                        e.remove();
                    }
                }
            }
            if self.bbs.len() > index {
                // 原尾部的更新索引
                let bs = &self.bbs[index];
                self.codes.insert(bs.hash_code(), index);
                if let Some(id) = bs.id() {
                    self.ids.insert(id, index);
                }
            }
            true
        } else {
            false
        }
    }

    /// 是否包含
    pub fn contain(&self, addr: &Address) -> bool {
        self.codes.contains_key(&addr.hash_code())
    }

    /// nth 获取第n个
    pub fn nth(&self, mut n: usize) -> Option<&BackendState> {
        if self.bbs.is_empty() {
            None
        } else {
            n = n % self.bbs.len();
            Some(&self.bbs[n])
        }
    }

    /// 通过id获取
    pub fn get_by_id(&self, id: u32) -> Option<&BackendState> {
        if let Some(index) = self.ids.get(&id) {
            self.nth(*index)
        } else {
            None
        }
    }

    /// 通过code获取
    pub fn get_by_code(&self, code: u64) -> Option<&BackendState> {
        if let Some(index) = self.codes.get(&code) {
            self.nth(*index)
        } else {
            None
        }
    }

    /// 获取所有的
    pub fn get_all(&self) -> &[BackendState] {
        self.bbs.as_slice()
    }
}

#[test]
fn test() {
    let mut bss = BackendStates::new();
    bss.add(None, Address::from("localhost:10001"));
    println!("{:?}", bss);
    bss.add(Some(1), Address::from("localhost:10001"));
    println!("{:?}", bss);
    bss.add(Some(2), Address::from("localhost:10001"));
    println!("{:?}", bss);
    bss.add(Some(2), Address::from("localhost:10002"));
    println!("{:?}", bss);
    bss.remove(&Address::from("localhost:10003"));
    println!("{:?}", bss);
    bss.remove(&Address::from("localhost:10001"));
    println!("{:?}", bss);
    bss.remove(&Address::from("localhost:10002"));
    println!("{:?}", bss);
    bss.add(Some(1), Address::from("localhost:10001"));
    println!("{:?}", bss);
    bss.add(Some(2), Address::from("localhost:10002"));
    println!("{:?}", bss);
    bss.remove(&Address::from("localhost:10002"));
    println!("{:?}", bss);
    assert!(bss.contain(&Address::from("localhost:10001")));
    println!("{:?}", bss.get_by_id(2));
    println!("{:?}", bss.get_by_id(1));
    println!("{:?}", bss.get_by_code(7139969718446815058));
}