nautilus_common/actor/
registry.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{
17    cell::{RefCell, UnsafeCell},
18    rc::Rc,
19    sync::OnceLock,
20};
21
22use ahash::{HashMap, HashMapExt};
23use ustr::Ustr;
24
25use super::Actor;
26
27pub struct ActorRegistry {
28    actors: RefCell<HashMap<Ustr, Rc<UnsafeCell<dyn Actor>>>>,
29}
30
31impl Default for ActorRegistry {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl ActorRegistry {
38    pub fn new() -> Self {
39        Self {
40            actors: RefCell::new(HashMap::new()),
41        }
42    }
43
44    pub fn insert(&self, id: Ustr, actor: Rc<UnsafeCell<dyn Actor>>) {
45        self.actors.borrow_mut().insert(id, actor);
46    }
47
48    pub fn get(&self, id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
49        self.actors.borrow().get(id).cloned()
50    }
51}
52
53// SAFETY: Actor registry is not meant to be passed between threads
54unsafe impl Sync for ActorRegistry {}
55unsafe impl Send for ActorRegistry {}
56
57static ACTOR_REGISTRY: OnceLock<ActorRegistry> = OnceLock::new();
58
59pub fn get_actor_registry() -> &'static ActorRegistry {
60    ACTOR_REGISTRY.get_or_init(ActorRegistry::new)
61}
62
63pub fn register_actor(actor: Rc<UnsafeCell<dyn Actor>>) {
64    let actor_id = unsafe { &mut *actor.get() }.id();
65    get_actor_registry().insert(actor_id, actor);
66}
67
68pub fn get_actor(id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
69    get_actor_registry().get(id)
70}
71
72#[allow(clippy::mut_from_ref)]
73pub fn get_actor_unchecked<T: Actor>(id: &Ustr) -> &mut T {
74    let actor = get_actor(id).unwrap_or_else(|| panic!("Actor for {id} not found"));
75    unsafe { &mut *(actor.get() as *mut _ as *mut T) }
76}