use crate::actor::ActorManager; use crate::{Actor, Addr}; use anyhow::Result; use fnv::FnvHasher; use futures::lock::Mutex; use once_cell::sync::OnceCell; use std::any::{Any, TypeId}; use std::cell::RefCell; use std::collections::HashMap; use std::hash::BuildHasherDefault; /// Trait define a global service. /// /// The service is a global actor. /// You can use `Actor::from_registry` to get the address `Addr` of the service. /// /// # Examples /// /// ```rust /// use xactor::*; /// /// #[message(result = "i32")] /// struct AddMsg(i32); /// /// #[derive(Default)] /// struct MyService(i32); /// /// impl Actor for MyService {} /// /// impl Service for MyService {} /// /// #[async_trait::async_trait] /// impl Handler for MyService { /// async fn handle(&mut self, ctx: &mut Context, msg: AddMsg) -> i32 { /// self.0 += msg.0; /// self.0 /// } /// } /// /// #[xactor::main] /// async fn main() -> Result<()> { /// let mut addr = MyService::from_registry().await?; /// assert_eq!(addr.call(AddMsg(1)).await?, 1); /// assert_eq!(addr.call(AddMsg(5)).await?, 6); /// Ok(()) /// } /// ``` #[async_trait::async_trait] pub trait Service: Actor + Default { async fn from_registry() -> Result> { static REGISTRY: OnceCell< Mutex, BuildHasherDefault>>, > = OnceCell::new(); let registry = REGISTRY.get_or_init(Default::default); let mut registry = registry.lock().await; match registry.get_mut(&TypeId::of::()) { Some(addr) => Ok(addr.downcast_ref::>().unwrap().clone()), None => { let actor_manager = ActorManager::new(); registry.insert(TypeId::of::(), Box::new(actor_manager.address())); drop(registry); actor_manager.start_actor(Self::default()).await } } } } thread_local! { static LOCAL_REGISTRY: RefCell, BuildHasherDefault>> = Default::default(); } /// Trait define a local service. /// /// The service is a thread local actor. /// You can use `Actor::from_registry` to get the address `Addr` of the service. #[async_trait::async_trait] pub trait LocalService: Actor + Default { async fn from_registry() -> Result> { let res = LOCAL_REGISTRY.with(|registry| { registry .borrow_mut() .get_mut(&TypeId::of::()) .map(|addr| addr.downcast_ref::>().unwrap().clone()) }); match res { Some(addr) => Ok(addr), None => { let addr = ActorManager::new().start_actor(Self::default()).await?; LOCAL_REGISTRY.with(|registry| { registry .borrow_mut() .insert(TypeId::of::(), Box::new(addr.clone())); }); Ok(addr) } } } }