use std::{
collections::VecDeque,
mem::take,
sync::atomic::{AtomicBool, Ordering},
};
use event_listener::Event;
use parking_lot::Mutex;
pub struct EventWorkQueue<T> {
queue: Mutex<VecDeque<T>>,
event: Event,
closed: AtomicBool,
}
impl<T> Default for EventWorkQueue<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> EventWorkQueue<T> {
pub fn new() -> Self {
Self {
queue: Mutex::new(VecDeque::new()),
event: Event::new(),
closed: AtomicBool::new(false),
}
}
pub fn push(&self, item: T) -> bool {
if self.closed.load(Ordering::Acquire) {
return false;
}
{
let mut q = self.queue.lock();
if self.closed.load(Ordering::Acquire) {
return false;
}
q.push_back(item);
}
self.event.notify(1);
true
}
#[inline]
pub fn try_pop(&self) -> Option<T> {
let mut q = self.queue.lock();
let item = q.pop_front()?;
if q.capacity() > 64 && q.len() <= q.capacity() / 4 {
q.shrink_to_fit();
}
Some(item)
}
pub async fn wait_to_read(&self) -> bool {
loop {
let listener = {
let q = self.queue.lock();
if !q.is_empty() {
return true;
}
if self.closed.load(Ordering::Acquire) {
return false;
}
self.event.listen()
};
listener.await;
}
}
pub fn drain(&self) -> Vec<T> {
let mut q = self.queue.lock();
take(&mut *q).into_iter().collect()
}
pub fn drain_into(&self, buf: &mut Vec<T>) -> usize {
let mut q = self.queue.lock();
let count = q.len();
buf.extend(q.drain(..));
if q.capacity() > 64 {
q.shrink_to_fit();
}
count
}
pub fn clear(&self) {
let mut q = self.queue.lock();
q.clear();
if q.capacity() > 64 {
q.shrink_to_fit();
}
}
pub fn close(&self) {
let q = self.queue.lock();
self.closed.store(true, Ordering::Release);
self.event.notify(usize::MAX);
drop(q);
}
pub fn is_closed(&self) -> bool {
self.closed.load(Ordering::Acquire)
}
pub fn is_empty(&self) -> bool {
self.queue.lock().is_empty()
}
pub fn len(&self) -> usize {
self.queue.lock().len()
}
}