1use serde::{Deserialize, Serialize};
13use starlang_atom::Atom;
14use std::fmt;
15use std::net::SocketAddr;
16use std::sync::OnceLock;
17
18pub const LOCAL_NODE_ID: u32 = 0;
20
21static LOCAL_NODE_ATOM: OnceLock<Atom> = OnceLock::new();
24
25static THIS_NODE: OnceLock<NodeIdentity> = OnceLock::new();
27
28fn local_node_atom() -> Atom {
30 *LOCAL_NODE_ATOM.get_or_init(|| Atom::new(""))
31}
32
33#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
51pub struct NodeId(u32);
52
53impl NodeId {
54 #[inline]
56 pub const fn new(id: u32) -> Self {
57 Self(id)
58 }
59
60 #[inline]
62 pub const fn local() -> Self {
63 Self(LOCAL_NODE_ID)
64 }
65
66 #[inline]
68 pub const fn as_u32(&self) -> u32 {
69 self.0
70 }
71
72 #[inline]
74 pub const fn is_local(&self) -> bool {
75 self.0 == LOCAL_NODE_ID
76 }
77}
78
79impl From<u32> for NodeId {
80 fn from(id: u32) -> Self {
81 Self(id)
82 }
83}
84
85impl From<NodeId> for u32 {
86 fn from(id: NodeId) -> Self {
87 id.0
88 }
89}
90
91impl fmt::Debug for NodeId {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "NodeId({})", self.0)
94 }
95}
96
97impl fmt::Display for NodeId {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 write!(f, "{}", self.0)
100 }
101}
102
103#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
118pub struct NodeName(String);
119
120impl NodeName {
121 pub fn new(name: impl Into<String>) -> Self {
125 Self(name.into())
126 }
127
128 pub fn as_str(&self) -> &str {
130 &self.0
131 }
132
133 pub fn short_name(&self) -> &str {
137 self.0.split('@').next().unwrap_or(&self.0)
138 }
139
140 pub fn host(&self) -> &str {
144 self.0.split('@').nth(1).unwrap_or("")
145 }
146}
147
148impl fmt::Debug for NodeName {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 write!(f, "NodeName({:?})", self.0)
151 }
152}
153
154impl fmt::Display for NodeName {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 write!(f, "{}", self.0)
157 }
158}
159
160impl From<&str> for NodeName {
161 fn from(s: &str) -> Self {
162 Self::new(s)
163 }
164}
165
166impl From<String> for NodeName {
167 fn from(s: String) -> Self {
168 Self::new(s)
169 }
170}
171
172#[derive(Clone, Debug, Serialize, Deserialize)]
177pub struct NodeInfo {
178 pub name: NodeName,
180 pub id: NodeId,
182 pub addr: Option<SocketAddr>,
184 pub creation: u32,
186}
187
188impl NodeInfo {
189 pub fn new(
191 name: impl Into<NodeName>,
192 id: NodeId,
193 addr: Option<SocketAddr>,
194 creation: u32,
195 ) -> Self {
196 Self {
197 name: name.into(),
198 id,
199 addr,
200 creation,
201 }
202 }
203}
204
205#[derive(Clone, Debug)]
209pub struct NodeIdentity {
210 pub name: NodeName,
212 pub name_atom: Atom,
214 pub creation: u32,
216}
217
218pub fn init_node(name: NodeName, creation: u32) -> Result<(), NodeIdentity> {
231 let name_atom = Atom::new(name.as_str());
232 THIS_NODE.set(NodeIdentity {
233 name,
234 name_atom,
235 creation,
236 })
237}
238
239pub fn node_name() -> Option<&'static NodeName> {
243 THIS_NODE.get().map(|n| &n.name)
244}
245
246pub fn node_name_atom() -> Atom {
251 THIS_NODE
252 .get()
253 .map(|n| n.name_atom)
254 .unwrap_or_else(local_node_atom)
255}
256
257pub fn node_creation() -> u32 {
261 THIS_NODE.get().map(|n| n.creation).unwrap_or(0)
262}
263
264pub fn is_distributed() -> bool {
266 THIS_NODE.get().is_some()
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_node_id_local() {
275 let local = NodeId::local();
276 assert!(local.is_local());
277 assert_eq!(local.as_u32(), 0);
278 }
279
280 #[test]
281 fn test_node_id_remote() {
282 let remote = NodeId::new(5);
283 assert!(!remote.is_local());
284 assert_eq!(remote.as_u32(), 5);
285 }
286
287 #[test]
288 fn test_node_name_parsing() {
289 let name = NodeName::new("mynode@example.com");
290 assert_eq!(name.short_name(), "mynode");
291 assert_eq!(name.host(), "example.com");
292 }
293
294 #[test]
295 fn test_node_name_no_at() {
296 let name = NodeName::new("standalone");
297 assert_eq!(name.short_name(), "standalone");
298 assert_eq!(name.host(), "");
299 }
300
301 #[test]
302 fn test_node_id_serialization() {
303 let id = NodeId::new(42);
304 let bytes = postcard::to_allocvec(&id).unwrap();
305 let decoded: NodeId = postcard::from_bytes(&bytes).unwrap();
306 assert_eq!(id, decoded);
307 }
308}