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() {
if let Entry::Occupied(e) = self.ids.entry(old) {
if index == *e.get() {
e.remove();
}
}
}
}
*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 {
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() {
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())
}
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])
}
}
pub fn get_by_id(&self, id: u32) -> Option<&BackendState> {
if let Some(index) = self.ids.get(&id) {
self.nth(*index)
} else {
None
}
}
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));
}