1use crate::args::RawArgs;
2use crate::outputs::StepOutputs;
3use crate::world::World;
4use crate::Result;
5use std::any::{Any, TypeId};
6use std::collections::HashMap;
7use std::future::Future;
8use std::pin::Pin;
9
10pub type StepFn<W> =
11 for<'a> fn(&'a mut W, RawArgs) -> Pin<Box<dyn Future<Output = Result<StepOutputs>> + Send + 'a>>;
12
13pub type ErasedStepFn = for<'a> fn(
14 &'a mut dyn Any,
15 RawArgs,
16) -> Pin<Box<dyn Future<Output = Result<StepOutputs>> + Send + 'a>>;
17
18pub struct ErasedStepDef {
19 pub name: &'static str,
20 pub world_type_id: TypeId,
21 pub func: ErasedStepFn,
22}
23
24impl ErasedStepDef {
25 pub const fn new(
26 name: &'static str,
27 world_type_id: TypeId,
28 func: ErasedStepFn,
29 ) -> Self {
30 Self {
31 name,
32 world_type_id,
33 func,
34 }
35 }
36}
37
38inventory::collect!(ErasedStepDef);
39
40pub struct StepRegistry {
41 steps: HashMap<String, ErasedStepFn>,
42}
43
44impl StepRegistry {
45 pub fn new() -> Self {
46 Self {
47 steps: HashMap::new(),
48 }
49 }
50
51 pub fn collect_for<W: World + 'static>(&mut self) {
52 let target_type_id = TypeId::of::<W>();
53
54 for step in inventory::iter::<ErasedStepDef> {
55 if step.world_type_id == target_type_id {
56 self.steps.insert(step.name.to_string(), step.func);
57 }
58 }
59 }
60
61 pub fn register(&mut self, name: impl Into<String>, func: ErasedStepFn) {
62 self.steps.insert(name.into(), func);
63 }
64
65 pub fn get(&self, name: &str) -> Option<&ErasedStepFn> {
66 self.steps.get(name)
67 }
68
69 pub fn len(&self) -> usize {
70 self.steps.len()
71 }
72
73 pub fn is_empty(&self) -> bool {
74 self.steps.is_empty()
75 }
76}
77
78impl Default for StepRegistry {
79 fn default() -> Self {
80 Self::new()
81 }
82}