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// -------------------------------------------------------------------------------------------------
1516use std::{
17 cell::{RefCell, UnsafeCell},
18 rc::Rc,
19 sync::OnceLock,
20};
2122use ahash::{HashMap, HashMapExt};
23use ustr::Ustr;
2425use super::Actor;
2627pub struct ActorRegistry {
28 actors: RefCell<HashMap<Ustr, Rc<UnsafeCell<dyn Actor>>>>,
29}
3031impl Default for ActorRegistry {
32fn default() -> Self {
33Self::new()
34 }
35}
3637impl ActorRegistry {
38pub fn new() -> Self {
39Self {
40 actors: RefCell::new(HashMap::new()),
41 }
42 }
4344pub fn insert(&self, id: Ustr, actor: Rc<UnsafeCell<dyn Actor>>) {
45self.actors.borrow_mut().insert(id, actor);
46 }
4748pub fn get(&self, id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
49self.actors.borrow().get(id).cloned()
50 }
51}
5253// SAFETY: Actor registry is not meant to be passed between threads
54unsafe impl Sync for ActorRegistry {}
55unsafe impl Send for ActorRegistry {}
5657static ACTOR_REGISTRY: OnceLock<ActorRegistry> = OnceLock::new();
5859pub fn get_actor_registry() -> &'static ActorRegistry {
60 ACTOR_REGISTRY.get_or_init(ActorRegistry::new)
61}
6263pub fn register_actor(actor: Rc<UnsafeCell<dyn Actor>>) {
64let actor_id = unsafe { &mut *actor.get() }.id();
65 get_actor_registry().insert(actor_id, actor);
66}
6768pub fn get_actor(id: &Ustr) -> Option<Rc<UnsafeCell<dyn Actor>>> {
69 get_actor_registry().get(id)
70}
7172#[allow(clippy::mut_from_ref)]
73pub fn get_actor_unchecked<T: Actor>(id: &Ustr) -> &mut T {
74let actor = get_actor(id).unwrap_or_else(|| panic!("Actor for {id} not found"));
75unsafe { &mut *(actor.get() as *mut _ as *mut T) }
76}