parent
c98f1c5c6c
commit
d3c43b323b
@ -0,0 +1,187 @@
|
||||
//! Cancelling async operations
|
||||
use tokio::sync::{
|
||||
watch,
|
||||
};
|
||||
use futures::Future;
|
||||
use std::{
|
||||
pin::Pin,
|
||||
task::{
|
||||
Poll,
|
||||
Context,
|
||||
}
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
macro_rules! with_cancel {
|
||||
($block:expr, $tok:expr) => {
|
||||
{
|
||||
::tokio::select!{
|
||||
_ = $tok => {
|
||||
Err($crate::cancel::TaskCancelledError)
|
||||
}
|
||||
a = $block => {
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn _test<T>(tok: T)
|
||||
where T: CancelFuture
|
||||
{
|
||||
with_cancel!(async move {
|
||||
123
|
||||
}, tok).unwrap();
|
||||
}
|
||||
|
||||
/// Error returned for cancelled `with_cancel!` blocks.
|
||||
#[derive(Debug)]
|
||||
pub struct TaskCancelledError;
|
||||
|
||||
/// A future used for cancelling an operation
|
||||
pub trait CancelFuture: Future{}
|
||||
|
||||
impl<F: ?Sized> CancelFuture for F
|
||||
where F: Future<Output = ()>{}
|
||||
|
||||
/// A token that can be awaited.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CancellationToken(watch::Receiver<bool>);
|
||||
|
||||
/// A source of `CancellationToken`s.
|
||||
#[derive(Debug)]
|
||||
pub struct CancellationTokenSource(watch::Sender<bool>, watch::Receiver<bool>);
|
||||
|
||||
impl CancellationTokenSource
|
||||
{
|
||||
/// Create a new cancellation token source
|
||||
pub fn new() -> Self
|
||||
{
|
||||
let (tx, rx) = watch::channel(false);
|
||||
Self(tx, rx)
|
||||
}
|
||||
|
||||
/// Create a new token
|
||||
pub fn create_token(&self) -> CancellationToken
|
||||
{
|
||||
CancellationToken(self.1.clone())
|
||||
}
|
||||
|
||||
/// Instruct all tokens to cancel.
|
||||
pub fn cancel(&mut self)
|
||||
{
|
||||
let _ = self.0.broadcast(true);
|
||||
}
|
||||
|
||||
/// Instruct all tokens to cancel, then drop this source.
|
||||
///
|
||||
/// When a source is dropped without cancelling, its tokens never complete.
|
||||
#[inline] pub fn cancel_consume(mut self)
|
||||
{
|
||||
self.cancel();
|
||||
}
|
||||
|
||||
/// Has this source been signalled?
|
||||
pub fn is_cancelled(&self) -> bool
|
||||
{
|
||||
*self.1.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
impl CancellationToken
|
||||
{
|
||||
/// Try to run this future, cancel it an return error if this token is signalled, consuming the token in the process.
|
||||
pub fn try_run_owned<'a, F: 'a, T>(self, fut: F) -> impl Future<Output=Result<T, TaskCancelledError>> + 'a
|
||||
where F: Future<Output=T>
|
||||
{
|
||||
async move {
|
||||
with_cancel!(fut, self.into_wait_on())
|
||||
}
|
||||
}
|
||||
/// Try to run this future, cancel it an return error if this token is signalled.
|
||||
pub async fn try_run<F, T>(&mut self, fut: F) -> Result<T, TaskCancelledError>
|
||||
where F: Future<Output=T>
|
||||
{
|
||||
with_cancel!(fut, self.wait_on())
|
||||
}
|
||||
/// Has this token been signalled?
|
||||
pub fn is_cancelled(&self) -> bool
|
||||
{
|
||||
*self.0.borrow()
|
||||
}
|
||||
|
||||
/// Panic the current task if this token has signalled cancelled.
|
||||
#[inline(always)] pub fn panic_if_cancelled(&self)
|
||||
{
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn inner_panic() -> !
|
||||
{
|
||||
panic!("Task cancelled")
|
||||
|
||||
}
|
||||
if self.is_cancelled() {
|
||||
inner_panic();
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for cancel to be
|
||||
pub async fn wait_on(&mut self)
|
||||
{
|
||||
if !*self.0.borrow() {
|
||||
while !match self.0.recv().await {
|
||||
Some(v) => v,
|
||||
None => return NeverFuture::never().await,
|
||||
} {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Consume into waiter.
|
||||
pub fn into_wait_on(mut self) -> impl CancelFuture + 'static
|
||||
{
|
||||
async move {
|
||||
if !*self.0.borrow() {
|
||||
while !match self.0.recv().await {
|
||||
Some(v) => v,
|
||||
None => return NeverFuture::never().await,
|
||||
} {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for CancellationToken
|
||||
{
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let fut = self.get_mut().wait_on();
|
||||
tokio::pin!(fut);
|
||||
fut.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// A future that never completes, and never queues itself for awakening.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NeverFuture<T=futures::never::Never>(PhantomData<T>);
|
||||
|
||||
impl<T> NeverFuture<T>
|
||||
{
|
||||
/// Create a new never-completing future.
|
||||
#[inline] pub const fn never() -> Self
|
||||
{
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for NeverFuture<T>
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
#[inline(always)] fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
//! Piping messages around
|
||||
use super::*;
|
||||
use futures::Future;
|
||||
|
||||
pub mod pubsub;
|
||||
|
||||
pub fn pass_messages()
|
@ -0,0 +1,22 @@
|
||||
//! Pub-sub traits
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{
|
||||
RwLock,
|
||||
mpsc,
|
||||
};
|
||||
|
||||
use message::Message;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SubListInner
|
||||
{
|
||||
//TODO: how tf do we do this?
|
||||
//subs: RwLock<HashMap<TypeID, RwLock<Vec<mpsc::Sender<message::SerializedMessage<dyn message::MessageValue>>>>>>,
|
||||
}
|
||||
|
||||
/// List of subscibers
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubscriberListRef(Arc<SubListInner>);
|
@ -0,0 +1,11 @@
|
||||
//! Socket handlers
|
||||
use super::*;
|
||||
|
||||
use tokio::io::{
|
||||
AsyncWrite,
|
||||
AsyncRead
|
||||
};
|
||||
use futures::Future;
|
||||
use cancel::*;
|
||||
|
||||
//pub fn handle_socket() -> impl Future<>
|
Loading…
Reference in new issue