1use std::any::Any;
6
7use bb_ir::component::ErasedComponent;
8
9pub use bb_ir::component::{
12 ComponentPackage, ConstructError, ConstructFn, DependencyDecl, RestoreError, RestoreFn,
13 SerializeFn,
14};
15
16pub trait ConcreteComponent: ErasedComponent + Sized {
21 const TYPE_NAME: &'static str;
23
24 const PACKAGE: ComponentPackage = ComponentPackage::Application;
26
27 const DEPENDENCIES: &'static [DependencyDecl] = &[];
30
31 type Config: Any + 'static;
33
34 type Error: std::error::Error + Send + Sync + 'static;
37
38 fn new(config: &Self::Config) -> Result<Self, Self::Error>;
41
42 fn serialize(&self) -> Vec<u8>;
44
45 fn restore(bytes: &[u8]) -> Result<Self, RestoreError>;
47}
48
49pub struct ComponentHandle {
52 pub type_name: &'static str,
54 pub package: ComponentPackage,
56 pub instance_id: u32,
58 pub serialize_fn: SerializeFn,
60 pub restore_fn: RestoreFn,
62 pub state_bytes: Vec<u8>,
64}
65
66impl std::fmt::Debug for ComponentHandle {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 f.debug_struct("ComponentHandle")
69 .field("type_name", &self.type_name)
70 .field("package", &self.package)
71 .field("instance_id", &self.instance_id)
72 .field("state_bytes_len", &self.state_bytes.len())
73 .finish_non_exhaustive()
74 }
75}
76
77impl ComponentHandle {
78 pub fn materialize(&self) -> Result<Box<dyn ErasedComponent>, RestoreError> {
80 (self.restore_fn)(&self.state_bytes)
81 }
82
83 pub fn capture_state(&self, instance: &dyn ErasedComponent) -> Vec<u8> {
85 (self.serialize_fn)(instance)
86 }
87
88 pub fn from_concrete<T: ConcreteComponent>(instance: &T, instance_id: u32) -> Self {
91 Self {
92 type_name: T::TYPE_NAME,
93 package: T::PACKAGE,
94 instance_id,
95 serialize_fn: |erased: &dyn ErasedComponent| -> Vec<u8> {
96 let any: &dyn Any = erased;
97 let concrete: &T = any
98 .downcast_ref::<T>()
99 .expect("ComponentHandle::serialize_fn called with mismatched type");
100 concrete.serialize()
101 },
102 restore_fn: |bytes: &[u8]| -> Result<Box<dyn ErasedComponent>, RestoreError> {
103 T::restore(bytes).map(|v| Box::new(v) as Box<dyn ErasedComponent>)
104 },
105 state_bytes: instance.serialize(),
106 }
107 }
108}