use crate::{
ResourceId,
core::{Accounting, lock},
};
use std::{
collections::VecDeque,
ops::{Deref, DerefMut},
sync::{Arc, Mutex},
};
pub(crate) struct RetirementQueue<R> {
items: Mutex<VecDeque<(ResourceId, R)>>,
accounting: Arc<Accounting>,
}
impl<R> RetirementQueue<R> {
pub fn new(accounting: Arc<Accounting>) -> Self {
Self {
items: Mutex::new(VecDeque::new()),
accounting,
}
}
pub fn push(&self, id: ResourceId, resource: R) {
lock(&self.items).push_back((id, resource));
self.accounting.notify();
}
pub fn pop(self: &Arc<Self>) -> Option<Retirement<R>> {
let item = lock(&self.items).pop_front();
item.map(|item| Retirement {
item: Some(item),
queue: self.clone(),
})
}
}
pub struct Retirement<R> {
item: Option<(ResourceId, R)>,
queue: Arc<RetirementQueue<R>>,
}
impl<R> Retirement<R> {
pub fn id(&self) -> ResourceId {
self.item.as_ref().unwrap().0
}
pub fn complete(mut self) {
drop(self.item.take().unwrap());
lock(&self.queue.accounting.counts).retiring -= 1;
self.queue.accounting.notify();
}
}
impl<R> Deref for Retirement<R> {
type Target = R;
fn deref(&self) -> &R {
&self.item.as_ref().unwrap().1
}
}
impl<R> DerefMut for Retirement<R> {
fn deref_mut(&mut self) -> &mut R {
&mut self.item.as_mut().unwrap().1
}
}
impl<R> Drop for Retirement<R> {
fn drop(&mut self) {
if let Some((id, resource)) = self.item.take() {
self.queue.push(id, resource);
}
}
}