hyperstack_interpreter/
spec_trait.rs

1use crate::ast::TypedStreamSpec;
2
3/// Trait for providing stream specifications from different sources
4///
5/// This trait enables dynamic loading of specs without the CLI needing
6/// to directly depend on all atom crates.
7pub trait SpecProvider {
8    /// Get the name of this spec (e.g., "settlement-game")
9    fn spec_name(&self) -> &str;
10
11    /// Get the entity name (e.g., "SettlementGame")
12    fn entity_name(&self) -> &str;
13
14    /// Get the stream spec with type information
15    fn get_spec(&self) -> Box<dyn std::any::Any>;
16
17    /// Get description of this spec
18    fn description(&self) -> Option<&str> {
19        None
20    }
21}
22
23/// Type-erased stream spec that can be used across crate boundaries
24///
25/// This allows the CLI to work with specs without knowing the concrete state type
26pub struct ErasedStreamSpec {
27    pub spec_name: String,
28    pub entity_name: String,
29    pub description: Option<String>,
30    // Store the actual spec as Any for type erasure
31    spec_any: Box<dyn std::any::Any>,
32}
33
34impl ErasedStreamSpec {
35    pub fn new<S: 'static>(
36        spec_name: String,
37        entity_name: String,
38        spec: TypedStreamSpec<S>,
39        description: Option<String>,
40    ) -> Self {
41        ErasedStreamSpec {
42            spec_name,
43            entity_name,
44            description,
45            spec_any: Box::new(spec),
46        }
47    }
48
49    /// Try to downcast to a specific spec type
50    pub fn downcast<S: 'static>(&self) -> Option<&TypedStreamSpec<S>> {
51        self.spec_any.downcast_ref::<TypedStreamSpec<S>>()
52    }
53}