1#![cfg_attr(not(feature = "std"), no_std)]
4
5extern crate alloc;
6
7use alloc::string::String;
8use core::{fmt::Display, ops::Deref};
9use zenoh::{key_expr::KeyExpr, session::ZenohId};
10
11use crate::qos::QosProfile;
12
13pub const EMPTY_PLACEHOLDER: &str = "%";
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub struct LivelinessKE(pub KeyExpr<'static>);
19
20impl LivelinessKE {
21 pub fn new(ke: KeyExpr<'static>) -> Self {
22 Self(ke)
23 }
24}
25
26impl Deref for LivelinessKE {
27 type Target = KeyExpr<'static>;
28 fn deref(&self) -> &Self::Target {
29 &self.0
30 }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35pub struct TopicKE(KeyExpr<'static>);
36
37impl TopicKE {
38 pub fn new(ke: KeyExpr<'static>) -> Self {
39 Self(ke)
40 }
41}
42
43impl Deref for TopicKE {
44 type Target = KeyExpr<'static>;
45 fn deref(&self) -> &Self::Target {
46 &self.0
47 }
48}
49
50impl Display for TopicKE {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 write!(f, "{}", self.0)
53 }
54}
55
56#[derive(Debug, Hash, Clone, PartialEq, Eq)]
58pub struct NodeEntity {
59 pub domain_id: usize,
60 pub z_id: ZenohId,
61 pub id: usize,
62 pub name: String,
63 pub namespace: String,
64 pub enclave: String,
65}
66
67impl NodeEntity {
68 pub fn new(
69 domain_id: usize,
70 z_id: ZenohId,
71 id: usize,
72 name: String,
73 namespace: String,
74 enclave: String,
75 ) -> Self {
76 Self {
77 domain_id,
78 z_id,
79 id,
80 name,
81 namespace,
82 enclave,
83 }
84 }
85}
86
87#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
89pub enum EndpointKind {
90 Publisher,
91 Subscription,
92 Service,
93 Client,
94}
95
96impl Display for EndpointKind {
97 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98 match self {
99 EndpointKind::Publisher => write!(f, "MP"),
100 EndpointKind::Subscription => write!(f, "MS"),
101 EndpointKind::Service => write!(f, "SS"),
102 EndpointKind::Client => write!(f, "SC"),
103 }
104 }
105}
106
107impl core::str::FromStr for EndpointKind {
108 type Err = &'static str;
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 match s {
112 "MP" => Ok(EndpointKind::Publisher),
113 "MS" => Ok(EndpointKind::Subscription),
114 "SS" => Ok(EndpointKind::Service),
115 "SC" => Ok(EndpointKind::Client),
116 _ => Err("Invalid endpoint kind"),
117 }
118 }
119}
120
121#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
123pub enum EntityKind {
124 Node,
125 Endpoint(EndpointKind),
126}
127
128impl Display for EntityKind {
129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130 match self {
131 EntityKind::Node => write!(f, "NN"),
132 EntityKind::Endpoint(k) => k.fmt(f),
133 }
134 }
135}
136
137impl core::str::FromStr for EntityKind {
138 type Err = &'static str;
139
140 fn from_str(s: &str) -> Result<Self, Self::Err> {
141 match s {
142 "NN" => Ok(EntityKind::Node),
143 _ => Ok(EntityKind::Endpoint(s.parse()?)),
144 }
145 }
146}
147
148impl From<EndpointKind> for EntityKind {
149 fn from(kind: EndpointKind) -> Self {
150 EntityKind::Endpoint(kind)
151 }
152}
153
154impl TryFrom<EntityKind> for EndpointKind {
155 type Error = &'static str;
156
157 fn try_from(kind: EntityKind) -> Result<Self, Self::Error> {
158 match kind {
159 EntityKind::Endpoint(k) => Ok(k),
160 EntityKind::Node => Err("Node is not a valid endpoint kind"),
161 }
162 }
163}
164
165#[derive(Debug, Hash, PartialEq, Eq, Clone)]
167pub struct TypeHash {
168 pub version: u8,
169 pub value: [u8; 32],
170}
171
172impl TypeHash {
173 const TYPE_HASH_NOT_SUPPORTED: &'static str = "TypeHashNotSupported";
175
176 pub const fn new(version: u8, value: [u8; 32]) -> Self {
177 Self { version, value }
178 }
179
180 pub const fn zero() -> Self {
181 Self {
182 version: 1,
183 value: [0u8; 32],
184 }
185 }
186
187 pub fn from_rihs_string(rihs_str: &str) -> Option<Self> {
188 if rihs_str == Self::TYPE_HASH_NOT_SUPPORTED {
190 return Some(TypeHash::zero());
191 }
192
193 if let Some(hex_part) = rihs_str.strip_prefix("RIHS01_") {
194 if hex_part.len() == 64 {
195 let mut hash_bytes = [0u8; 32];
196 for (i, chunk) in hex_part.as_bytes().chunks(2).enumerate() {
197 if i < 32 {
198 if let Ok(byte_val) =
199 u8::from_str_radix(core::str::from_utf8(chunk).unwrap_or("00"), 16)
200 {
201 hash_bytes[i] = byte_val;
202 } else {
203 return None;
204 }
205 }
206 }
207 return Some(TypeHash {
208 version: 1,
209 value: hash_bytes,
210 });
211 }
212 }
213 None
214 }
215
216 pub fn is_supported() -> bool {
218 cfg!(not(feature = "no-type-hash"))
219 }
220
221 pub fn to_rihs_string(&self) -> String {
222 #[cfg(feature = "no-type-hash")]
223 {
224 Self::TYPE_HASH_NOT_SUPPORTED.to_string()
226 }
227
228 #[cfg(not(feature = "no-type-hash"))]
229 {
230 use alloc::format;
231 match self.version {
232 1 => {
233 let hex_str: String = self.value.iter().map(|b| format!("{:02x}", b)).collect();
234 format!("RIHS01_{}", hex_str)
235 }
236 _ => format!(
237 "RIHS{:02x}_{}",
238 self.version,
239 self.value
240 .iter()
241 .map(|b| format!("{:02x}", b))
242 .collect::<String>()
243 ),
244 }
245 }
246 }
247}
248
249impl Display for TypeHash {
250 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251 write!(f, "{}", self.to_rihs_string())
252 }
253}
254
255#[derive(Debug, Hash, PartialEq, Eq, Clone)]
257pub struct TypeInfo {
258 pub name: String,
259 pub hash: TypeHash,
260}
261
262impl TypeInfo {
263 pub fn new(name: &str, hash: TypeHash) -> Self {
264 TypeInfo {
265 name: name.to_string(),
266 hash,
267 }
268 }
269}
270
271#[derive(Debug, Hash, PartialEq, Eq, Clone)]
273pub struct EndpointEntity {
274 pub id: usize,
275 pub node: Option<NodeEntity>,
276 pub kind: EndpointKind,
277 pub topic: String,
278 pub type_info: Option<TypeInfo>,
279 pub qos: QosProfile,
280}
281
282impl EndpointEntity {
283 pub fn entity_kind(&self) -> EntityKind {
284 self.kind.into()
285 }
286}
287
288#[derive(Debug, Clone, PartialEq, Eq)]
290pub enum Entity {
291 Node(NodeEntity),
292 Endpoint(EndpointEntity),
293}
294
295#[derive(Debug, Clone, Copy, PartialEq, Eq)]
297pub enum EntityConversionError {
298 MissingAdminSpace,
299 MissingDomainId,
300 MissingZId,
301 MissingNodeId,
302 MissingEntityId,
303 MissingEntityKind,
304 MissingEnclave,
305 MissingNamespace,
306 MissingNodeName,
307 MissingTopicName,
308 MissingTopicType,
309 MissingTopicHash,
310 MissingTopicQoS,
311 ParsingError,
312 QosDecodeError(crate::qos::QosDecodeError),
313}
314
315impl Display for EntityConversionError {
316 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
317 write!(f, "{:?}", self)
318 }
319}
320
321#[cfg(feature = "std")]
322impl std::error::Error for EntityConversionError {}