use std::cell::{Cell, RefCell};
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use super::wait_queue::WaitQueue;
#[derive(Clone)]
pub struct PriorityResource {
state: Rc<RefCell<WaitQueue<u32>>>,
}
impl std::fmt::Debug for PriorityResource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_struct("PriorityResource");
if let Ok(q) = self.state.try_borrow() {
d.field("in_use", &q.in_use())
.field("capacity", &q.capacity())
.field("queue_len", &q.live_waiters());
}
d.finish_non_exhaustive()
}
}
impl PriorityResource {
#[must_use]
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "PriorityResource capacity must be at least 1");
PriorityResource {
state: Rc::new(RefCell::new(WaitQueue::new(capacity))),
}
}
#[must_use = "futures do nothing unless awaited"]
pub fn request(&self, priority: u32) -> PriorityResourceRequest {
PriorityResourceRequest {
state: Rc::clone(&self.state),
priority,
registered: false,
consumed: false,
canceled: Rc::new(Cell::new(false)),
granted: Rc::new(Cell::new(false)),
}
}
#[must_use]
pub fn in_use(&self) -> usize {
self.state.borrow().in_use()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.state.borrow().capacity()
}
#[must_use]
pub fn queue_len(&self) -> usize {
self.state.borrow().live_waiters()
}
}
pub struct PriorityResourceRequest {
state: Rc<RefCell<WaitQueue<u32>>>,
priority: u32,
registered: bool,
consumed: bool,
canceled: Rc<Cell<bool>>,
granted: Rc<Cell<bool>>,
}
impl std::fmt::Debug for PriorityResourceRequest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PriorityResourceRequest")
.field("priority", &self.priority)
.field("registered", &self.registered)
.field("granted", &self.granted.get())
.finish_non_exhaustive()
}
}
impl Future for PriorityResourceRequest {
type Output = PriorityResourceGuard;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<PriorityResourceGuard> {
if self.granted.get() {
self.consumed = true;
return Poll::Ready(PriorityResourceGuard {
state: Rc::clone(&self.state),
});
}
let acquired = {
let mut state = self.state.borrow_mut();
if state.try_acquire() {
true
} else {
if !self.registered {
state.register(
self.priority,
cx.waker().clone(),
Rc::clone(&self.canceled),
Rc::clone(&self.granted),
);
}
false
}
};
if acquired {
self.consumed = true;
return Poll::Ready(PriorityResourceGuard {
state: Rc::clone(&self.state),
});
}
self.registered = true;
Poll::Pending
}
}
impl Drop for PriorityResourceRequest {
fn drop(&mut self) {
if self.consumed {
return; }
if self.granted.get() {
self.state.borrow_mut().release();
} else if self.registered {
self.canceled.set(true);
}
}
}
pub struct PriorityResourceGuard {
state: Rc<RefCell<WaitQueue<u32>>>,
}
impl std::fmt::Debug for PriorityResourceGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PriorityResourceGuard")
.finish_non_exhaustive()
}
}
impl Drop for PriorityResourceGuard {
fn drop(&mut self) {
self.state.borrow_mut().release();
}
}