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