1use std::{error::Error, future::Future, pin::Pin};
6
7use crate::{spawn::JobBuilder, CurrentJob};
8
9pub type JobFunctionType = Box<
11 dyn FnMut(
12 CurrentJob,
13 ) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Send + Sync>>> + Send>>
14 + Send,
15>;
16
17pub trait JobRegister: Sized {
19 fn builder(self) -> JobBuilder;
21 fn name(&self) -> &'static str;
23 fn from_name(name: &str) -> Option<Self>;
25 fn function(&self) -> JobFunctionType;
27}
28
29#[macro_export]
45macro_rules! job_registry {
46 (
47 $reg_name:ident,
48 {$($msg_fn_name:ident: $msg_name:literal => $msg_fn:path),*$(,)?}
49 ) => {
50 #[doc = "Job Registry"]
51 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
52 pub enum $reg_name {
53 $(
54 #[doc = concat!("`", $msg_name, "` leading to `", stringify!($msg_fn), "`.")]
55 #[allow(non_camel_case_types)]
56 $msg_fn_name
57 ),*
58 }
59
60 impl $crate::JobRegister for $reg_name {
61 #[inline]
62 fn builder(self) -> $crate::JobBuilder {
63 match self {
64 $(Self::$msg_fn_name => $crate::JobBuilder::new($msg_name)),*
65 }
66 }
67
68 #[inline]
70 fn name(&self) -> &'static str {
71 match *self {
72 $(Self::$msg_fn_name => $msg_name),*
73 }
74 }
75
76 #[inline]
78 fn from_name(name: &str) -> Option<Self> {
79 match name {
80 $($msg_name => Some(Self::$msg_fn_name)),*,
81 _ => None,
82 }
83 }
84
85 #[inline]
87 fn function(&self) -> $crate::JobFunctionType {
88 match *self {
89 $(Self::$msg_fn_name => Box::new(|job| Box::pin(async move {
90 $msg_fn(job).await.map_err(Into::into)
91 }))),*
92 }
93 }
94 }
95 };
96}
97
98#[cfg(test)]
100mod tests {
101 #![allow(clippy::expect_used, unused_qualifications, clippy::unused_async)]
102
103 use color_eyre::Result;
104
105 use super::*;
106 use crate::job_registry;
107
108 job_registry!(JobRegistry, {
109 some_fn: "cats" => some_fn,
110 OtherFn: "foxes" => self::some_other_fn,
111 });
112
113 async fn some_fn(_job: CurrentJob) -> Result<()> {
114 Ok(())
115 }
116 async fn some_other_fn(_job: CurrentJob) -> Result<(), Box<dyn Error + Send + Sync>> {
117 Ok(())
118 }
119
120 #[test]
121 fn test_job_registry() {
122 let name = JobRegistry::some_fn.name();
123 assert_eq!(name, "cats");
124
125 let _function = JobRegistry::from_name("foxes").expect("name was set").function();
126
127 let _builder = JobRegistry::some_fn.builder();
128 }
129}