nautilus_common/actor/
registry.rs1use std::{
17 cell::{RefCell, UnsafeCell},
18 fmt::Debug,
19 rc::Rc,
20};
21
22use ahash::{HashMap, HashMapExt};
23use ustr::Ustr;
24
25use super::Actor;
26
27thread_local! {
28 static ACTOR_REGISTRY: ActorRegistry = ActorRegistry::new();
29}
30
31pub struct ActorRegistry {
33 actors: RefCell<HashMap<Ustr, Rc<UnsafeCell<dyn Actor>>>>,
34}
35
36impl Debug for ActorRegistry {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 let actors_ref = self.actors.borrow();
39 let keys: Vec<&Ustr> = actors_ref.keys().collect();
40 f.debug_struct(stringify!(ActorRegistry))
41 .field("actors", &keys)
42 .finish()
43 }
44}
45
46impl Default for ActorRegistry {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl ActorRegistry {
53 pub fn new() -> Self {
54 Self {
55 actors: RefCell::new(HashMap::new()),
56 }
57 }
58
59 pub fn insert(&self, id: Ustr, actor: Rc<UnsafeCell<dyn Actor>>) {
60 let mut actors = self.actors.borrow_mut();
61 if actors.contains_key(&id) {
62 log::warn!("Replacing existing actor with id: {id}");
63 }
64 actors.insert(id, actor);
65 }
66
67 pub fn get(&self, id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
68 self.actors.borrow().get(id).cloned()
69 }
70
71 pub fn len(&self) -> usize {
73 self.actors.borrow().len()
74 }
75
76 pub fn is_empty(&self) -> bool {
78 self.actors.borrow().is_empty()
79 }
80
81 pub fn remove(&self, id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
83 self.actors.borrow_mut().remove(id)
84 }
85
86 pub fn contains(&self, id: &Ustr) -> bool {
88 self.actors.borrow().contains_key(id)
89 }
90}
91
92pub fn get_actor_registry() -> &'static ActorRegistry {
93 ACTOR_REGISTRY.with(|registry| unsafe {
94 std::mem::transmute::<&ActorRegistry, &'static ActorRegistry>(registry)
99 })
100}
101
102pub fn register_actor<T>(actor: T) -> Rc<UnsafeCell<T>>
104where
105 T: Actor + 'static,
106{
107 let actor_id = actor.id();
108 let actor_ref = Rc::new(UnsafeCell::new(actor));
109
110 let actor_trait_ref: Rc<UnsafeCell<dyn Actor>> = actor_ref.clone();
112 get_actor_registry().insert(actor_id, actor_trait_ref);
113
114 actor_ref
115}
116
117pub fn get_actor(id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
118 get_actor_registry().get(id)
119}
120
121#[allow(clippy::mut_from_ref)]
135pub fn get_actor_unchecked<T: Actor>(id: &Ustr) -> &mut T {
136 let actor = get_actor(id).unwrap_or_else(|| panic!("Actor for {id} not found"));
137 unsafe { &mut *(actor.get() as *mut _ as *mut T) }
139}
140
141#[allow(clippy::mut_from_ref)]
145pub fn try_get_actor_unchecked<T: Actor>(id: &Ustr) -> Option<&mut T> {
146 let actor = get_actor(id)?;
147 Some(unsafe { &mut *(actor.get() as *mut _ as *mut T) })
149}
150
151pub fn actor_exists(id: &Ustr) -> bool {
153 get_actor_registry().contains(id)
154}
155
156pub fn actor_count() -> usize {
158 get_actor_registry().len()
159}
160
161#[cfg(test)]
162pub fn clear_actor_registry() {
164 get_actor_registry().actors.borrow_mut().clear();
166}