blueprint_core/extract/
job_id.rs

1//! Extracts the Job ID from the current job call.
2
3use crate::job::call::Parts as JobCallParts;
4use crate::{FromJobCallParts, IntoJobResult};
5
6/// A Specialized extractor for the [`JobId`] of the current [`JobCall`].
7///
8/// It will try to extract `T` from the job call parts as long as `T` implements [`TryFrom`](core::convert::TryFrom) for [`JobId`] which
9/// already works for all the primitive types and can be implemented for custom types.
10///
11/// [`JobId`]: crate::JobId
12/// [`JobCall`]: crate::JobCall
13#[derive(Debug, Clone)]
14pub struct JobId<T>(pub T);
15
16crate::__impl_deref!(JobId);
17
18impl<T, Ctx> FromJobCallParts<Ctx> for JobId<T>
19where
20    T: TryFrom<crate::JobId>,
21    <T as TryFrom<crate::JobId>>::Error: IntoJobResult,
22    Ctx: Send + Sync + 'static,
23{
24    type Rejection = <T as TryFrom<crate::JobId>>::Error;
25
26    async fn from_job_call_parts(
27        parts: &mut JobCallParts,
28        _: &Ctx,
29    ) -> Result<Self, Self::Rejection> {
30        let job_id = parts.job_id;
31        T::try_from(job_id).map(JobId)
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    macro_rules! test_extract_job_id{
40        ($($ty:ty),*) => {
41            $(
42                let job_id: $ty = 42;
43                let mut parts = JobCallParts::new(job_id);
44                let extracted_job_id: JobId<$ty> = JobId::from_job_call_parts(&mut parts, &()).await.unwrap();
45                assert_eq!(extracted_job_id.0, job_id);
46
47                let job_id = <$ty>::MAX;
48                let mut parts = JobCallParts::new(job_id);
49                let extracted_job_id: JobId<$ty> = JobId::from_job_call_parts(&mut parts, &()).await.unwrap();
50                assert_eq!(extracted_job_id.0, job_id);
51
52                let job_id = <$ty>::MIN;
53                let mut parts = JobCallParts::new(job_id);
54                let extracted_job_id: JobId<$ty> = JobId::from_job_call_parts(&mut parts, &()).await.unwrap();
55                assert_eq!(extracted_job_id.0, job_id);
56            )*
57        };
58    }
59
60    #[tokio::test]
61    async fn it_correctly_extracts_all_numbers() {
62        test_extract_job_id!(
63            u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, i128, u128
64        );
65    }
66
67    #[derive(Copy, Clone, Debug, PartialEq)]
68    struct MyCustomJobId;
69
70    impl TryFrom<crate::JobId> for MyCustomJobId {
71        type Error = ();
72
73        fn try_from(job_id: crate::JobId) -> Result<Self, Self::Error> {
74            if u64::from(job_id) == 42u64 {
75                Ok(MyCustomJobId)
76            } else {
77                Err(())
78            }
79        }
80    }
81
82    impl From<MyCustomJobId> for crate::job::JobId {
83        fn from(_: MyCustomJobId) -> crate::JobId {
84            42u64.into()
85        }
86    }
87
88    #[tokio::test]
89    async fn it_works_for_custom_types() {
90        let job_id: MyCustomJobId = MyCustomJobId;
91        let mut parts = JobCallParts::new(job_id);
92
93        let extracted_job_id: JobId<MyCustomJobId> =
94            JobId::from_job_call_parts(&mut parts, &()).await.unwrap();
95        assert_eq!(extracted_job_id.0, job_id);
96    }
97
98    #[tokio::test]
99    async fn it_rejects_invalid_job_ids() {
100        let mut parts = JobCallParts::new(41u64);
101        let extracted_job_id = JobId::<MyCustomJobId>::from_job_call_parts(&mut parts, &()).await;
102        assert!(extracted_job_id.is_err());
103    }
104}