use tokio::sync::{RwLock, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::BalancingStrategy;
use std::ops::{DerefMut, Deref};
use rand::Rng;
pub struct Random<K>{
rng:Mutex<rand::rngs::OsRng>,
scope:AtomicUsize,
list:RwLock<Vec<(K,usize)>>
}
impl<K:Clone + Eq + Send + Sync > Random<K>{
pub fn new()->Self{
let rng =Mutex::new(rand::rngs::OsRng::default());
let scope = AtomicUsize::new(0);
let list= RwLock::new(vec![]);
Self{rng,scope,list}
}
pub async fn rand(&self)->usize{
let mut r = self.rng.lock().await;
let r = r.deref_mut();
r.gen_range(0..self.scope.load(Ordering::Relaxed))
}
}
#[async_trait::async_trait]
impl<K:Clone + Eq + Send + Sync > BalancingStrategy<K> for Random<K>{
async fn add(&self, k: K, n: usize) {
if n <= 0{
return;
}
let mut list = self.list.write().await;
let list = list.deref_mut();
list.push((k,n));
self.scope.fetch_add(n,Ordering::Relaxed);
}
async fn remove(&self, k: K) {
let mut list = self.list.write().await;
let list = list.deref_mut();
if list.len() < 1 {
return
}
for index in 0..list.len(){
if k == list[index].0 {
self.scope.fetch_sub(list[index].1,Ordering::Relaxed);
list.remove(index);
break;
}
}
}
async fn select(&self) -> Option<K> {
let list = self.list.read().await;
let list = list.deref();
if list.len() < 1 {
return None
}
let mut number = self.rand().await;
for index in 0..list.len() {
if number < list[index].1 {
return Some(list[index].0.clone())
}else{
number -= list[index].1;
}
}
None
}
}