use std::any::Any;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use crate::ctx::Ctx;
use crate::error::CordisError;
use crate::BoxFuture;
pub(crate) mod sync;
pub use sync::{
SyncEvent, SyncListener, SyncNext, SyncPatternListener, SyncPatternWaterfallListener,
SyncWaterfallListener,
};
pub trait Event: Send + Sync + 'static {
const NAME: &'static str;
type Value: Send + 'static;
}
pub trait Listener<E: Event>: Send + Sync + 'static {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
e: &'a E,
) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>>;
}
impl<E, F> Listener<E> for F
where
E: Event,
F: for<'a> Fn(&'a Ctx, &'a E) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>>
+ Send
+ Sync
+ 'static,
{
fn call<'a>(
&'a self,
ctx: &'a Ctx,
e: &'a E,
) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>> {
self(ctx, e)
}
}
pub trait WaterfallListener<E: Event>: Send + Sync + 'static {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
e: &'a E,
next: Next<'a, E>,
) -> BoxFuture<'a, Result<E::Value, CordisError>>;
}
pub trait PatternListener<E: Event>: Send + Sync + 'static {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
key: crate::EventKey<E>,
e: &'a E,
) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>>;
}
impl<E: Event, F> PatternListener<E> for F
where
F: for<'a> Fn(
&'a Ctx,
crate::EventKey<E>,
&'a E,
) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>>
+ Send
+ Sync
+ 'static,
{
fn call<'a>(
&'a self,
ctx: &'a Ctx,
key: crate::EventKey<E>,
e: &'a E,
) -> BoxFuture<'a, Result<Option<E::Value>, CordisError>> {
self(ctx, key, e)
}
}
pub trait PatternWaterfallListener<E: Event>: Send + Sync + 'static {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
key: crate::EventKey<E>,
e: &'a E,
next: Next<'a, E>,
) -> BoxFuture<'a, Result<E::Value, CordisError>>;
}
pub(crate) struct PatternAdapter<L, E: Event>(pub L, pub PhantomData<fn() -> E>);
impl<E: Event, L: PatternListener<E>> crate::bus::ErasedCall for PatternAdapter<L, E> {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
key: &'a crate::TypeKey,
e: &'a DynEvent,
) -> BoxFuture<'a, Result<Option<ErasedValue>, CordisError>> {
Box::pin(async move {
let e = e
.downcast_ref::<E>()
.ok_or_else(|| CordisError::PluginFailed("event type mismatch".into()))?;
let key = crate::EventKey::from_erased(key);
self.0
.call(ctx, key, e)
.await
.map(|value| value.map(|v| Box::new(v) as ErasedValue))
})
}
}
pub(crate) struct PatternWaterfallAdapter<L, E: Event>(pub L, pub PhantomData<fn() -> E>);
impl<E: Event, L: PatternWaterfallListener<E>> crate::bus::ErasedWaterfallCall
for PatternWaterfallAdapter<L, E>
{
fn call<'a>(
&'a self,
ctx: &'a Ctx,
key: &'a crate::TypeKey,
e: &'a DynEvent,
next: crate::bus::ErasedNext<'a>,
) -> BoxFuture<'a, Result<ErasedValue, CordisError>> {
Box::pin(async move {
let e = e
.downcast_ref::<E>()
.ok_or_else(|| CordisError::PluginFailed("event type mismatch".into()))?;
let key = crate::EventKey::from_erased(key);
self.0
.call(
ctx,
key,
e,
Next {
inner: next,
_marker: PhantomData,
},
)
.await
.map(|value| Box::new(value) as ErasedValue)
})
}
}
pub trait Terminal<E: Event>: Send + 'static {
fn call<'a>(&'a self, ctx: &'a Ctx, e: &'a E) -> BoxFuture<'a, Result<E::Value, CordisError>>;
}
impl<E, F> Terminal<E> for F
where
E: Event,
F: for<'a> Fn(&'a Ctx, &'a E) -> BoxFuture<'a, Result<E::Value, CordisError>> + Send + 'static,
{
fn call<'a>(&'a self, ctx: &'a Ctx, e: &'a E) -> BoxFuture<'a, Result<E::Value, CordisError>> {
self(ctx, e)
}
}
pub struct Next<'a, E: Event> {
pub(crate) inner: crate::bus::ErasedNext<'a>,
pub(crate) _marker: PhantomData<fn() -> E>,
}
impl<'a, E: Event> Next<'a, E> {
pub fn call(self) -> BoxFuture<'a, Result<E::Value, CordisError>> {
Box::pin(async move {
let boxed = self.inner.invoke().await?;
match boxed.downcast::<E::Value>() {
Ok(v) => Ok(*v),
Err(_) => Err(CordisError::PluginFailed(
"waterfall value type mismatch".into(),
)),
}
})
}
}
#[derive(Debug, Clone, Copy, Default)]
#[non_exhaustive]
pub struct EventOptions {
pub prepend: bool,
pub once: bool,
}
impl EventOptions {
pub const fn prepend(mut self, prepend: bool) -> Self {
self.prepend = prepend;
self
}
pub const fn once(mut self, once: bool) -> Self {
self.once = once;
self
}
}
pub(crate) type ErasedValue = Box<dyn Any + Send>;
pub(crate) type DynEvent = dyn Any + Send + Sync;
pub(crate) struct ListenerAdapter<L, E: Event>(pub L, pub PhantomData<fn() -> E>);
impl<E: Event, L: Listener<E>> crate::bus::ErasedCall for ListenerAdapter<L, E> {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
_key: &'a crate::TypeKey,
e: &'a DynEvent,
) -> BoxFuture<'a, Result<Option<ErasedValue>, CordisError>> {
match e.downcast_ref::<E>() {
Some(e) => Box::pin(async move {
self.0
.call(ctx, e)
.await
.map(|opt| opt.map(|v| Box::new(v) as ErasedValue))
}),
None => mismatch(),
}
}
}
pub(crate) struct WaterfallAdapter<L, E: Event>(pub L, pub PhantomData<fn() -> E>);
impl<E: Event, L: WaterfallListener<E>> crate::bus::ErasedWaterfallCall for WaterfallAdapter<L, E> {
fn call<'a>(
&'a self,
ctx: &'a Ctx,
_key: &'a crate::TypeKey,
e: &'a DynEvent,
next: crate::bus::ErasedNext<'a>,
) -> BoxFuture<'a, Result<ErasedValue, CordisError>> {
match e.downcast_ref::<E>() {
Some(e) => {
let next = Next {
inner: next,
_marker: PhantomData,
};
Box::pin(async move {
let v = self.0.call(ctx, e, next).await?;
Ok(Box::new(v) as ErasedValue)
})
}
None => mismatch(),
}
}
}
pub(crate) struct TerminalAdapter<E: Event, T: Terminal<E>>(pub T, pub PhantomData<fn() -> E>);
impl<E: Event, T: Terminal<E>> crate::bus::ErasedTerminal for TerminalAdapter<E, T> {
fn call<'a>(
&'a mut self,
ctx: &'a Ctx,
e: &'a DynEvent,
) -> BoxFuture<'a, Result<ErasedValue, CordisError>> {
match e.downcast_ref::<E>() {
Some(e) => Box::pin(async move {
self.0
.call(ctx, e)
.await
.map(|v| Box::new(v) as ErasedValue)
}),
None => mismatch(),
}
}
}
fn mismatch<'a, T>() -> BoxFuture<'a, Result<T, CordisError>> {
Box::pin(async { Err(CordisError::PluginFailed("event type mismatch".into())) })
}
pub(crate) struct CatchUnwind<F>(Pin<Box<F>>);
impl<F> CatchUnwind<F> {
pub(crate) fn new(fut: F) -> Self {
Self(Box::pin(fut))
}
}
impl<F: Future> Future for CatchUnwind<F> {
type Output = Result<F::Output, Box<dyn Any + Send>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let inner =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| this.0.as_mut().poll(cx)));
match inner {
Ok(poll) => poll.map(Ok),
Err(p) => Poll::Ready(Err(p)),
}
}
}