1use alloc::{
16 boxed::Box,
17 format,
18 string::{String, ToString},
19};
20use core::{
21 convert::{From, TryFrom, TryInto},
22 fmt::{self, Display},
23 hash::Hash,
24 ops::{Deref, RangeInclusive},
25 str::FromStr,
26};
27
28use serde::{Deserialize, Serialize};
29pub use uhlc::{Timestamp, NTP64};
30use zenoh_keyexpr::OwnedKeyExpr;
31use zenoh_result::{bail, zerror};
32
33pub type TimestampId = uhlc::ID;
35
36pub mod whatami;
38pub use whatami::*;
39pub use zenoh_keyexpr::key_expr;
40
41pub mod wire_expr;
42pub use wire_expr::*;
43
44mod cowstr;
45pub use cowstr::CowStr;
46pub mod encoding;
47pub use encoding::{Encoding, EncodingId};
48
49pub mod locator;
50pub use locator::*;
51
52pub mod endpoint;
53pub use endpoint::*;
54
55pub mod resolution;
56pub use resolution::*;
57
58pub mod parameters;
59pub use parameters::Parameters;
60
61#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
63#[repr(transparent)]
64pub struct ZenohIdProto(uhlc::ID);
65
66impl ZenohIdProto {
67 pub const MAX_SIZE: usize = 16;
68
69 #[inline]
70 pub fn size(&self) -> usize {
71 self.0.size()
72 }
73
74 #[inline]
75 pub fn to_le_bytes(&self) -> [u8; uhlc::ID::MAX_SIZE] {
76 self.0.to_le_bytes()
77 }
78
79 pub fn rand() -> ZenohIdProto {
80 ZenohIdProto(uhlc::ID::rand())
81 }
82
83 pub fn into_keyexpr(self) -> OwnedKeyExpr {
84 self.into()
85 }
86}
87
88impl Default for ZenohIdProto {
89 fn default() -> Self {
90 Self::rand()
91 }
92}
93
94#[derive(Debug, Clone, Copy)]
96pub struct SizeError(usize);
97
98#[cfg(feature = "std")]
99impl std::error::Error for SizeError {}
100#[cfg(not(feature = "std"))]
101impl zenoh_result::IError for SizeError {}
102
103impl From<uhlc::SizeError> for SizeError {
104 fn from(val: uhlc::SizeError) -> Self {
105 Self(val.0)
106 }
107}
108
109impl fmt::Display for SizeError {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 write!(
113 f,
114 "Maximum ID size ({} bytes) exceeded: {}",
115 uhlc::ID::MAX_SIZE,
116 self.0
117 )
118 }
119}
120
121macro_rules! derive_tryfrom {
122 ($T: ty) => {
123 impl TryFrom<$T> for ZenohIdProto {
124 type Error = zenoh_result::Error;
125 fn try_from(val: $T) -> Result<Self, Self::Error> {
126 match val.try_into() {
127 Ok(ok) => Ok(Self(ok)),
128 Err(err) => Err(Box::<SizeError>::new(err.into())),
129 }
130 }
131 }
132 };
133}
134derive_tryfrom!([u8; 1]);
135derive_tryfrom!(&[u8; 1]);
136derive_tryfrom!([u8; 2]);
137derive_tryfrom!(&[u8; 2]);
138derive_tryfrom!([u8; 3]);
139derive_tryfrom!(&[u8; 3]);
140derive_tryfrom!([u8; 4]);
141derive_tryfrom!(&[u8; 4]);
142derive_tryfrom!([u8; 5]);
143derive_tryfrom!(&[u8; 5]);
144derive_tryfrom!([u8; 6]);
145derive_tryfrom!(&[u8; 6]);
146derive_tryfrom!([u8; 7]);
147derive_tryfrom!(&[u8; 7]);
148derive_tryfrom!([u8; 8]);
149derive_tryfrom!(&[u8; 8]);
150derive_tryfrom!([u8; 9]);
151derive_tryfrom!(&[u8; 9]);
152derive_tryfrom!([u8; 10]);
153derive_tryfrom!(&[u8; 10]);
154derive_tryfrom!([u8; 11]);
155derive_tryfrom!(&[u8; 11]);
156derive_tryfrom!([u8; 12]);
157derive_tryfrom!(&[u8; 12]);
158derive_tryfrom!([u8; 13]);
159derive_tryfrom!(&[u8; 13]);
160derive_tryfrom!([u8; 14]);
161derive_tryfrom!(&[u8; 14]);
162derive_tryfrom!([u8; 15]);
163derive_tryfrom!(&[u8; 15]);
164derive_tryfrom!([u8; 16]);
165derive_tryfrom!(&[u8; 16]);
166derive_tryfrom!(&[u8]);
167
168impl FromStr for ZenohIdProto {
169 type Err = zenoh_result::Error;
170
171 fn from_str(s: &str) -> Result<Self, Self::Err> {
172 if s.contains(|c: char| c.is_ascii_uppercase()) {
173 bail!(
174 "Invalid id: {} - uppercase hexadecimal is not accepted, use lowercase",
175 s
176 );
177 }
178 let u: uhlc::ID = s
179 .parse()
180 .map_err(|e: uhlc::ParseIDError| zerror!("Invalid id: {} - {}", s, e.cause))?;
181 Ok(ZenohIdProto(u))
182 }
183}
184
185impl fmt::Debug for ZenohIdProto {
186 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187 write!(f, "{}", self.0)
188 }
189}
190
191impl fmt::Display for ZenohIdProto {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 fmt::Debug::fmt(self, f)
194 }
195}
196
197impl From<&ZenohIdProto> for uhlc::ID {
199 fn from(zid: &ZenohIdProto) -> Self {
200 zid.0
201 }
202}
203
204impl From<ZenohIdProto> for uhlc::ID {
205 fn from(zid: ZenohIdProto) -> Self {
206 zid.0
207 }
208}
209
210impl From<ZenohIdProto> for OwnedKeyExpr {
211 fn from(zid: ZenohIdProto) -> Self {
212 unsafe { OwnedKeyExpr::from_string_unchecked(zid.to_string()) }
217 }
218}
219
220impl From<&ZenohIdProto> for OwnedKeyExpr {
221 fn from(zid: &ZenohIdProto) -> Self {
222 (*zid).into()
223 }
224}
225
226impl serde::Serialize for ZenohIdProto {
227 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
228 where
229 S: serde::Serializer,
230 {
231 serializer.serialize_str(self.to_string().as_str())
232 }
233}
234
235impl<'de> serde::Deserialize<'de> for ZenohIdProto {
236 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
237 where
238 D: serde::Deserializer<'de>,
239 {
240 struct ZenohIdVisitor;
241
242 impl<'de> serde::de::Visitor<'de> for ZenohIdVisitor {
243 type Value = ZenohIdProto;
244
245 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
246 formatter.write_str(&format!(
247 "An hex string of 1-{} bytes",
248 ZenohIdProto::MAX_SIZE
249 ))
250 }
251
252 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
253 where
254 E: serde::de::Error,
255 {
256 v.parse().map_err(serde::de::Error::custom)
257 }
258
259 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
260 where
261 E: serde::de::Error,
262 {
263 self.visit_str(v)
264 }
265
266 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
267 where
268 E: serde::de::Error,
269 {
270 self.visit_str(&v)
271 }
272 }
273
274 deserializer.deserialize_str(ZenohIdVisitor)
275 }
276}
277
278pub type EntityId = u32;
280
281#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
283pub struct EntityGlobalIdProto {
284 pub zid: ZenohIdProto,
285 pub eid: EntityId,
286}
287
288impl EntityGlobalIdProto {
289 #[cfg(feature = "test")]
290 pub fn rand() -> Self {
291 use rand::Rng;
292 Self {
293 zid: ZenohIdProto::rand(),
294 eid: rand::thread_rng().gen(),
295 }
296 }
297}
298
299#[repr(u8)]
300#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
301pub enum Priority {
302 Control = 0,
303 RealTime = 1,
304 InteractiveHigh = 2,
305 InteractiveLow = 3,
306 DataHigh = 4,
307 #[default]
308 Data = 5,
309 DataLow = 6,
310 Background = 7,
311}
312
313#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize)]
314pub struct PriorityRange(RangeInclusive<Priority>);
316
317impl Deref for PriorityRange {
318 type Target = RangeInclusive<Priority>;
319
320 fn deref(&self) -> &Self::Target {
321 &self.0
322 }
323}
324
325impl PriorityRange {
326 pub fn new(range: RangeInclusive<Priority>) -> Self {
327 Self(range)
328 }
329
330 pub fn includes(&self, other: &PriorityRange) -> bool {
332 self.start() <= other.start() && other.end() <= self.end()
333 }
334
335 pub fn len(&self) -> usize {
336 *self.end() as usize - *self.start() as usize + 1
337 }
338
339 pub fn is_empty(&self) -> bool {
340 false
341 }
342
343 #[cfg(feature = "test")]
344 pub fn rand() -> Self {
345 use rand::Rng;
346 let mut rng = rand::thread_rng();
347 let start = rng.gen_range(Priority::MAX as u8..Priority::MIN as u8);
348 let end = rng.gen_range((start + 1)..=Priority::MIN as u8);
349
350 Self(Priority::try_from(start).unwrap()..=Priority::try_from(end).unwrap())
351 }
352}
353
354impl Display for PriorityRange {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 write!(f, "{}-{}", *self.start() as u8, *self.end() as u8)
357 }
358}
359
360#[derive(Debug, PartialEq)]
361pub enum InvalidPriorityRange {
362 InvalidSyntax { found: String },
363 InvalidBound { message: String },
364}
365
366impl Display for InvalidPriorityRange {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 match self {
369 InvalidPriorityRange::InvalidSyntax { found } => write!(f, "invalid priority range string, expected an range of the form `start-end` but found {found}"),
370 InvalidPriorityRange::InvalidBound { message } => write!(f, "invalid priority range bound: {message}"),
371 }
372 }
373}
374
375#[cfg(feature = "std")]
376impl std::error::Error for InvalidPriorityRange {}
377
378impl FromStr for PriorityRange {
379 type Err = InvalidPriorityRange;
380
381 fn from_str(s: &str) -> Result<Self, Self::Err> {
382 const SEPARATOR: &str = "-";
383 let mut metadata = s.split(SEPARATOR);
384
385 let start = metadata
386 .next()
387 .ok_or_else(|| InvalidPriorityRange::InvalidSyntax {
388 found: s.to_string(),
389 })?
390 .parse::<u8>()
391 .map(Priority::try_from)
392 .map_err(|err| InvalidPriorityRange::InvalidBound {
393 message: err.to_string(),
394 })?
395 .map_err(|err| InvalidPriorityRange::InvalidBound {
396 message: err.to_string(),
397 })?;
398
399 match metadata.next() {
400 Some(slice) => {
401 let end = slice
402 .parse::<u8>()
403 .map(Priority::try_from)
404 .map_err(|err| InvalidPriorityRange::InvalidBound {
405 message: err.to_string(),
406 })?
407 .map_err(|err| InvalidPriorityRange::InvalidBound {
408 message: err.to_string(),
409 })?;
410
411 if metadata.next().is_some() {
412 return Err(InvalidPriorityRange::InvalidSyntax {
413 found: s.to_string(),
414 });
415 };
416
417 Ok(PriorityRange::new(start..=end))
418 }
419 None => Ok(PriorityRange::new(start..=start)),
420 }
421 }
422}
423
424impl Priority {
425 pub const DEFAULT: Self = Self::Data;
427 pub const MIN: Self = Self::Background;
429 pub const MAX: Self = Self::Control;
431 pub const NUM: usize = 1 + Self::MIN as usize - Self::MAX as usize;
433}
434
435impl TryFrom<u8> for Priority {
436 type Error = zenoh_result::Error;
437
438 fn try_from(v: u8) -> Result<Self, Self::Error> {
439 match v {
440 0 => Ok(Priority::Control),
441 1 => Ok(Priority::RealTime),
442 2 => Ok(Priority::InteractiveHigh),
443 3 => Ok(Priority::InteractiveLow),
444 4 => Ok(Priority::DataHigh),
445 5 => Ok(Priority::Data),
446 6 => Ok(Priority::DataLow),
447 7 => Ok(Priority::Background),
448 unknown => bail!(
449 "{} is not a valid priority value. Admitted values are: [{}-{}].",
450 unknown,
451 Self::MAX as u8,
452 Self::MIN as u8
453 ),
454 }
455 }
456}
457
458#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
459#[repr(u8)]
460pub enum Reliability {
461 BestEffort = 0,
462 #[default]
463 Reliable = 1,
464}
465
466impl Reliability {
467 pub const DEFAULT: Self = Self::Reliable;
468
469 #[cfg(feature = "test")]
470 pub fn rand() -> Self {
471 use rand::Rng;
472
473 let mut rng = rand::thread_rng();
474
475 if rng.gen_bool(0.5) {
476 Reliability::Reliable
477 } else {
478 Reliability::BestEffort
479 }
480 }
481}
482
483impl From<bool> for Reliability {
484 fn from(value: bool) -> Self {
485 if value {
486 Reliability::Reliable
487 } else {
488 Reliability::BestEffort
489 }
490 }
491}
492
493impl From<Reliability> for bool {
494 fn from(value: Reliability) -> Self {
495 match value {
496 Reliability::BestEffort => false,
497 Reliability::Reliable => true,
498 }
499 }
500}
501
502impl Display for Reliability {
503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504 write!(f, "{}", *self as u8)
505 }
506}
507
508#[derive(Debug)]
509pub struct InvalidReliability {
510 found: String,
511}
512
513impl Display for InvalidReliability {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515 write!(
516 f,
517 "invalid Reliability string, expected `{}` or `{}` but found {}",
518 Reliability::Reliable as u8,
519 Reliability::BestEffort as u8,
520 self.found
521 )
522 }
523}
524
525#[cfg(feature = "std")]
526impl std::error::Error for InvalidReliability {}
527
528impl FromStr for Reliability {
529 type Err = InvalidReliability;
530
531 fn from_str(s: &str) -> Result<Self, Self::Err> {
532 let Ok(desc) = s.parse::<u8>() else {
533 return Err(InvalidReliability {
534 found: s.to_string(),
535 });
536 };
537
538 if desc == Reliability::BestEffort as u8 {
539 Ok(Reliability::BestEffort)
540 } else if desc == Reliability::Reliable as u8 {
541 Ok(Reliability::Reliable)
542 } else {
543 Err(InvalidReliability {
544 found: s.to_string(),
545 })
546 }
547 }
548}
549
550#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
551pub struct Channel {
552 pub priority: Priority,
553 pub reliability: Reliability,
554}
555
556impl Channel {
557 pub const DEFAULT: Self = Self {
558 priority: Priority::DEFAULT,
559 reliability: Reliability::DEFAULT,
560 };
561}
562
563#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Deserialize)]
565#[repr(u8)]
566pub enum CongestionControl {
567 #[default]
568 Drop = 0,
570 Block = 1,
573 #[cfg(feature = "unstable")]
574 BlockFirst = 2,
578}
579
580impl CongestionControl {
581 pub const DEFAULT: Self = Self::Drop;
582
583 #[cfg(feature = "internal")]
584 pub const DEFAULT_PUSH: Self = Self::Drop;
585 #[cfg(not(feature = "internal"))]
586 pub(crate) const DEFAULT_PUSH: Self = Self::Drop;
587
588 #[cfg(feature = "internal")]
589 pub const DEFAULT_REQUEST: Self = Self::Block;
590 #[cfg(not(feature = "internal"))]
591 pub(crate) const DEFAULT_REQUEST: Self = Self::Block;
592
593 #[cfg(feature = "internal")]
594 pub const DEFAULT_RESPONSE: Self = Self::Block;
595 #[cfg(not(feature = "internal"))]
596 pub(crate) const DEFAULT_RESPONSE: Self = Self::Block;
597
598 #[cfg(feature = "internal")]
599 pub const DEFAULT_DECLARE: Self = Self::Block;
600 #[cfg(not(feature = "internal"))]
601 pub(crate) const DEFAULT_DECLARE: Self = Self::Block;
602
603 #[cfg(feature = "internal")]
604 pub const DEFAULT_OAM: Self = Self::Block;
605 #[cfg(not(feature = "internal"))]
606 pub(crate) const DEFAULT_OAM: Self = Self::Block;
607}
608
609#[cfg(test)]
610mod tests {
611 use core::str::FromStr;
612
613 use crate::core::{Priority, PriorityRange};
614
615 #[test]
616 fn test_priority_range() {
617 assert_eq!(
618 PriorityRange::from_str("2-3"),
619 Ok(PriorityRange::new(
620 Priority::InteractiveHigh..=Priority::InteractiveLow
621 ))
622 );
623
624 assert_eq!(
625 PriorityRange::from_str("7"),
626 Ok(PriorityRange::new(
627 Priority::Background..=Priority::Background
628 ))
629 );
630
631 assert!(PriorityRange::from_str("1-").is_err());
632 assert!(PriorityRange::from_str("-5").is_err());
633 }
634}