use futures_util::future::join_all;
use std::{convert::Infallible, ops::Deref};
use serde::{Deserialize, Serialize};
use crate::{
error::{CallSubscribeError, CborValueError, TryFromEventError},
future::SubscribeFutureRet,
state::State,
};
pub use ciborium::Value;
#[cfg(feature = "macros")]
pub use ioevent_macro::{Event, subscriber};
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct EventData {
pub tag: String,
pub payload: Value,
}
pub type AnyEvent = EventData;
type SubscribeFn<T> = fn(&State<T>, &EventData) -> SubscribeFutureRet;
pub struct Subscriber<T>((), &'static Selector, pub SubscribeFn<T>)
where
T: 'static;
impl<T> Deref for Subscriber<T> {
type Target = SubscribeFn<T>;
fn deref(&self) -> &Self::Target {
&self.2
}
}
impl<T> Subscriber<T> {
pub const fn new<E>(f: SubscribeFn<T>) -> Self
where
E: Event,
{
Subscriber((), &E::SELECTOR, f)
}
pub async fn try_call(
&self,
state: &State<T>,
event: &EventData,
) -> Result<(), CallSubscribeError> {
if self.1.match_event(event) {
(*self)(state, event).await
} else {
Ok(())
}
}
}
type InnerSubscribers<T> = Subscriber<T>;
pub struct Subscribers<T>(pub &'static [InnerSubscribers<T>])
where
T: 'static;
impl<T> Clone for Subscribers<T> {
fn clone(&self) -> Self {
Subscribers(self.0)
}
}
impl<T> Copy for Subscriber<T> {}
impl<T> Clone for Subscriber<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Subscribers<T>
where
T: 'static,
{
pub fn init(sub_iter: impl Into<&'static [InnerSubscribers<T>]>) -> Self {
Subscribers(sub_iter.into())
}
pub async fn emit(
&self,
state: &State<T>,
event: &EventData,
) -> impl Iterator<Item = CallSubscribeError> + use<T> + Send + 'static {
let futures = self.0.iter().map(|sub| sub.try_call(state, event));
join_all(futures).await.into_iter().filter_map(|v| v.err())
}
}
impl From<Infallible> for TryFromEventError {
fn from(_value: Infallible) -> Self {
TryFromEventError::Infallible
}
}
impl From<CborValueError> for TryFromEventError {
fn from(value: CborValueError) -> Self {
TryFromEventError::Deserialize(value)
}
}
pub trait Event: Serialize + for<'ed> TryFrom<&'ed EventData, Error = TryFromEventError> {
const TAG: &'static str;
const SELECTOR: Selector = Selector(|x| x.tag == Self::TAG);
fn upcast(&self) -> Result<EventData, CborValueError> {
Ok(EventData {
tag: Self::TAG.to_string(),
payload: Value::serialized(&self)?,
})
}
}
impl Event for EventData {
const TAG: &'static str = "#";
const SELECTOR: Selector = Selector(|_| true);
fn upcast(&self) -> Result<EventData, CborValueError> {
Ok(self.clone())
}
}
impl TryFrom<&EventData> for EventData {
type Error = TryFromEventError;
fn try_from(value: &EventData) -> Result<Self, Self::Error> {
Ok(value.clone())
}
}
#[derive(Hash, Eq, PartialEq)]
pub struct Selector(pub fn(&EventData) -> bool);
impl Selector {
pub fn match_event(&self, event: &EventData) -> bool {
(self.0)(event)
}
}