1use std::sync::Arc;
2
3use crate::error::{Error, Result};
4use crate::extractor::Service;
5use crate::service::RegistrySnapshot;
6
7use super::meta::Meta;
8
9pub struct CronContext {
17 pub(crate) registry: Arc<RegistrySnapshot>,
18 pub(crate) meta: Meta,
19}
20
21pub trait FromCronContext: Sized {
26 fn from_cron_context(ctx: &CronContext) -> Result<Self>;
33}
34
35impl<T: Send + Sync + 'static> FromCronContext for Service<T> {
36 fn from_cron_context(ctx: &CronContext) -> Result<Self> {
37 ctx.registry.get::<T>().map(Service).ok_or_else(|| {
38 Error::internal(format!(
39 "service not found in registry: {}",
40 std::any::type_name::<T>()
41 ))
42 })
43 }
44}
45
46impl FromCronContext for Meta {
47 fn from_cron_context(ctx: &CronContext) -> Result<Self> {
48 Ok(ctx.meta.clone())
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use std::any::{Any, TypeId};
56 use std::collections::HashMap;
57
58 fn test_context() -> CronContext {
59 let mut services: HashMap<TypeId, Arc<dyn Any + Send + Sync>> = HashMap::new();
60 services.insert(TypeId::of::<u32>(), Arc::new(42u32));
61 let snapshot = Arc::new(RegistrySnapshot::new(services));
62
63 CronContext {
64 registry: snapshot,
65 meta: Meta {
66 name: "test_job".to_string(),
67 deadline: None,
68 tick: chrono::Utc::now(),
69 },
70 }
71 }
72
73 #[test]
74 fn service_extractor_finds_registered() {
75 let ctx = test_context();
76 let svc = Service::<u32>::from_cron_context(&ctx).unwrap();
77 assert_eq!(*svc.0, 42);
78 }
79
80 #[test]
81 fn service_extractor_fails_for_missing() {
82 let ctx = test_context();
83 let result = Service::<String>::from_cron_context(&ctx);
84 assert!(result.is_err());
85 }
86
87 #[test]
88 fn meta_extractor_returns_meta() {
89 let ctx = test_context();
90 let meta = Meta::from_cron_context(&ctx).unwrap();
91 assert_eq!(meta.name, "test_job");
92 }
93}