use nimiq_collections::{UniqueLinkedList, Queue};
use std::time::Duration;
use std::time::Instant;
use std::cmp;
use std::hash::Hash;
use std::rc::Rc;
use std::borrow::Borrow;
pub struct ThrottledQueue<T>
where T: Hash + Eq {
queue: UniqueLinkedList<T>,
max_size: Option<usize>,
max_allowance: usize,
allowance_per_interval: usize,
allowance_interval: Duration,
last_allowance: Instant,
available_now: usize,
}
impl<T> ThrottledQueue<T>
where T: Hash + Eq {
#[inline]
pub fn new(max_allowance: usize, allowance_interval: Duration, allowance_per_interval: usize, max_size: Option<usize>) -> Self {
ThrottledQueue {
queue: UniqueLinkedList::new(),
max_size,
max_allowance,
allowance_per_interval: cmp::min(max_allowance, allowance_per_interval),
allowance_interval,
last_allowance: Instant::now(),
available_now: max_allowance,
}
}
pub fn num_available(&mut self) -> usize {
if self.allowance_interval > Duration::default() {
let now = Instant::now();
let mut duration = now.duration_since(self.last_allowance);
let mut num_intervals: usize = 0;
while let Some(left) = duration.checked_sub(self.allowance_interval) {
num_intervals += 1;
duration = left;
}
if num_intervals > 0 {
self.available_now = cmp::min(self.max_allowance, self.available_now + (num_intervals as usize) * self.allowance_per_interval);
}
self.last_allowance = now;
}
cmp::min(self.available_now, self.len())
}
pub fn check_available(&mut self) -> bool {
self.num_available() > 0
}
pub fn push_back(&mut self, elt: T) {
if let Some(max_size) = self.max_size {
if self.queue.len() >= max_size {
self.queue.pop_front();
}
}
self.queue.push_back(elt);
}
pub fn pop_front(&mut self) -> Option<T> {
if self.num_available() > 0 {
self.available_now -= 1;
return self.queue.pop_front();
}
None
}
pub fn remove<Q: ?Sized>(&mut self, x: &Q) -> Option<T>
where Rc<T>: Borrow<Q>, Q: Hash + Eq
{
self.queue.remove(x)
}
#[inline]
pub fn len(&self) -> usize {
self.queue.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
}
impl<T> Queue<T> for ThrottledQueue<T>
where T: Hash + Eq {
fn is_empty(&self) -> bool {
self.queue.is_empty()
}
fn len(&self) -> usize {
self.queue.len()
}
fn clear(&mut self) {
self.queue.clear()
}
fn peek(&self) -> Option<&T> {
if self.available_now > 0 {
return self.queue.peek();
}
None
}
fn dequeue(&mut self) -> Option<T> {
self.pop_front()
}
fn dequeue_multi(&mut self, n: usize) -> Vec<T> {
let mut v = Vec::new();
for _ in 0..n {
match self.dequeue() {
Some(elt) => v.push(elt),
None => return v,
}
}
v
}
fn enqueue(&mut self, elt: T) {
self.push_back(elt)
}
fn append(&mut self, other: &mut Self) {
while let Some(elt) = other.queue.pop_front() {
self.push_back(elt);
}
}
fn requeue(&mut self, elt: T) {
self.queue.requeue(elt)
}
}