use std::any::{Any, TypeId};
use std::fmt;
use std::sync::Arc;
use futures::future::BoxFuture;
use crate::types::job_id::JobID;
use super::callback_msg::CallbackMsg;
pub enum CallbackHandler {
Sync(Box<dyn Fn(&dyn CallbackMsg) + Send + Sync>),
Async(Box<dyn Fn(Arc<dyn Any + Send + Sync>) -> BoxFuture<'static, ()> + Send + Sync>),
}
impl fmt::Debug for CallbackHandler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CallbackHandler::Sync(_) => f.write_str("CallbackHandler::Sync"),
CallbackHandler::Async(_) => f.write_str("CallbackHandler::Async"),
}
}
}
pub struct CallbackSubscription {
type_id: TypeId,
job_id: Option<JobID>,
handler: CallbackHandler,
}
impl CallbackSubscription {
pub fn new(type_id: TypeId, job_id: Option<JobID>, handler: CallbackHandler) -> Self {
Self {
type_id,
job_id,
handler,
}
}
pub fn callback_type(&self) -> TypeId {
self.type_id
}
pub fn job_id(&self) -> Option<JobID> {
self.job_id
}
pub fn matches(&self, type_id: TypeId, job_id: JobID) -> bool {
if self.type_id != type_id {
return false;
}
match self.job_id {
None => true,
Some(id) => id == JobID::INVALID || id == job_id,
}
}
pub fn handler(&self) -> &CallbackHandler {
&self.handler
}
}
impl fmt::Debug for CallbackSubscription {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CallbackSubscription")
.field("type_id", &self.type_id)
.field("job_id", &self.job_id)
.field("handler", &self.handler)
.finish()
}
}
pub struct Callback<TCall>
where
TCall: CallbackMsg + 'static,
{
job_id: Option<JobID>,
on_run: Box<dyn Fn(&TCall) + Send + Sync>,
}
impl<TCall> Callback<TCall>
where
TCall: CallbackMsg + 'static,
{
pub fn new(on_run: Box<dyn Fn(&TCall) + Send + Sync>, job_id: Option<JobID>) -> Self {
Self { job_id, on_run }
}
pub fn job_id(&self) -> Option<JobID> {
self.job_id
}
pub fn into_subscription(self) -> CallbackSubscription {
let type_id = TypeId::of::<TCall>();
let on_run = self.on_run;
CallbackSubscription::new(
type_id,
self.job_id,
CallbackHandler::Sync(Box::new(move |msg: &dyn CallbackMsg| {
if let Some(callback) = msg.as_any().downcast_ref::<TCall>() {
on_run(callback);
}
})),
)
}
}
impl<TCall> fmt::Debug for Callback<TCall>
where
TCall: CallbackMsg + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Callback")
.field("type_id", &TypeId::of::<TCall>())
.field("job_id", &self.job_id)
.finish()
}
}
pub struct AsyncCallback<TCall>
where
TCall: CallbackMsg + 'static,
{
job_id: Option<JobID>,
on_run: Box<dyn Fn(Arc<TCall>) -> BoxFuture<'static, ()> + Send + Sync>,
}
impl<TCall> AsyncCallback<TCall>
where
TCall: CallbackMsg + 'static,
{
pub fn new(on_run: Box<dyn Fn(Arc<TCall>) -> BoxFuture<'static, ()> + Send + Sync>, job_id: Option<JobID>) -> Self {
Self { job_id, on_run }
}
pub fn job_id(&self) -> Option<JobID> {
self.job_id
}
pub fn into_subscription(self) -> CallbackSubscription {
let type_id = TypeId::of::<TCall>();
let on_run = self.on_run;
CallbackSubscription::new(
type_id,
self.job_id,
CallbackHandler::Async(Box::new(move |msg: Arc<dyn Any + Send + Sync>| {
match msg.downcast::<TCall>() {
Ok(callback) => on_run(callback),
Err(_) => Box::pin(async {}),
}
})),
)
}
}
impl<TCall> fmt::Debug for AsyncCallback<TCall>
where
TCall: CallbackMsg + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AsyncCallback")
.field("type_id", &TypeId::of::<TCall>())
.field("job_id", &self.job_id)
.finish()
}
}