1use mesh_derive::Protobuf;
5use std::fmt;
6use std::fmt::Debug;
7use std::fmt::Display;
8use std::str::FromStr;
9
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Protobuf)]
12pub struct Uuid(pub [u8; 16]);
13
14impl Uuid {
15 fn new() -> Self {
16 let mut id = Self([0; 16]);
19 getrandom::fill(&mut id.0[..]).expect("rng failure");
20 id
21 }
22}
23
24impl Display for Uuid {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "{:x}", u128::from_be_bytes(self.0))
27 }
28}
29
30impl Debug for Uuid {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 Display::fmt(self, f)
33 }
34}
35
36#[derive(Debug)]
37pub struct ParseUuidError;
38
39impl FromStr for Uuid {
40 type Err = ParseUuidError;
41
42 fn from_str(s: &str) -> Result<Self, Self::Err> {
43 if s.is_empty() || s.as_bytes()[0] == b'+' {
44 return Err(ParseUuidError);
45 }
46 u128::from_str_radix(s, 16)
47 .map(|n| Self(n.to_be_bytes()))
48 .map_err(|_| ParseUuidError)
49 }
50}
51
52#[cfg(debug_assertions)]
53mod debug {
54 use super::Uuid;
60 use std::sync::Once;
61 use std::sync::atomic::AtomicBool;
62 use std::sync::atomic::AtomicU64;
63 use std::sync::atomic::Ordering;
64
65 static CHECK_ONCE: Once = Once::new();
66 static USE_LINEAR_IDS: AtomicBool = AtomicBool::new(false);
67
68 pub struct DebugUuidSource(AtomicU64);
69
70 impl DebugUuidSource {
71 pub const fn new() -> Self {
72 Self(AtomicU64::new(1))
73 }
74
75 pub fn next(&self) -> Option<Uuid> {
76 CHECK_ONCE.call_once(|| {
77 if std::env::var_os("__MESH_UNSAFE_DEBUG_IDS__").is_some_and(|x| !x.is_empty()) {
78 tracing::error!("using unsafe debugging mesh IDs--this mesh could be compromised by external callers");
79 USE_LINEAR_IDS.store(true, Ordering::Relaxed);
80 }
81 });
82
83 if !USE_LINEAR_IDS.load(Ordering::Relaxed) {
84 return None;
85 }
86
87 Some(Uuid(
88 u128::from(self.0.fetch_add(1, Ordering::Relaxed)).to_be_bytes(),
89 ))
90 }
91 }
92}
93
94#[derive(Copy, Clone, PartialEq, Eq, Hash, Protobuf)]
96pub struct NodeId(pub Uuid);
97
98impl NodeId {
99 pub const ZERO: Self = Self(Uuid([0; 16]));
100
101 pub fn new() -> Self {
102 #[cfg(debug_assertions)]
103 {
104 static SOURCE: debug::DebugUuidSource = debug::DebugUuidSource::new();
105 if let Some(id) = SOURCE.next() {
106 return Self(id);
107 }
108 }
109 Self(Uuid::new())
110 }
111}
112
113impl Debug for NodeId {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(f, "N-{:?}", &self.0)
116 }
117}
118
119#[derive(Copy, Clone, PartialEq, Eq, Hash, Protobuf)]
121pub struct PortId(pub Uuid);
122
123impl PortId {
124 pub fn new() -> Self {
125 #[cfg(debug_assertions)]
126 {
127 static SOURCE: debug::DebugUuidSource = debug::DebugUuidSource::new();
128 if let Some(id) = SOURCE.next() {
129 return Self(id);
130 }
131 }
132 Self(Uuid::new())
133 }
134}
135
136impl Debug for PortId {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 write!(f, "P-{:?}", &self.0)
139 }
140}
141
142#[derive(Copy, Clone, PartialEq, Eq, Protobuf)]
144pub struct Address {
145 pub node: NodeId,
146 pub port: PortId,
147}
148
149impl Address {
150 pub fn new(node: NodeId, port: PortId) -> Self {
151 Self { node, port }
152 }
153}
154
155impl Debug for Address {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(f, "{:?}.{:?}", &self.node, &self.port)
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::Uuid;
164
165 #[test]
166 fn test_uuid() {
167 Uuid::new();
168 }
169}