Skip to main content

bb_ir/
component.rs

1//! Foundation polymorphism plumbing shared by `bb-dsl` (authoring)
2//! and `bb-runtime` (dispatch).
3
4use std::any::Any;
5
6/// Marker for engine-owned component instances. Blanket impl covers
7/// every `Any + Send + Sync`.
8pub trait ErasedComponent: Any + Send + Sync {}
9
10impl<T: Any + Send + Sync> ErasedComponent for T {}
11
12/// Dyn-safe downcast surface. No blanket impl — `Box<dyn AnyComponent>`
13/// would otherwise shadow per-type vtables. `bb::Concrete` derive
14/// emits the impl.
15pub trait AnyComponent: ErasedComponent {
16    /// Downcast view - immutable.
17    fn as_any(&self) -> &dyn Any;
18
19    /// Downcast view - mutable.
20    fn as_any_mut(&mut self) -> &mut dyn Any;
21}
22
23/// Component-package origin tag. Surfaces in introspection +
24/// telemetry.
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
26pub enum ComponentPackage {
27    /// Shipped in the bytesandbrains crate family.
28    Framework,
29
30    /// Shipped by the application author. Default.
31    Application,
32}
33
34/// Author-declared sibling dependency at a named slot. Compiler
35/// verifies role match; runtime reaches it via
36/// `RuntimeResourceRef::dependency::<T>(slot)`.
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
38pub struct DependencyDecl {
39    /// PascalCase role identifier. Plain string so `bb-ir` stays
40    /// free of the `ComponentRole` enum.
41    pub role: &'static str,
42
43    /// Slot name in the compiler's binding spec.
44    pub slot: &'static str,
45}
46
47/// Error variants surfaced by `ConcreteComponent::restore`.
48#[derive(Debug)]
49pub enum RestoreError {
50    /// Deserialization failed at the framework's bincode boundary.
51    Malformed(bincode::Error),
52
53    /// Impl-specific restore failure.
54    Custom(String),
55}
56
57impl std::fmt::Display for RestoreError {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        match self {
60            Self::Malformed(e) => write!(f, "malformed component state bytes: {e}"),
61            Self::Custom(m) => write!(f, "component restore failed: {m}"),
62        }
63    }
64}
65
66impl std::error::Error for RestoreError {}
67
68/// Monomorphized `T::serialize` captured at derive-codegen time.
69pub type SerializeFn = fn(&dyn ErasedComponent) -> Vec<u8>;
70
71/// Monomorphized `T::restore`; used by snapshot/resume.
72pub type RestoreFn = fn(&[u8]) -> Result<Box<dyn ErasedComponent>, RestoreError>;
73
74/// Errors surfaced by `ConstructFn`.
75#[derive(Debug)]
76pub struct ConstructError {
77    /// `TYPE_NAME` of the concrete being constructed.
78    pub type_name: &'static str,
79    /// Downcast miss or `T::new` error stringified.
80    pub detail: String,
81}
82
83impl std::fmt::Display for ConstructError {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(f, "construct {}: {}", self.type_name, self.detail)
86    }
87}
88
89impl std::error::Error for ConstructError {}
90
91/// Per-type constructor. Downcasts `&dyn Any` → `&Config` and calls
92/// `T::new`. Install looks it up by `TYPE_NAME`.
93pub type ConstructFn = fn(&dyn Any) -> Result<Box<dyn ErasedComponent>, ConstructError>;
94