use std::{error::Error, future::Future, pin::Pin};
use crate::{spawn::JobBuilder, CurrentJob};
pub type JobFunctionType = Box<
dyn FnMut(
CurrentJob,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Send + Sync>>> + Send>>
+ Send,
>;
pub trait JobRegister: Sized {
fn builder(self) -> JobBuilder;
fn name(&self) -> &'static str;
fn from_name(name: &str) -> Option<Self>;
fn function(&self) -> JobFunctionType;
}
#[macro_export]
macro_rules! job_registry {
(
$reg_name:ident,
{$($msg_fn_name:ident: $msg_name:literal => $msg_fn:path),*$(,)?}
) => {
#[doc = "Job Registry"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum $reg_name {
$(
#[doc = concat!("`", $msg_name, "` leading to `", stringify!($msg_fn), "`.")]
#[allow(non_camel_case_types)]
$msg_fn_name
),*
}
impl $crate::JobRegister for $reg_name {
#[inline]
fn builder(self) -> $crate::JobBuilder {
match self {
$(Self::$msg_fn_name => $crate::JobBuilder::new($msg_name)),*
}
}
#[inline]
fn name(&self) -> &'static str {
match *self {
$(Self::$msg_fn_name => $msg_name),*
}
}
#[inline]
fn from_name(name: &str) -> Option<Self> {
match name {
$($msg_name => Some(Self::$msg_fn_name)),*,
_ => None,
}
}
#[inline]
fn function(&self) -> $crate::JobFunctionType {
match *self {
$(Self::$msg_fn_name => Box::new(|job| Box::pin(async move {
$msg_fn(job).await.map_err(Into::into)
}))),*
}
}
}
};
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, unused_qualifications, clippy::unused_async)]
use color_eyre::Result;
use super::*;
use crate::job_registry;
job_registry!(JobRegistry, {
some_fn: "cats" => some_fn,
OtherFn: "foxes" => self::some_other_fn,
});
async fn some_fn(_job: CurrentJob) -> Result<()> {
Ok(())
}
async fn some_other_fn(_job: CurrentJob) -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(())
}
#[test]
fn test_job_registry() {
let name = JobRegistry::some_fn.name();
assert_eq!(name, "cats");
let _function = JobRegistry::from_name("foxes").expect("name was set").function();
let _builder = JobRegistry::some_fn.builder();
}
}