1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Local actor registry for registering and looking up actors by arbitrary names.
use std::{
any::Any,
borrow::{Borrow, Cow},
collections::{HashMap, hash_map::Keys},
hash::Hash,
sync::{LazyLock, Mutex},
};
use crate::{
Actor,
actor::{ActorId, ActorRef},
error::RegistryError,
};
/// Global actor registry for local actors.
pub static ACTOR_REGISTRY: LazyLock<Mutex<ActorRegistry>> =
LazyLock::new(|| Mutex::new(ActorRegistry::new()));
/// A local actor registry storing actor refs by name.
#[derive(Debug, Default)]
pub struct ActorRegistry {
actor_refs: HashMap<Cow<'static, str>, RegisteredActorRef>,
}
impl ActorRegistry {
/// Creates a new empty actor registry.
pub fn new() -> Self {
ActorRegistry {
actor_refs: HashMap::new(),
}
}
/// Creates a new empty actor registry with at least the specified capacity.
pub fn with_capacity(capacity: usize) -> Self {
ActorRegistry {
actor_refs: HashMap::with_capacity(capacity),
}
}
/// Returns the number of actor refs that can be held without reallocating.
pub fn capacity(&self) -> usize {
self.actor_refs.capacity()
}
/// An iterator visiting all registered actor refs in arbitrary order.
pub fn names(&self) -> Keys<'_, Cow<'static, str>, RegisteredActorRef> {
self.actor_refs.keys()
}
/// The number of registered actor refs.
pub fn len(&self) -> usize {
self.actor_refs.len()
}
/// Returns `true` if the registry contains no actor refs.
pub fn is_empty(&self) -> bool {
self.actor_refs.is_empty()
}
/// Clears the registry, removing all actor refs. Keeps the allocated memory for reuse.
pub fn clear(&mut self) {
self.actor_refs.clear()
}
/// Gets an actor ref previously registered for a given actor type.
///
/// If the actor type does not match the one it was registered with,
/// a [`RegistryError::BadActorType`] error will be returned.
pub fn get<A, Q>(&mut self, name: &Q) -> Result<Option<ActorRef<A>>, RegistryError>
where
A: Actor,
Q: Hash + Eq + ?Sized,
Cow<'static, str>: Borrow<Q>,
{
self.actor_refs
.get(name)
.map(|actor_ref| {
actor_ref
.actor_ref()
.cloned()
.ok_or(RegistryError::BadActorType)
})
.transpose()
}
/// Returns `true` if an actor has been registered under a given name.
pub fn contains_name<Q>(&self, name: &Q) -> bool
where
Q: Hash + Eq + ?Sized,
Cow<'static, str>: Borrow<Q>,
{
self.actor_refs.contains_key(name)
}
/// Inserts a new actor ref under a given name, which can be used later to be looked up.
pub fn insert<A: Actor>(
&mut self,
name: impl Into<Cow<'static, str>>,
actor_ref: ActorRef<A>,
) -> bool {
let name = name.into();
if self.actor_refs.contains_key(&name) {
return false;
}
self.actor_refs
.insert(name, RegisteredActorRef::new(actor_ref));
true
}
/// Removes a previously registered actor ref under a given name.
pub fn remove<Q>(&mut self, name: &Q) -> bool
where
Q: Hash + Eq + ?Sized,
Cow<'static, str>: Borrow<Q>,
{
self.actor_refs.remove(name).is_some()
}
/// Removes a previously registered actor ref by `ActorId`.
pub fn remove_by_id(&mut self, id: &ActorId) -> bool {
self.actor_refs
.extract_if(|_, entry| &entry.id == id)
.next()
.is_some()
}
}
/// A locally registered actor ref.
#[derive(Debug)]
pub struct RegisteredActorRef {
id: ActorId,
actor_ref: Box<dyn Any + Send>,
}
impl RegisteredActorRef {
/// Creates a new `RegisteredActorRef` from an `ActorRef`.
pub fn new<A: Actor>(actor_ref: ActorRef<A>) -> Self {
RegisteredActorRef {
id: actor_ref.id(),
actor_ref: Box::new(actor_ref),
}
}
/// Returns the actor's id.
pub fn id(&self) -> ActorId {
self.id
}
/// Returns the `ActorRef`, or `None` if the provided `A` generic doesn't match the registered entry.
pub fn actor_ref<A: Actor>(&self) -> Option<&ActorRef<A>> {
self.actor_ref.downcast_ref()
}
}