use std::ops::Deref;
use std::sync::Arc;
use tokio::sync::Notify;
use tokio::task::{JoinError, spawn_blocking};
use crate::error::{OpenError, PushError, TryPushError};
use crate::queue::{Builder, Consumer, Producer, Reserved};
use crate::store::Store;
struct Signals {
room: Notify,
items: Notify,
}
pub type AsyncEnds<S> = (AsyncProducer<S>, AsyncConsumer<S>);
impl<S: Store + 'static> Builder<S> {
pub async fn open_async(self) -> Result<AsyncEnds<S>, OpenError<S::Error>> {
let (producer, consumer) = join(spawn_blocking(move || self.open()).await)?;
let signals = Arc::new(Signals {
room: Notify::new(),
items: Notify::new(),
});
Ok((
AsyncProducer {
inner: producer,
signals: Arc::clone(&signals),
},
AsyncConsumer {
inner: Arc::new(consumer),
signals,
},
))
}
}
pub struct AsyncProducer<S> {
inner: Producer<S>,
signals: Arc<Signals>,
}
impl<S> Clone for AsyncProducer<S> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
signals: Arc::clone(&self.signals),
}
}
}
impl<S: Store + 'static> AsyncProducer<S> {
pub async fn push(&self, value: Vec<u8>) -> Result<(), PushError<S::Error>> {
let value: Arc<[u8]> = Arc::from(value);
let mut waker = std::pin::pin!(self.signals.room.notified());
loop {
waker.as_mut().enable();
let inner = self.inner.clone();
let value = Arc::clone(&value);
match join(spawn_blocking(move || inner.try_push(&value)).await) {
Ok(()) => {
self.signals.items.notify_one();
return Ok(());
}
Err(TryPushError::Full) => {}
Err(TryPushError::Closed) => return Err(PushError::Closed),
Err(TryPushError::Store(e)) => return Err(PushError::Store(e)),
}
waker.as_mut().await;
waker.set(self.signals.room.notified());
}
}
pub async fn try_push(&self, value: Vec<u8>) -> Result<(), TryPushError<S::Error>> {
let inner = self.inner.clone();
let result = join(spawn_blocking(move || inner.try_push(&value)).await);
if result.is_ok() {
self.signals.items.notify_one();
}
result
}
pub fn close(&self) {
self.inner.close();
self.signals.room.notify_waiters();
self.signals.items.notify_waiters();
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
pub struct AsyncConsumer<S> {
inner: Arc<Consumer<S>>,
signals: Arc<Signals>,
}
impl<S: Store + 'static> AsyncConsumer<S> {
pub async fn reserve(&self) -> Result<Option<AsyncReserved<S>>, S::Error> {
let mut waker = std::pin::pin!(self.signals.items.notified());
loop {
waker.as_mut().enable();
let consumer = Arc::clone(&self.inner);
match join(spawn_blocking(move || consumer.reserve()).await)? {
Some(inner) => {
return Ok(Some(AsyncReserved {
inner: Some(inner),
signals: Arc::clone(&self.signals),
}));
}
None if self.inner.is_drained() => return Ok(None),
None => {}
}
waker.as_mut().await;
waker.set(self.signals.items.notified());
}
}
}
pub struct AsyncReserved<S: Store> {
inner: Option<Reserved<S>>,
signals: Arc<Signals>,
}
impl<S: Store + 'static> AsyncReserved<S> {
pub fn seq(&self) -> u64 {
self.inner
.as_ref()
.expect("reserved already consumed")
.seq()
}
pub async fn ack(mut self) -> Result<(), S::Error> {
let reserved = self.inner.take().expect("reserved already consumed");
let result = join(spawn_blocking(move || reserved.ack()).await);
if result.is_ok() {
self.signals.room.notify_one();
self.signals.items.notify_one();
}
result
}
pub fn nack(mut self) {
if let Some(reserved) = self.inner.take() {
reserved.nack();
self.signals.items.notify_one();
}
}
}
impl<S: Store> Deref for AsyncReserved<S> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.inner.as_ref().expect("reserved already consumed")
}
}
impl<S: Store> Drop for AsyncReserved<S> {
fn drop(&mut self) {
if let Some(reserved) = self.inner.take() {
reserved.nack();
self.signals.items.notify_one();
}
}
}
fn join<T>(joined: Result<T, JoinError>) -> T {
joined.unwrap_or_else(|e| std::panic::resume_unwind(e.into_panic()))
}