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
//! Addresses as numbers. An address is its name's atom (`yog_data::Atom`):
//! the same number in every binary of the process — the runtime, each mod,
//! the host's Java. A message type keeps its own once it's resolved, so a
//! call after the first passes a number, no string looked up.
use yog_sync::atomic::{AtomicU32, Ordering};
/// An address: its name's atom number.
pub type Address = u32;
/// No address: what an empty name resolves to (`yog_abi::NO_ADDRESS`).
pub const NO_ADDRESS: Address = u32::MAX;
/// `name`'s address.
pub fn resolve(name: &str) -> Address {
if name.is_empty() {
NO_ADDRESS
} else {
yog_data::Atom::new(name).number()
}
}
/// A message type's address, resolved the first time it's asked for.
pub struct Cached(AtomicU32);
impl Cached {
/// Not resolved yet ([`NO_ADDRESS`] is never cached: it costs nothing to resolve).
const UNSET: u32 = NO_ADDRESS;
pub const fn new() -> Self {
Cached(AtomicU32::new(Self::UNSET))
}
/// `name`'s address (always the same name for this cache).
pub fn get(&self, name: &str) -> Address {
let n = self.0.load(Ordering::Relaxed);
if n != Self::UNSET {
return n;
}
let n = resolve(name);
self.0.store(n, Ordering::Relaxed);
n
}
}
impl Default for Cached {
fn default() -> Self {
Self::new()
}
}
/// Where a message goes: its own address (cached), or for a key its
/// branch's, resolved each time.
pub(crate) fn of(cached: &Cached, address: &'static str, key: Option<&str>) -> Address {
match key {
None => cached.get(address),
Some(key) => resolve(&crate::keyed(address, key)),
}
}