use std::fmt;
use std::future::Future;
use std::fmt::Debug;
use std::pin::Pin;
use std::sync::Arc;
use acton_ern::Ern;
use super::SupervisionError;
use crate::actor::{ActorConfig, Idle, ManagedActor, RestartPolicy};
use crate::common::{ActorHandle, ActorRuntime};
type SpawnFuture<'a> =
Pin<Box<dyn Future<Output = Result<ActorHandle, SupervisionError>> + Send + 'a>>;
pub trait ChildSpawner: Send + Sync + Debug {
fn child_id(&self) -> &Ern;
fn restart_policy(&self) -> RestartPolicy;
fn spawn(&self, runtime: ActorRuntime, parent: ActorHandle) -> SpawnFuture<'_>;
}
pub type ChildBlueprint<S> = dyn Fn(&mut ManagedActor<Idle, S>) + Send + Sync + 'static;
pub struct TypedSpawner<S: Default + Send + Debug + 'static> {
child_id: Ern,
config: ActorConfig,
blueprint: Arc<ChildBlueprint<S>>,
}
impl<S: Default + Send + Debug + 'static> TypedSpawner<S> {
pub fn new(config: ActorConfig, blueprint: Arc<ChildBlueprint<S>>) -> Self {
Self {
child_id: config.id(),
config,
blueprint,
}
}
}
impl<S: Default + Send + Debug + 'static> Debug for TypedSpawner<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypedSpawner")
.field("child_id", &self.child_id)
.field("model", &std::any::type_name::<S>())
.finish_non_exhaustive()
}
}
impl<S: Default + Send + Debug + 'static> ChildSpawner for TypedSpawner<S> {
fn child_id(&self) -> &Ern {
&self.child_id
}
fn restart_policy(&self) -> RestartPolicy {
self.config.restart_policy()
}
fn spawn(&self, runtime: ActorRuntime, _parent: ActorHandle) -> SpawnFuture<'_> {
Box::pin(async move {
let mut actor = ManagedActor::<Idle, S>::new(Some(&runtime), Some(&self.config));
(self.blueprint)(&mut actor);
Ok(actor.start().await)
})
}
}