use std::future::Future;
use std::sync::Arc;
use std::time::Duration;
use tokio::spawn;
use tokio::sync::{mpsc, Mutex};
use tokio::sync::mpsc::Sender;
use tokio::task::JoinHandle;
use tokio::time::timeout;
use async_trait::async_trait;
use tokio_interruptible_future::{InterruptError, interruptible_sendable};
#[allow(dead_code)]
#[derive(Clone)]
pub struct TasksWithRegularPausesData {
sudden_tx: Arc<Mutex<Option<Sender<()>>>>,
}
impl TasksWithRegularPausesData {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
sudden_tx: Arc::new(Mutex::new(None)),
}
}
}
#[async_trait]
pub trait TasksWithRegularPauses<Task: Future<Output = ()> + Send>: Send + Sync + 'static {
fn data(&self) -> &TasksWithRegularPausesData;
fn data_mut(&mut self) -> &mut TasksWithRegularPausesData;
async fn next_task(&mut self) -> Option<Task>;
fn sleep_duration(&self) -> Duration;
async fn _task(&mut self) -> Result<(), InterruptError> { loop {
let fut = self.next_task().await;
if let Some(fut) = fut {
fut.await;
} else {
break;
}
let (sudden_tx, mut sudden_rx) = mpsc::channel(1);
self.data_mut().sudden_tx = Arc::new(Mutex::new(Some(sudden_tx)));
let sleep_duration = self.sleep_duration(); let _ = timeout(sleep_duration, sudden_rx.recv()).await;
}
Ok(())
}
fn spawn(&'static mut self, interrupt_notifier: async_channel::Receiver<()>) -> JoinHandle<Result<(), InterruptError>> {
spawn( interruptible_sendable(interrupt_notifier, Box::pin(Self::_task(self))))
}
async fn suddenly(&self) -> Result<(), tokio::sync::mpsc::error::TrySendError<()>>{
let sudden_tx = self.data().sudden_tx.lock().await.take(); if let Some(sudden_tx) = sudden_tx {
sudden_tx.try_send(())?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::time::Duration;
use async_channel::bounded;
use tokio::sync::Mutex;
use async_trait::async_trait;
use tokio::runtime::Runtime;
use tokio_interruptible_future::InterruptError;
use crate::TaskItem;
use crate::tasks_with_regular_pauses::{TasksWithRegularPauses, TasksWithRegularPausesData};
#[derive(Clone)]
struct OurTaskQueue {
data: TasksWithRegularPausesData,
}
impl OurTaskQueue {
pub fn new() -> Self {
Self {
data: TasksWithRegularPausesData::new(),
}
}
}
#[async_trait]
impl<'a> TasksWithRegularPauses<TaskItem> for OurTaskQueue where Self: 'static {
fn data(&self) -> &TasksWithRegularPausesData {
&self.data
}
fn data_mut(&mut self) -> &mut TasksWithRegularPausesData {
&mut self.data
}
async fn next_task(&self) -> Option<TaskItem> {
Some(Box::pin(async { () }))
}
fn sleep_duration(&self) -> Duration {
Duration::from_millis(1)
}
}
#[test]
fn empty() -> Result<(), InterruptError> {
let queue = OurTaskQueue::new();
let (interrupt_notifier_tx, interrupt_notifier_rx) = bounded(1);
let rt = Runtime::new().unwrap();
rt.block_on(async {
OurTaskQueue::spawn(queue.clone(), interrupt_notifier_rx);
let _ = interrupt_notifier_tx.send(()).await;
queue.clone().suddenly().await.unwrap();
});
Ok(())
}
}