Skip to main content

zenoh_protocol/network/
mod.rs

1//
2// Copyright (c) 2022 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14pub mod declare;
15pub mod interest;
16pub mod oam;
17pub mod push;
18pub mod request;
19pub mod response;
20pub mod timestamp_stack;
21
22use core::fmt;
23
24pub use declare::{
25    Declare, DeclareBody, DeclareFinal, DeclareKeyExpr, DeclareQueryable, DeclareSubscriber,
26    DeclareToken, UndeclareKeyExpr, UndeclareQueryable, UndeclareSubscriber, UndeclareToken,
27};
28pub use interest::Interest;
29pub use oam::Oam;
30pub use push::Push;
31pub use request::{AtomicRequestId, Request, RequestId};
32pub use response::{Response, ResponseFinal};
33
34use crate::core::{CongestionControl, Priority, Reliability, WireExpr};
35#[cfg(feature = "shared-memory")]
36use crate::zenoh::{PushBody, RequestBody, ResponseBody};
37
38pub mod id {
39    // WARNING: it's crucial that these IDs do NOT collide with the IDs
40    //          defined in `crate::transport::id`.
41    pub const OAM: u8 = 0x1f;
42    pub const DECLARE: u8 = 0x1e;
43    pub const PUSH: u8 = 0x1d;
44    pub const REQUEST: u8 = 0x1c;
45    pub const RESPONSE: u8 = 0x1b;
46    pub const RESPONSE_FINAL: u8 = 0x1a;
47    pub const INTEREST: u8 = 0x19;
48}
49
50#[repr(u8)]
51#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
52pub enum Mapping {
53    #[default]
54    Receiver = 0,
55    Sender = 1,
56}
57
58impl Mapping {
59    pub const DEFAULT: Self = Self::Receiver;
60
61    #[cfg(feature = "test")]
62    #[doc(hidden)]
63    pub fn rand() -> Self {
64        use rand::Rng;
65
66        let mut rng = rand::thread_rng();
67        if rng.gen_bool(0.5) {
68            Mapping::Sender
69        } else {
70            Mapping::Receiver
71        }
72    }
73}
74
75// Zenoh messages at zenoh-network level
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum NetworkBody {
78    Push(Push),
79    Request(Request),
80    Response(Response),
81    ResponseFinal(ResponseFinal),
82    Interest(Interest),
83    Declare(Declare),
84    OAM(Oam),
85}
86
87#[derive(Debug, Copy, Clone, PartialEq, Eq)]
88pub enum NetworkBodyRef<'a> {
89    Push(&'a Push),
90    Request(&'a Request),
91    Response(&'a Response),
92    ResponseFinal(&'a ResponseFinal),
93    Interest(&'a Interest),
94    Declare(&'a Declare),
95    OAM(&'a Oam),
96}
97
98#[derive(Debug, PartialEq, Eq)]
99pub enum NetworkBodyMut<'a> {
100    Push(&'a mut Push),
101    Request(&'a mut Request),
102    Response(&'a mut Response),
103    ResponseFinal(&'a mut ResponseFinal),
104    Interest(&'a mut Interest),
105    Declare(&'a mut Declare),
106    OAM(&'a mut Oam),
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct NetworkMessage {
111    pub body: NetworkBody,
112    pub reliability: Reliability,
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq)]
116pub struct NetworkMessageRef<'a> {
117    pub body: NetworkBodyRef<'a>,
118    pub reliability: Reliability,
119}
120
121#[derive(Debug, PartialEq, Eq)]
122pub struct NetworkMessageMut<'a> {
123    pub body: NetworkBodyMut<'a>,
124    pub reliability: Reliability,
125}
126
127pub trait NetworkMessageExt {
128    #[doc(hidden)]
129    fn body(&self) -> NetworkBodyRef<'_>;
130
131    #[doc(hidden)]
132    fn reliability(&self) -> Reliability;
133
134    #[inline]
135    fn is_reliable(&self) -> bool {
136        self.reliability() == Reliability::Reliable
137    }
138
139    #[inline]
140    fn is_express(&self) -> bool {
141        match self.body() {
142            NetworkBodyRef::Push(msg) => msg.ext_qos.is_express(),
143            NetworkBodyRef::Request(msg) => msg.ext_qos.is_express(),
144            NetworkBodyRef::Response(msg) => msg.ext_qos.is_express(),
145            NetworkBodyRef::ResponseFinal(msg) => msg.ext_qos.is_express(),
146            NetworkBodyRef::Interest(msg) => msg.ext_qos.is_express(),
147            NetworkBodyRef::Declare(msg) => msg.ext_qos.is_express(),
148            NetworkBodyRef::OAM(msg) => msg.ext_qos.is_express(),
149        }
150    }
151
152    #[inline]
153    fn congestion_control(&self) -> CongestionControl {
154        match self.body() {
155            NetworkBodyRef::Push(msg) => msg.ext_qos.get_congestion_control(),
156            NetworkBodyRef::Request(msg) => msg.ext_qos.get_congestion_control(),
157            NetworkBodyRef::Response(msg) => msg.ext_qos.get_congestion_control(),
158            NetworkBodyRef::ResponseFinal(msg) => msg.ext_qos.get_congestion_control(),
159            NetworkBodyRef::Interest(msg) => msg.ext_qos.get_congestion_control(),
160            NetworkBodyRef::Declare(msg) => msg.ext_qos.get_congestion_control(),
161            NetworkBodyRef::OAM(msg) => msg.ext_qos.get_congestion_control(),
162        }
163    }
164
165    #[inline]
166    #[cfg(feature = "shared-memory")]
167    fn is_shm(&self) -> bool {
168        match self.body() {
169            NetworkBodyRef::Push(Push { payload, .. }) => match payload {
170                PushBody::Put(p) => p.ext_shm.is_some(),
171                PushBody::Del(_) => false,
172            },
173            NetworkBodyRef::Request(Request { payload, .. }) => match payload {
174                RequestBody::Query(b) => b.ext_body.as_ref().is_some_and(|b| b.ext_shm.is_some()),
175            },
176            NetworkBodyRef::Response(Response { payload, .. }) => match payload {
177                ResponseBody::Reply(b) => match &b.payload {
178                    PushBody::Put(p) => p.ext_shm.is_some(),
179                    PushBody::Del(_) => false,
180                },
181                ResponseBody::Err(e) => e.ext_shm.is_some(),
182            },
183            NetworkBodyRef::ResponseFinal(_)
184            | NetworkBodyRef::Interest(_)
185            | NetworkBodyRef::Declare(_)
186            | NetworkBodyRef::OAM(_) => false,
187        }
188    }
189
190    #[inline]
191    fn is_droppable(&self) -> bool {
192        !self.is_reliable() || self.congestion_control() == CongestionControl::Drop
193    }
194
195    #[inline]
196    fn priority(&self) -> Priority {
197        match self.body() {
198            NetworkBodyRef::Push(msg) => msg.ext_qos.get_priority(),
199            NetworkBodyRef::Request(msg) => msg.ext_qos.get_priority(),
200            NetworkBodyRef::Response(msg) => msg.ext_qos.get_priority(),
201            NetworkBodyRef::ResponseFinal(msg) => msg.ext_qos.get_priority(),
202            NetworkBodyRef::Interest(msg) => msg.ext_qos.get_priority(),
203            NetworkBodyRef::Declare(msg) => msg.ext_qos.get_priority(),
204            NetworkBodyRef::OAM(msg) => msg.ext_qos.get_priority(),
205        }
206    }
207
208    #[inline]
209    fn wire_expr(&self) -> Option<&WireExpr<'_>> {
210        match &self.body() {
211            NetworkBodyRef::Push(m) => Some(&m.wire_expr),
212            NetworkBodyRef::Request(m) => Some(&m.wire_expr),
213            NetworkBodyRef::Response(m) => Some(&m.wire_expr),
214            NetworkBodyRef::ResponseFinal(_) => None,
215            NetworkBodyRef::Interest(m) => m.wire_expr.as_ref(),
216            NetworkBodyRef::Declare(m) => match &m.body {
217                DeclareBody::DeclareKeyExpr(m) => Some(&m.wire_expr),
218                DeclareBody::UndeclareKeyExpr(_) => None,
219                DeclareBody::DeclareSubscriber(m) => Some(&m.wire_expr),
220                DeclareBody::UndeclareSubscriber(m) => Some(&m.ext_wire_expr.wire_expr),
221                DeclareBody::DeclareQueryable(m) => Some(&m.wire_expr),
222                DeclareBody::UndeclareQueryable(m) => Some(&m.ext_wire_expr.wire_expr),
223                DeclareBody::DeclareToken(m) => Some(&m.wire_expr),
224                DeclareBody::UndeclareToken(m) => Some(&m.ext_wire_expr.wire_expr),
225                DeclareBody::DeclareFinal(_) => None,
226            },
227            NetworkBodyRef::OAM(_) => None,
228        }
229    }
230
231    #[inline]
232    fn payload_size(&self) -> Option<usize> {
233        match &self.body() {
234            NetworkBodyRef::Push(p) => Some(p.payload_size()),
235            NetworkBodyRef::Request(r) => Some(r.payload_size()),
236            NetworkBodyRef::Response(r) => Some(r.payload_size()),
237            NetworkBodyRef::ResponseFinal(_)
238            | NetworkBodyRef::Interest(_)
239            | NetworkBodyRef::Declare(_)
240            | NetworkBodyRef::OAM(_) => None,
241        }
242    }
243
244    #[inline]
245    fn as_ref(&self) -> NetworkMessageRef<'_> {
246        NetworkMessageRef {
247            body: self.body(),
248            reliability: self.reliability(),
249        }
250    }
251
252    #[inline]
253    fn to_owned(&self) -> NetworkMessage {
254        NetworkMessage {
255            body: match self.body() {
256                NetworkBodyRef::Push(msg) => NetworkBody::Push(msg.clone()),
257                NetworkBodyRef::Request(msg) => NetworkBody::Request(msg.clone()),
258                NetworkBodyRef::Response(msg) => NetworkBody::Response(msg.clone()),
259                NetworkBodyRef::ResponseFinal(msg) => NetworkBody::ResponseFinal(msg.clone()),
260                NetworkBodyRef::Interest(msg) => NetworkBody::Interest(msg.clone()),
261                NetworkBodyRef::Declare(msg) => NetworkBody::Declare(msg.clone()),
262                NetworkBodyRef::OAM(msg) => NetworkBody::OAM(msg.clone()),
263            },
264            reliability: self.reliability(),
265        }
266    }
267}
268
269impl<M: NetworkMessageExt> NetworkMessageExt for &M {
270    fn body(&self) -> NetworkBodyRef<'_> {
271        (**self).body()
272    }
273
274    fn reliability(&self) -> Reliability {
275        (**self).reliability()
276    }
277}
278
279impl<M: NetworkMessageExt> NetworkMessageExt for &mut M {
280    fn body(&self) -> NetworkBodyRef<'_> {
281        (**self).body()
282    }
283
284    fn reliability(&self) -> Reliability {
285        (**self).reliability()
286    }
287}
288
289impl NetworkMessageExt for NetworkMessage {
290    fn body(&self) -> NetworkBodyRef<'_> {
291        match &self.body {
292            NetworkBody::Push(body) => NetworkBodyRef::Push(body),
293            NetworkBody::Request(body) => NetworkBodyRef::Request(body),
294            NetworkBody::Response(body) => NetworkBodyRef::Response(body),
295            NetworkBody::ResponseFinal(body) => NetworkBodyRef::ResponseFinal(body),
296            NetworkBody::Interest(body) => NetworkBodyRef::Interest(body),
297            NetworkBody::Declare(body) => NetworkBodyRef::Declare(body),
298            NetworkBody::OAM(body) => NetworkBodyRef::OAM(body),
299        }
300    }
301
302    fn reliability(&self) -> Reliability {
303        self.reliability
304    }
305}
306
307impl NetworkMessageExt for NetworkMessageRef<'_> {
308    fn body(&self) -> NetworkBodyRef<'_> {
309        self.body
310    }
311
312    fn reliability(&self) -> Reliability {
313        self.reliability
314    }
315}
316
317impl NetworkMessageExt for NetworkMessageMut<'_> {
318    fn body(&self) -> NetworkBodyRef<'_> {
319        match &self.body {
320            NetworkBodyMut::Push(body) => NetworkBodyRef::Push(body),
321            NetworkBodyMut::Request(body) => NetworkBodyRef::Request(body),
322            NetworkBodyMut::Response(body) => NetworkBodyRef::Response(body),
323            NetworkBodyMut::ResponseFinal(body) => NetworkBodyRef::ResponseFinal(body),
324            NetworkBodyMut::Interest(body) => NetworkBodyRef::Interest(body),
325            NetworkBodyMut::Declare(body) => NetworkBodyRef::Declare(body),
326            NetworkBodyMut::OAM(body) => NetworkBodyRef::OAM(body),
327        }
328    }
329
330    fn reliability(&self) -> Reliability {
331        self.reliability
332    }
333}
334
335impl NetworkMessage {
336    #[cfg(feature = "test")]
337    #[doc(hidden)]
338    pub fn rand() -> Self {
339        use rand::Rng;
340
341        let mut rng = rand::thread_rng();
342
343        let body = match rng.gen_range(0..6) {
344            0 => NetworkBody::Push(Push::rand()),
345            1 => NetworkBody::Request(Request::rand()),
346            2 => NetworkBody::Response(Response::rand()),
347            3 => NetworkBody::ResponseFinal(ResponseFinal::rand()),
348            4 => NetworkBody::Declare(Declare::rand()),
349            5 => NetworkBody::OAM(Oam::rand()),
350            _ => unreachable!(),
351        };
352
353        body.into()
354    }
355
356    #[inline]
357    pub fn as_mut(&mut self) -> NetworkMessageMut<'_> {
358        let body = match &mut self.body {
359            NetworkBody::Push(body) => NetworkBodyMut::Push(body),
360            NetworkBody::Request(body) => NetworkBodyMut::Request(body),
361            NetworkBody::Response(body) => NetworkBodyMut::Response(body),
362            NetworkBody::ResponseFinal(body) => NetworkBodyMut::ResponseFinal(body),
363            NetworkBody::Interest(body) => NetworkBodyMut::Interest(body),
364            NetworkBody::Declare(body) => NetworkBodyMut::Declare(body),
365            NetworkBody::OAM(body) => NetworkBodyMut::OAM(body),
366        };
367        NetworkMessageMut {
368            body,
369            reliability: self.reliability,
370        }
371    }
372}
373
374impl NetworkMessageMut<'_> {
375    #[inline]
376    pub fn as_mut(&mut self) -> NetworkMessageMut<'_> {
377        let body = match &mut self.body {
378            NetworkBodyMut::Push(body) => NetworkBodyMut::Push(body),
379            NetworkBodyMut::Request(body) => NetworkBodyMut::Request(body),
380            NetworkBodyMut::Response(body) => NetworkBodyMut::Response(body),
381            NetworkBodyMut::ResponseFinal(body) => NetworkBodyMut::ResponseFinal(body),
382            NetworkBodyMut::Interest(body) => NetworkBodyMut::Interest(body),
383            NetworkBodyMut::Declare(body) => NetworkBodyMut::Declare(body),
384            NetworkBodyMut::OAM(body) => NetworkBodyMut::OAM(body),
385        };
386        NetworkMessageMut {
387            body,
388            reliability: self.reliability,
389        }
390    }
391}
392
393impl fmt::Display for NetworkMessageRef<'_> {
394    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
395        match &self.body {
396            NetworkBodyRef::OAM(_) => write!(f, "OAM"),
397            NetworkBodyRef::Push(_) => write!(f, "Push"),
398            NetworkBodyRef::Request(_) => write!(f, "Request"),
399            NetworkBodyRef::Response(_) => write!(f, "Response"),
400            NetworkBodyRef::ResponseFinal(_) => write!(f, "ResponseFinal"),
401            NetworkBodyRef::Interest(_) => write!(f, "Interest"),
402            NetworkBodyRef::Declare(_) => write!(f, "Declare"),
403        }
404    }
405}
406
407impl fmt::Display for NetworkMessage {
408    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
409        self.as_ref().fmt(f)
410    }
411}
412
413impl fmt::Display for NetworkMessageMut<'_> {
414    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415        self.as_ref().fmt(f)
416    }
417}
418
419impl From<NetworkBody> for NetworkMessage {
420    #[inline]
421    fn from(body: NetworkBody) -> Self {
422        Self {
423            body,
424            reliability: Reliability::DEFAULT,
425        }
426    }
427}
428
429#[cfg(feature = "test")]
430impl From<Push> for NetworkMessage {
431    fn from(push: Push) -> Self {
432        NetworkBody::Push(push).into()
433    }
434}
435
436// Extensions
437pub mod ext {
438    use core::fmt;
439
440    use crate::{
441        common::{imsg, ZExtZ64},
442        core::{CongestionControl, EntityId, Priority, ZenohIdProto},
443    };
444
445    /// ```text
446    ///  7 6 5 4 3 2 1 0
447    /// +-+-+-+-+-+-+-+-+
448    /// |Z|0_1|    ID   |
449    /// +-+-+-+---------+
450    /// %0|r|F|E|D|prio %
451    /// +---------------+
452    ///
453    /// - prio: Priority class
454    /// - D:    Don't drop. Don't drop the message for congestion control.
455    /// - E:    Express. Don't batch this message.
456    /// - F:    Don't drop the first message for congestion control.
457    /// - r:  Reserved
458    /// ```
459    #[repr(transparent)]
460    #[derive(Clone, Copy, PartialEq, Eq)]
461    pub struct QoSType<const ID: u8> {
462        inner: u8,
463    }
464
465    impl<const ID: u8> QoSType<{ ID }> {
466        const P_MASK: u8 = 0b00000111;
467        const D_FLAG: u8 = 0b00001000;
468        const E_FLAG: u8 = 0b00010000;
469        const F_FLAG: u8 = 0b00100000;
470
471        pub const DEFAULT: Self = Self::new(Priority::DEFAULT, CongestionControl::DEFAULT, false);
472
473        pub const DECLARE: Self =
474            Self::new(Priority::Control, CongestionControl::DEFAULT_DECLARE, false);
475        pub const INTEREST: Self = Self::new(
476            Priority::Control,
477            CongestionControl::DEFAULT_INTEREST,
478            false,
479        );
480        pub const PUSH: Self = Self::new(Priority::DEFAULT, CongestionControl::DEFAULT_PUSH, false);
481        pub const REQUEST: Self =
482            Self::new(Priority::DEFAULT, CongestionControl::DEFAULT_REQUEST, false);
483        pub const OAM: Self = Self::new(Priority::Control, CongestionControl::DEFAULT_OAM, false);
484
485        pub const fn new(
486            priority: Priority,
487            congestion_control: CongestionControl,
488            is_express: bool,
489        ) -> Self {
490            let mut inner = priority as u8;
491            match congestion_control {
492                CongestionControl::Block => inner |= Self::D_FLAG,
493                #[cfg(feature = "unstable")]
494                CongestionControl::BlockFirst => inner |= Self::F_FLAG,
495                _ => {}
496            }
497            if is_express {
498                inner |= Self::E_FLAG;
499            }
500            Self { inner }
501        }
502
503        pub fn set_priority(&mut self, priority: Priority) {
504            self.inner = imsg::set_bitfield(self.inner, priority as u8, Self::P_MASK);
505        }
506
507        pub const fn get_priority(&self) -> Priority {
508            unsafe { core::mem::transmute(self.inner & Self::P_MASK) }
509        }
510
511        pub fn set_congestion_control(&mut self, cctrl: CongestionControl) {
512            match cctrl {
513                CongestionControl::Block => {
514                    self.inner = imsg::set_flag(self.inner, Self::D_FLAG);
515                    self.inner = imsg::unset_flag(self.inner, Self::F_FLAG);
516                }
517                CongestionControl::Drop => {
518                    self.inner = imsg::unset_flag(self.inner, Self::D_FLAG);
519                    self.inner = imsg::unset_flag(self.inner, Self::F_FLAG);
520                }
521                #[cfg(feature = "unstable")]
522                CongestionControl::BlockFirst => {
523                    self.inner = imsg::unset_flag(self.inner, Self::D_FLAG);
524                    self.inner = imsg::set_flag(self.inner, Self::F_FLAG);
525                }
526            }
527        }
528
529        pub const fn get_congestion_control(&self) -> CongestionControl {
530            match (
531                imsg::has_flag(self.inner, Self::D_FLAG),
532                imsg::has_flag(self.inner, Self::F_FLAG),
533            ) {
534                (false, false) => CongestionControl::Drop,
535                #[cfg(feature = "unstable")]
536                (false, true) => CongestionControl::BlockFirst,
537                #[cfg(not(feature = "unstable"))]
538                (false, true) => CongestionControl::Drop,
539                (true, _) => CongestionControl::Block,
540            }
541        }
542
543        pub fn set_is_express(&mut self, is_express: bool) {
544            match is_express {
545                true => self.inner = imsg::set_flag(self.inner, Self::E_FLAG),
546                false => self.inner = imsg::unset_flag(self.inner, Self::E_FLAG),
547            }
548        }
549
550        pub const fn is_express(&self) -> bool {
551            imsg::has_flag(self.inner, Self::E_FLAG)
552        }
553
554        #[cfg(feature = "test")]
555        #[doc(hidden)]
556        pub fn rand() -> Self {
557            use rand::Rng;
558            let mut rng = rand::thread_rng();
559
560            let inner: u8 = rng.gen();
561            Self { inner }
562        }
563    }
564
565    impl<const ID: u8> Default for QoSType<{ ID }> {
566        fn default() -> Self {
567            Self::new(Priority::DEFAULT, CongestionControl::DEFAULT, false)
568        }
569    }
570
571    impl<const ID: u8> From<ZExtZ64<{ ID }>> for QoSType<{ ID }> {
572        fn from(ext: ZExtZ64<{ ID }>) -> Self {
573            Self {
574                inner: ext.value as u8,
575            }
576        }
577    }
578
579    impl<const ID: u8> From<QoSType<{ ID }>> for ZExtZ64<{ ID }> {
580        fn from(ext: QoSType<{ ID }>) -> Self {
581            ZExtZ64::new(ext.inner as u64)
582        }
583    }
584
585    impl<const ID: u8> fmt::Debug for QoSType<{ ID }> {
586        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
587            f.debug_struct("QoS")
588                .field("priority", &self.get_priority())
589                .field("congestion", &self.get_congestion_control())
590                .field("express", &self.is_express())
591                .finish()
592        }
593    }
594
595    /// ```text
596    ///  7 6 5 4 3 2 1 0
597    /// +-+-+-+-+-+-+-+-+
598    /// |Z|1_0|    ID   |
599    /// +-+-+-+---------+
600    /// ~ ts: <u8;z16>  ~
601    /// +---------------+
602    /// ```
603    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
604    pub struct TimestampType<const ID: u8> {
605        pub timestamp: uhlc::Timestamp,
606    }
607
608    impl<const ID: u8> TimestampType<{ ID }> {
609        #[cfg(feature = "test")]
610        #[doc(hidden)]
611        pub fn rand() -> Self {
612            use rand::Rng;
613            let mut rng = rand::thread_rng();
614
615            let time = uhlc::NTP64(rng.gen());
616            let id = uhlc::ID::try_from(ZenohIdProto::rand().to_le_bytes()).unwrap();
617            let timestamp = uhlc::Timestamp::new(time, id);
618            Self { timestamp }
619        }
620    }
621
622    /// ```text
623    ///  7 6 5 4 3 2 1 0
624    /// +-+-+-+-+-+-+-+-+
625    /// |Z|0_1|    ID   |
626    /// +-+-+-+---------+
627    /// %    node_id    %
628    /// +---------------+
629    /// ```
630    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
631    pub struct NodeIdType<const ID: u8> {
632        pub node_id: u16,
633    }
634
635    impl<const ID: u8> NodeIdType<{ ID }> {
636        // node_id == 0 means the message has been generated by the node itself
637        pub const DEFAULT: Self = Self { node_id: 0 };
638
639        #[cfg(feature = "test")]
640        #[doc(hidden)]
641        pub fn rand() -> Self {
642            use rand::Rng;
643            let mut rng = rand::thread_rng();
644            let node_id = rng.gen();
645            Self { node_id }
646        }
647    }
648
649    impl<const ID: u8> Default for NodeIdType<{ ID }> {
650        fn default() -> Self {
651            Self::DEFAULT
652        }
653    }
654
655    impl<const ID: u8> From<ZExtZ64<{ ID }>> for NodeIdType<{ ID }> {
656        fn from(ext: ZExtZ64<{ ID }>) -> Self {
657            Self {
658                node_id: ext.value as u16,
659            }
660        }
661    }
662
663    impl<const ID: u8> From<NodeIdType<{ ID }>> for ZExtZ64<{ ID }> {
664        fn from(ext: NodeIdType<{ ID }>) -> Self {
665            ZExtZ64::new(ext.node_id as u64)
666        }
667    }
668
669    /// ```text
670    ///  7 6 5 4 3 2 1 0
671    /// +-+-+-+-+-+-+-+-+
672    /// |zid_len|X|X|X|X|
673    /// +-------+-+-+---+
674    /// ~      zid      ~
675    /// +---------------+
676    /// %      eid      %
677    /// +---------------+
678    /// ```
679    #[derive(Debug, Clone, PartialEq, Eq)]
680    pub struct EntityGlobalIdType<const ID: u8> {
681        pub zid: ZenohIdProto,
682        pub eid: EntityId,
683    }
684
685    impl<const ID: u8> EntityGlobalIdType<{ ID }> {
686        #[cfg(feature = "test")]
687        #[doc(hidden)]
688        pub fn rand() -> Self {
689            use rand::Rng;
690            let mut rng = rand::thread_rng();
691
692            let zid = ZenohIdProto::rand();
693            let eid: EntityId = rng.gen();
694            Self { zid, eid }
695        }
696    }
697}