1use alloc::string::String;
15use core::{convert::TryFrom, fmt, num::NonZeroU8, ops::BitOr, str::FromStr};
16
17use const_format::formatcp;
18use serde::ser::SerializeSeq;
19use zenoh_result::{bail, ZError};
20
21#[repr(u8)]
39#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
40pub enum WhatAmI {
41 Router = 0b001,
42 #[default]
43 Peer = 0b010,
44 Client = 0b100,
45}
46
47impl WhatAmI {
48 const STR_R: &'static str = "router";
49 const STR_P: &'static str = "peer";
50 const STR_C: &'static str = "client";
51
52 const U8_R: u8 = Self::Router as u8;
53 const U8_P: u8 = Self::Peer as u8;
54 const U8_C: u8 = Self::Client as u8;
55
56 pub const fn to_str(self) -> &'static str {
57 match self {
58 Self::Router => Self::STR_R,
59 Self::Peer => Self::STR_P,
60 Self::Client => Self::STR_C,
61 }
62 }
63
64 #[cfg(feature = "test")]
65 #[doc(hidden)]
66 pub fn rand() -> Self {
67 use rand::prelude::SliceRandom;
68 let mut rng = rand::thread_rng();
69
70 *[Self::Router, Self::Peer, Self::Client]
71 .choose(&mut rng)
72 .unwrap()
73 }
74
75 pub const fn is_client(self) -> bool {
76 matches!(self, WhatAmI::Client)
77 }
78
79 pub const fn is_peer(self) -> bool {
80 matches!(self, WhatAmI::Peer)
81 }
82
83 pub const fn is_router(self) -> bool {
84 matches!(self, WhatAmI::Router)
85 }
86}
87
88impl TryFrom<u8> for WhatAmI {
89 type Error = ();
90
91 fn try_from(v: u8) -> Result<Self, Self::Error> {
92 match v {
93 Self::U8_R => Ok(Self::Router),
94 Self::U8_P => Ok(Self::Peer),
95 Self::U8_C => Ok(Self::Client),
96 _ => Err(()),
97 }
98 }
99}
100
101impl FromStr for WhatAmI {
102 type Err = ZError;
103
104 fn from_str(s: &str) -> Result<Self, Self::Err> {
105 match s {
106 Self::STR_R => Ok(Self::Router),
107 Self::STR_P => Ok(Self::Peer),
108 Self::STR_C => Ok(Self::Client),
109 _ => bail!(
110 "{s} is not a valid WhatAmI value. Valid values are: {}, {}, {}.",
111 Self::STR_R,
112 Self::STR_P,
113 Self::STR_C
114 ),
115 }
116 }
117}
118
119impl fmt::Display for WhatAmI {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.write_str(self.to_str())
122 }
123}
124
125impl From<WhatAmI> for u8 {
126 fn from(w: WhatAmI) -> Self {
127 w as u8
128 }
129}
130
131#[repr(transparent)]
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
138pub struct WhatAmIMatcher(NonZeroU8);
139
140impl WhatAmIMatcher {
141 const U8_0: u8 = 1 << 7;
143 const U8_R: u8 = Self::U8_0 | WhatAmI::U8_R;
144 const U8_P: u8 = Self::U8_0 | WhatAmI::U8_P;
145 const U8_C: u8 = Self::U8_0 | WhatAmI::U8_C;
146 const U8_R_P: u8 = Self::U8_0 | WhatAmI::U8_R | WhatAmI::U8_P;
147 const U8_P_C: u8 = Self::U8_0 | WhatAmI::U8_P | WhatAmI::U8_C;
148 const U8_R_C: u8 = Self::U8_0 | WhatAmI::U8_R | WhatAmI::U8_C;
149 const U8_R_P_C: u8 = Self::U8_0 | WhatAmI::U8_R | WhatAmI::U8_P | WhatAmI::U8_C;
150
151 pub const fn empty() -> Self {
153 Self(unsafe { NonZeroU8::new_unchecked(Self::U8_0) })
154 }
155
156 pub const fn router(self) -> Self {
158 Self(unsafe { NonZeroU8::new_unchecked(self.0.get() | Self::U8_R) })
159 }
160
161 pub const fn peer(self) -> Self {
163 Self(unsafe { NonZeroU8::new_unchecked(self.0.get() | Self::U8_P) })
164 }
165
166 pub const fn client(self) -> Self {
168 Self(unsafe { NonZeroU8::new_unchecked(self.0.get() | Self::U8_C) })
169 }
170
171 pub const fn is_empty(&self) -> bool {
173 self.0.get() == Self::U8_0
174 }
175
176 pub const fn matches(&self, w: WhatAmI) -> bool {
178 (self.0.get() & w as u8) != 0
179 }
180
181 pub const fn to_str(self) -> &'static str {
184 match self.0.get() {
185 Self::U8_0 => "",
186 Self::U8_R => WhatAmI::STR_R,
187 Self::U8_P => WhatAmI::STR_P,
188 Self::U8_C => WhatAmI::STR_C,
189 Self::U8_R_P => formatcp!("{}|{}", WhatAmI::STR_R, WhatAmI::STR_P),
190 Self::U8_R_C => formatcp!("{}|{}", WhatAmI::STR_R, WhatAmI::STR_C),
191 Self::U8_P_C => formatcp!("{}|{}", WhatAmI::STR_P, WhatAmI::STR_C),
192 Self::U8_R_P_C => formatcp!("{}|{}|{}", WhatAmI::STR_R, WhatAmI::STR_P, WhatAmI::STR_C),
193
194 _ => unreachable!(),
195 }
196 }
197
198 #[cfg(feature = "test")]
199 #[doc(hidden)]
200 pub fn rand() -> Self {
201 use rand::Rng;
202
203 let mut rng = rand::thread_rng();
204 let mut waim = WhatAmIMatcher::empty();
205 if rng.gen_bool(0.5) {
206 waim = waim.router();
207 }
208 if rng.gen_bool(0.5) {
209 waim = waim.peer();
210 }
211 if rng.gen_bool(0.5) {
212 waim = waim.client();
213 }
214 waim
215 }
216}
217
218impl TryFrom<u8> for WhatAmIMatcher {
219 type Error = ();
220
221 fn try_from(v: u8) -> Result<Self, Self::Error> {
222 const MIN: u8 = 0;
223 const MAX: u8 = WhatAmI::U8_R | WhatAmI::U8_P | WhatAmI::U8_C;
224
225 if (MIN..=MAX).contains(&v) {
226 Ok(WhatAmIMatcher(unsafe {
227 NonZeroU8::new_unchecked(Self::U8_0 | v)
228 }))
229 } else {
230 Err(())
231 }
232 }
233}
234
235impl FromStr for WhatAmIMatcher {
236 type Err = ();
237
238 fn from_str(s: &str) -> Result<Self, Self::Err> {
239 let mut inner = 0;
240 for s in s.split('|') {
241 match s.trim() {
242 "" => {}
243 WhatAmI::STR_R => inner |= WhatAmI::U8_R,
244 WhatAmI::STR_P => inner |= WhatAmI::U8_P,
245 WhatAmI::STR_C => inner |= WhatAmI::U8_C,
246 _ => return Err(()),
247 }
248 }
249 Self::try_from(inner)
250 }
251}
252
253impl fmt::Display for WhatAmIMatcher {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 f.write_str(self.to_str())
256 }
257}
258
259impl From<WhatAmIMatcher> for u8 {
260 fn from(w: WhatAmIMatcher) -> u8 {
261 w.0.get()
262 }
263}
264
265impl<T> BitOr<T> for WhatAmIMatcher
266where
267 NonZeroU8: BitOr<T, Output = NonZeroU8>,
268{
269 type Output = Self;
270
271 fn bitor(self, rhs: T) -> Self::Output {
272 WhatAmIMatcher(self.0 | rhs)
273 }
274}
275
276impl BitOr<WhatAmI> for WhatAmIMatcher {
277 type Output = Self;
278
279 fn bitor(self, rhs: WhatAmI) -> Self::Output {
280 self | rhs as u8
281 }
282}
283
284impl BitOr for WhatAmIMatcher {
285 type Output = Self;
286
287 fn bitor(self, rhs: Self) -> Self::Output {
288 self | rhs.0
289 }
290}
291
292impl BitOr for WhatAmI {
293 type Output = WhatAmIMatcher;
294
295 fn bitor(self, rhs: Self) -> Self::Output {
296 WhatAmIMatcher(unsafe {
297 NonZeroU8::new_unchecked(self as u8 | rhs as u8 | WhatAmIMatcher::U8_0)
298 })
299 }
300}
301
302impl From<WhatAmI> for WhatAmIMatcher {
303 fn from(w: WhatAmI) -> Self {
304 WhatAmIMatcher(unsafe { NonZeroU8::new_unchecked(w as u8 | WhatAmIMatcher::U8_0) })
305 }
306}
307
308impl serde::Serialize for WhatAmI {
310 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
311 where
312 S: serde::Serializer,
313 {
314 serializer.serialize_str(self.to_str())
315 }
316}
317
318#[derive(Debug)]
319pub struct WhatAmIVisitor;
320
321impl<'de> serde::de::Visitor<'de> for WhatAmIVisitor {
322 type Value = WhatAmI;
323
324 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
325 write!(
326 formatter,
327 "either '{}', '{}' or '{}'",
328 WhatAmI::STR_R,
329 WhatAmI::STR_P,
330 WhatAmI::STR_C
331 )
332 }
333 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
334 where
335 E: serde::de::Error,
336 {
337 v.parse().map_err(|_| {
338 serde::de::Error::unknown_variant(v, &[WhatAmI::STR_R, WhatAmI::STR_P, WhatAmI::STR_C])
339 })
340 }
341 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
342 where
343 E: serde::de::Error,
344 {
345 self.visit_str(v)
346 }
347 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
348 where
349 E: serde::de::Error,
350 {
351 self.visit_str(&v)
352 }
353}
354
355impl<'de> serde::Deserialize<'de> for WhatAmI {
356 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
357 where
358 D: serde::Deserializer<'de>,
359 {
360 deserializer.deserialize_str(WhatAmIVisitor)
361 }
362}
363
364impl serde::Serialize for WhatAmIMatcher {
365 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
366 where
367 S: serde::Serializer,
368 {
369 let values = [WhatAmI::Router, WhatAmI::Peer, WhatAmI::Client]
370 .iter()
371 .filter(|v| self.matches(**v));
372 let mut seq = serializer.serialize_seq(Some(values.clone().count()))?;
373 for v in values {
374 seq.serialize_element(v)?;
375 }
376 seq.end()
377 }
378}
379
380#[derive(Debug)]
381pub struct WhatAmIMatcherVisitor;
382impl<'de> serde::de::Visitor<'de> for WhatAmIMatcherVisitor {
383 type Value = WhatAmIMatcher;
384 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
385 write!(
386 formatter,
387 "a list of whatami variants ('{}', '{}', '{}')",
388 WhatAmI::STR_R,
389 WhatAmI::STR_P,
390 WhatAmI::STR_C
391 )
392 }
393
394 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
395 where
396 A: serde::de::SeqAccess<'de>,
397 {
398 let mut inner = 0;
399
400 while let Some(s) = seq.next_element::<String>()? {
401 match s.as_str() {
402 WhatAmI::STR_R => inner |= WhatAmI::U8_R,
403 WhatAmI::STR_P => inner |= WhatAmI::U8_P,
404 WhatAmI::STR_C => inner |= WhatAmI::U8_C,
405 _ => {
406 return Err(serde::de::Error::invalid_value(
407 serde::de::Unexpected::Str(&s),
408 &formatcp!(
409 "one of ('{}', '{}', '{}')",
410 WhatAmI::STR_R,
411 WhatAmI::STR_P,
412 WhatAmI::STR_C
413 ),
414 ))
415 }
416 }
417 }
418
419 Ok(WhatAmIMatcher::try_from(inner)
420 .expect("`WhatAmIMatcher` should be valid by construction"))
421 }
422}
423
424impl<'de> serde::Deserialize<'de> for WhatAmIMatcher {
425 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
426 where
427 D: serde::Deserializer<'de>,
428 {
429 deserializer.deserialize_seq(WhatAmIMatcherVisitor)
430 }
431}