use std::collections::HashMap;
use std::sync::{Mutex, PoisonError};
pub(crate) const PENDING: &str = "";
#[derive(Debug)]
pub(crate) struct Shares {
cap: usize,
held: Mutex<HashMap<String, usize>>,
}
impl Shares {
pub(crate) fn new(max_connections: usize) -> Self {
Self {
cap: (max_connections / 2).max(1),
held: Mutex::new(HashMap::new()),
}
}
pub(crate) fn cap(&self) -> usize {
self.cap
}
pub(crate) fn take(&self, holder: &str) -> Option<Share<'_>> {
let mut held = self.held.lock().unwrap_or_else(PoisonError::into_inner);
let count = held.entry(holder.to_owned()).or_insert(0);
if *count >= self.cap {
return None;
}
*count += 1;
Some(Share {
shares: self,
holder: holder.to_owned(),
})
}
#[cfg(test)]
fn held(&self, holder: &str) -> usize {
let held = self.held.lock().unwrap_or_else(PoisonError::into_inner);
held.get(holder).copied().unwrap_or(0)
}
}
#[derive(Debug)]
pub(crate) struct Share<'a> {
shares: &'a Shares,
holder: String,
}
impl Drop for Share<'_> {
fn drop(&mut self) {
let mut held = self
.shares
.held
.lock()
.unwrap_or_else(PoisonError::into_inner);
if let Some(count) = held.get_mut(&self.holder) {
*count = count.saturating_sub(1);
if *count == 0 {
held.remove(&self.holder);
}
}
}
}
#[cfg(test)]
mod tests;