rust_actions/
registry.rs

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}