Skip to main content

zenoh_protocol/common/
extension.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//
14use core::{
15    convert::TryFrom,
16    fmt::{self, Debug},
17};
18
19use zenoh_buffers::ZBuf;
20
21/// # Zenoh extensions
22///
23/// A zenoh extension is encoded as TLV (Type, Length, Value).
24/// Zenoh extensions with unknown IDs (i.e., type) can be skipped by reading the length and
25/// not decoding the body (i.e. value). In case the zenoh extension is unknown, it is
26/// still possible to forward it to the next hops, which in turn may be able to understand it.
27/// This results in the capability of introducing new extensions in an already running system
28/// without requiring the redeployment of the totality of infrastructure nodes.
29///
30/// The zenoh extension wire format is the following:
31///
32/// ```text
33/// Header flags:
34/// - E |: Encoding     The encoding of the extension
35/// - E/
36/// - Z: More           If Z==1 then another extension will follow.
37///
38///  7 6 5 4 3 2 1 0
39/// +-+-+-+-+-+-+-+-+
40/// |Z|ENC|M|   ID  |
41/// +-+---+-+-------+
42/// %    length     % -- If ENC == Z64 || ENC == ZBuf (z32)
43/// +---------------+
44/// ~     [u8]      ~ -- If ENC == ZBuf
45/// +---------------+
46///
47/// Encoding:
48/// - 0b00: Unit
49/// - 0b01: Z64
50/// - 0b10: ZBuf
51/// - 0b11: Reserved
52///
53/// (*) If the zenoh extension is not understood, then it SHOULD NOT be dropped and it
54///     SHOULD be forwarded to the next hops.
55/// ```
56///
57pub mod iext {
58    use core::fmt;
59
60    pub const ID_BITS: u8 = 4;
61    pub const ID_MASK: u8 = !(u8::MAX << ID_BITS);
62
63    pub const FLAG_M: u8 = 1 << 4;
64    pub const ENC_UNIT: u8 = 0b00 << 5;
65    pub const ENC_Z64: u8 = 0b01 << 5;
66    pub const ENC_ZBUF: u8 = 0b10 << 5;
67    pub const ENC_MASK: u8 = 0b11 << 5;
68    pub const FLAG_Z: u8 = 1 << 7;
69
70    pub const fn eid(header: u8) -> u8 {
71        header & !FLAG_Z
72    }
73
74    pub const fn mid(header: u8) -> u8 {
75        header & ID_MASK
76    }
77
78    pub(super) const fn id(id: u8, mandatory: bool, encoding: u8) -> u8 {
79        let mut id = id & ID_MASK;
80        if mandatory {
81            id |= FLAG_M;
82        } else {
83            id &= !FLAG_M;
84        }
85        id |= encoding;
86        id
87    }
88
89    pub(super) const fn is_mandatory(id: u8) -> bool {
90        crate::common::imsg::has_flag(id, FLAG_M)
91    }
92
93    pub(super) fn fmt(f: &mut fmt::DebugStruct, id: u8) {
94        f.field("Id", &(id & ID_MASK))
95            .field("Mandatory", &is_mandatory(id))
96            .field(
97                "Encoding",
98                match id & ENC_MASK {
99                    ENC_UNIT => &"Unit",
100                    ENC_Z64 => &"Z64",
101                    ENC_ZBUF => &"ZBuf",
102                    _ => &"Unknown",
103                },
104            );
105    }
106}
107
108#[derive(Debug)]
109pub struct DidntConvert;
110
111#[repr(transparent)]
112#[derive(Clone, Copy, PartialEq, Eq)]
113pub struct ZExtUnit<const ID: u8>;
114
115impl<const ID: u8> Default for ZExtUnit<{ ID }> {
116    fn default() -> Self {
117        Self::new()
118    }
119}
120
121impl<const ID: u8> ZExtUnit<{ ID }> {
122    pub const ID: u8 = ID;
123
124    pub const fn new() -> Self {
125        Self
126    }
127
128    pub const fn id(mandatory: bool) -> u8 {
129        iext::id(ID, mandatory, iext::ENC_UNIT)
130    }
131
132    pub const fn is_mandatory(&self) -> bool {
133        iext::is_mandatory(ID)
134    }
135
136    pub const fn transmute<const DI: u8>(self) -> ZExtUnit<{ DI }> {
137        ZExtUnit::new()
138    }
139
140    #[cfg(feature = "test")]
141    #[doc(hidden)]
142    pub fn rand() -> Self {
143        Self::new()
144    }
145}
146
147impl<const ID: u8> Debug for ZExtUnit<{ ID }> {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        let mut s = f.debug_struct("ZExtUnit");
150        iext::fmt(&mut s, ID);
151        s.finish()
152    }
153}
154
155impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtUnit<{ ID }> {
156    type Error = DidntConvert;
157
158    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
159        if v.id != ID {
160            return Err(DidntConvert);
161        }
162        match v.body {
163            ZExtBody::Unit => Ok(Self::new()),
164            _ => Err(DidntConvert),
165        }
166    }
167}
168
169#[repr(transparent)]
170#[derive(Clone, Copy, PartialEq, Eq)]
171pub struct ZExtZ64<const ID: u8> {
172    pub value: u64,
173}
174
175impl<const ID: u8> ZExtZ64<{ ID }> {
176    pub const ID: u8 = ID;
177
178    pub const fn new(value: u64) -> Self {
179        Self { value }
180    }
181
182    pub const fn id(mandatory: bool) -> u8 {
183        iext::id(ID, mandatory, iext::ENC_Z64)
184    }
185
186    pub const fn is_mandatory(&self) -> bool {
187        iext::is_mandatory(ID)
188    }
189
190    pub const fn transmute<const DI: u8>(self) -> ZExtZ64<{ DI }> {
191        ZExtZ64::new(self.value)
192    }
193
194    #[cfg(feature = "test")]
195    #[doc(hidden)]
196    pub fn rand() -> Self {
197        use rand::Rng;
198
199        let mut rng = rand::thread_rng();
200        let value: u64 = rng.gen();
201        Self { value }
202    }
203}
204
205impl<const ID: u8> Debug for ZExtZ64<{ ID }> {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        let mut s = f.debug_struct("ZExtZ64");
208        iext::fmt(&mut s, ID);
209        s.field("Value", &self.value).finish()
210    }
211}
212
213impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtZ64<{ ID }> {
214    type Error = DidntConvert;
215
216    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
217        if v.id != ID {
218            return Err(DidntConvert);
219        }
220        match v.body {
221            ZExtBody::Z64(v) => Ok(Self::new(v)),
222            _ => Err(DidntConvert),
223        }
224    }
225}
226
227#[repr(transparent)]
228#[derive(Clone, PartialEq, Eq)]
229pub struct ZExtZBuf<const ID: u8> {
230    pub value: ZBuf,
231}
232
233impl<const ID: u8> ZExtZBuf<{ ID }> {
234    pub const ID: u8 = ID;
235
236    pub const fn new(value: ZBuf) -> Self {
237        Self { value }
238    }
239
240    pub const fn id(mandatory: bool) -> u8 {
241        iext::id(ID, mandatory, iext::ENC_ZBUF)
242    }
243
244    pub const fn is_mandatory(&self) -> bool {
245        iext::is_mandatory(ID)
246    }
247
248    pub fn transmute<const DI: u8>(self) -> ZExtZBuf<{ DI }> {
249        ZExtZBuf::new(self.value)
250    }
251
252    #[cfg(feature = "test")]
253    #[doc(hidden)]
254    pub fn rand() -> Self {
255        use rand::Rng;
256
257        let mut rng = rand::thread_rng();
258        let value = ZBuf::rand(rng.gen_range(8..=64));
259        Self { value }
260    }
261}
262
263impl<const ID: u8> Debug for ZExtZBuf<{ ID }> {
264    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265        let mut s = f.debug_struct("ZExtZBuf");
266        iext::fmt(&mut s, ID);
267        s.field("Value", &self.value).finish()
268    }
269}
270
271impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtZBuf<{ ID }> {
272    type Error = DidntConvert;
273
274    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
275        if v.id != ID {
276            return Err(DidntConvert);
277        }
278        match v.body {
279            ZExtBody::ZBuf(v) => Ok(Self::new(v)),
280            _ => Err(DidntConvert),
281        }
282    }
283}
284
285#[derive(Clone, PartialEq, Eq)]
286pub struct ZExtZBufHeader<const ID: u8> {
287    pub len: usize,
288}
289
290impl<const ID: u8> ZExtZBufHeader<{ ID }> {
291    pub const ID: u8 = ID;
292
293    pub const fn new(len: usize) -> Self {
294        Self { len }
295    }
296
297    pub const fn id(mandatory: bool) -> u8 {
298        iext::id(ID, mandatory, iext::ENC_ZBUF)
299    }
300
301    pub const fn is_mandatory(&self) -> bool {
302        iext::is_mandatory(ID)
303    }
304}
305
306impl<const ID: u8> Debug for ZExtZBufHeader<{ ID }> {
307    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308        let mut s = f.debug_struct("ZExtZBufHeader");
309        iext::fmt(&mut s, ID);
310        s.field("Len", &self.len).finish()
311    }
312}
313
314#[derive(Debug, Default, Clone, PartialEq, Eq)]
315pub enum ZExtBody {
316    #[default]
317    Unit,
318    Z64(u64),
319    ZBuf(ZBuf),
320}
321
322impl ZExtBody {
323    #[cfg(feature = "test")]
324    #[doc(hidden)]
325    pub fn rand() -> Self {
326        use rand::{seq::SliceRandom, Rng};
327        let mut rng = rand::thread_rng();
328        [
329            ZExtBody::Unit,
330            ZExtBody::Z64(rng.gen()),
331            ZExtBody::ZBuf(ZBuf::rand(rng.gen_range(8..=64))),
332        ]
333        .choose(&mut rng)
334        .unwrap()
335        .clone()
336    }
337}
338
339#[derive(Clone, PartialEq, Eq)]
340pub struct ZExtUnknown {
341    pub id: u8,
342    pub body: ZExtBody,
343}
344
345impl ZExtUnknown {
346    pub const fn new(id: u8, mandatory: bool, body: ZExtBody) -> Self {
347        let enc = match &body {
348            ZExtBody::Unit => iext::ENC_UNIT,
349            ZExtBody::Z64(_) => iext::ENC_Z64,
350            ZExtBody::ZBuf(_) => iext::ENC_ZBUF,
351        };
352        let id = iext::id(id, mandatory, enc);
353        Self { id, body }
354    }
355
356    pub const fn is_mandatory(&self) -> bool {
357        iext::is_mandatory(self.id)
358    }
359
360    #[cfg(feature = "test")]
361    #[doc(hidden)]
362    pub fn rand() -> Self {
363        use rand::Rng;
364        let mut rng = rand::thread_rng();
365
366        let id: u8 = rng.gen_range(0x00..=iext::ID_MASK);
367        let mandatory = rng.gen_bool(0.5);
368        let body = ZExtBody::rand();
369        Self::new(id, mandatory, body)
370    }
371
372    #[cfg(feature = "test")]
373    #[doc(hidden)]
374    pub fn rand2(start: u8, mandatory: bool) -> Self {
375        use rand::Rng;
376        let mut rng = rand::thread_rng();
377
378        let id: u8 = rng.gen_range(start..=iext::ID_MASK);
379        let body = ZExtBody::rand();
380        Self::new(id, mandatory, body)
381    }
382}
383
384impl Debug for ZExtUnknown {
385    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386        let mut s = f.debug_struct("ZExtUnknown");
387        iext::fmt(&mut s, self.id);
388        match &self.body {
389            ZExtBody::Unit => {}
390            ZExtBody::Z64(v) => {
391                s.field("Value", v);
392            }
393            ZExtBody::ZBuf(v) => {
394                s.field("Value", v);
395            }
396        };
397        s.finish()
398    }
399}
400
401impl<const ID: u8> From<ZExtUnit<{ ID }>> for ZExtUnknown {
402    fn from(_: ZExtUnit<{ ID }>) -> Self {
403        ZExtUnknown {
404            id: ID,
405            body: ZExtBody::Unit,
406        }
407    }
408}
409
410impl<const ID: u8> From<ZExtZ64<{ ID }>> for ZExtUnknown {
411    fn from(e: ZExtZ64<{ ID }>) -> Self {
412        ZExtUnknown {
413            id: ID,
414            body: ZExtBody::Z64(e.value),
415        }
416    }
417}
418
419impl<const ID: u8> From<ZExtZBuf<{ ID }>> for ZExtUnknown {
420    fn from(e: ZExtZBuf<{ ID }>) -> Self {
421        ZExtUnknown {
422            id: ID,
423            body: ZExtBody::ZBuf(e.value),
424        }
425    }
426}
427
428// Macros
429#[macro_export]
430macro_rules! zextunit {
431    ($id:expr, $m:expr) => {
432        $crate::common::extension::ZExtUnit<{ $crate::common::extension::ZExtUnit::<$id>::id($m) }>
433    }
434}
435
436#[macro_export]
437macro_rules! zextz64 {
438    ($id:expr, $m:expr) => {
439        $crate::common::extension::ZExtZ64<{ $crate::common::extension::ZExtZ64::<$id>::id($m) }>
440    }
441}
442
443#[macro_export]
444macro_rules! zextzbuf {
445    ($id:expr, $m:expr) => {
446        $crate::common::extension::ZExtZBuf<{ $crate::common::extension::ZExtZBuf::<$id>::id($m) }>
447    }
448}