Skip to main content

atomr_core/actor/
address.rs

1//! An `Address` locates an actor system on the network.
2//! akka.net: `Actor/Address.cs`.
3
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct Address {
10    pub protocol: String,
11    pub system: String,
12    pub host: Option<String>,
13    pub port: Option<u16>,
14}
15
16impl Address {
17    pub fn local(system: impl Into<String>) -> Self {
18        Self { protocol: "akka".into(), system: system.into(), host: None, port: None }
19    }
20
21    pub fn remote(
22        protocol: impl Into<String>,
23        system: impl Into<String>,
24        host: impl Into<String>,
25        port: u16,
26    ) -> Self {
27        Self { protocol: protocol.into(), system: system.into(), host: Some(host.into()), port: Some(port) }
28    }
29
30    pub fn has_local_scope(&self) -> bool {
31        self.host.is_none()
32    }
33
34    pub fn has_global_scope(&self) -> bool {
35        self.host.is_some()
36    }
37
38    /// Parses strings like `akka://sys` or `akka.tcp://sys@host:1234`.
39    pub fn parse(s: &str) -> Option<Self> {
40        let (protocol, rest) = s.split_once("://")?;
41        if let Some((sys, host_port)) = rest.split_once('@') {
42            let (host, port) = host_port.split_once(':')?;
43            Some(Self::remote(protocol, sys, host, port.parse().ok()?))
44        } else {
45            Some(Self::local(rest).with_protocol(protocol))
46        }
47    }
48
49    fn with_protocol(mut self, p: impl Into<String>) -> Self {
50        self.protocol = p.into();
51        self
52    }
53}
54
55impl fmt::Display for Address {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        match (&self.host, self.port) {
58            (Some(h), Some(p)) => write!(f, "{}://{}@{}:{}", self.protocol, self.system, h, p),
59            _ => write!(f, "{}://{}", self.protocol, self.system),
60        }
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn local_has_no_host() {
70        let a = Address::local("Sys");
71        assert!(a.has_local_scope());
72        assert_eq!(a.to_string(), "akka://Sys");
73    }
74
75    #[test]
76    fn remote_roundtrips() {
77        let a = Address::remote("akka.tcp", "Sys", "host", 1234);
78        assert!(a.has_global_scope());
79        assert_eq!(Address::parse(&a.to_string()).unwrap(), a);
80    }
81
82    #[test]
83    fn parses_local_form() {
84        assert_eq!(Address::parse("akka://Sys").unwrap(), Address::local("Sys"));
85    }
86}