use std::any::Any;
use crate::error::IdentityError;
pub trait Actor: Send + Sync + Any {
fn label(&self) -> &str;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
}
#[macro_export]
macro_rules! actor_downcast_methods {
() => {
fn as_any(&self) -> &dyn ::std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any {
self
}
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn ::std::any::Any> {
self
}
};
}
pub trait IdentityFactory: Send + Sync + 'static {
fn reconstruct(&self, actor_json: &str) -> Result<Box<dyn Actor>, IdentityError>;
}
#[cfg(test)]
mod tests {
use super::*;
struct TestActor {
label: String,
}
impl Actor for TestActor {
fn label(&self) -> &str {
&self.label
}
actor_downcast_methods!();
}
struct TestFactory;
impl IdentityFactory for TestFactory {
fn reconstruct(&self, actor_json: &str) -> Result<Box<dyn Actor>, IdentityError> {
if actor_json.contains("System") {
Ok(Box::new(TestActor {
label: "ok".into(),
}))
} else {
Err(IdentityError::InvalidActor("missing System".into()))
}
}
}
#[test]
fn identity_factory_reconstructs() {
let factory = TestFactory;
let actor = factory
.reconstruct(r#"{"System":{"operation":"t"}}"#)
.expect("ok");
assert_eq!(actor.label(), "ok");
}
#[test]
fn actor_downcast_to_concrete() {
let factory = TestFactory;
let actor = factory
.reconstruct(r#"{"System":{"operation":"t"}}"#)
.expect("ok");
let concrete = actor
.into_any()
.downcast::<TestActor>()
.expect("TestActor");
assert_eq!(concrete.label(), "ok");
}
}