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
108pub struct DidntConvert;
109
110#[repr(transparent)]
111#[derive(Clone, Copy, PartialEq, Eq)]
112pub struct ZExtUnit<const ID: u8>;
113
114impl<const ID: u8> Default for ZExtUnit<{ ID }> {
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120impl<const ID: u8> ZExtUnit<{ ID }> {
121    pub const ID: u8 = ID;
122
123    pub const fn new() -> Self {
124        Self
125    }
126
127    pub const fn id(mandatory: bool) -> u8 {
128        iext::id(ID, mandatory, iext::ENC_UNIT)
129    }
130
131    pub const fn is_mandatory(&self) -> bool {
132        iext::is_mandatory(ID)
133    }
134
135    pub const fn transmute<const DI: u8>(self) -> ZExtUnit<{ DI }> {
136        ZExtUnit::new()
137    }
138
139    #[cfg(feature = "test")]
140    #[doc(hidden)]
141    pub fn rand() -> Self {
142        Self::new()
143    }
144}
145
146impl<const ID: u8> Debug for ZExtUnit<{ ID }> {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        let mut s = f.debug_struct("ZExtUnit");
149        iext::fmt(&mut s, ID);
150        s.finish()
151    }
152}
153
154impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtUnit<{ ID }> {
155    type Error = DidntConvert;
156
157    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
158        if v.id != ID {
159            return Err(DidntConvert);
160        }
161        match v.body {
162            ZExtBody::Unit => Ok(Self::new()),
163            _ => Err(DidntConvert),
164        }
165    }
166}
167
168#[repr(transparent)]
169#[derive(Clone, Copy, PartialEq, Eq)]
170pub struct ZExtZ64<const ID: u8> {
171    pub value: u64,
172}
173
174impl<const ID: u8> ZExtZ64<{ ID }> {
175    pub const ID: u8 = ID;
176
177    pub const fn new(value: u64) -> Self {
178        Self { value }
179    }
180
181    pub const fn id(mandatory: bool) -> u8 {
182        iext::id(ID, mandatory, iext::ENC_Z64)
183    }
184
185    pub const fn is_mandatory(&self) -> bool {
186        iext::is_mandatory(ID)
187    }
188
189    pub const fn transmute<const DI: u8>(self) -> ZExtZ64<{ DI }> {
190        ZExtZ64::new(self.value)
191    }
192
193    #[cfg(feature = "test")]
194    #[doc(hidden)]
195    pub fn rand() -> Self {
196        use rand::Rng;
197
198        let mut rng = rand::thread_rng();
199        let value: u64 = rng.gen();
200        Self { value }
201    }
202}
203
204impl<const ID: u8> Debug for ZExtZ64<{ ID }> {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        let mut s = f.debug_struct("ZExtZ64");
207        iext::fmt(&mut s, ID);
208        s.field("Value", &self.value).finish()
209    }
210}
211
212impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtZ64<{ ID }> {
213    type Error = DidntConvert;
214
215    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
216        if v.id != ID {
217            return Err(DidntConvert);
218        }
219        match v.body {
220            ZExtBody::Z64(v) => Ok(Self::new(v)),
221            _ => Err(DidntConvert),
222        }
223    }
224}
225
226#[repr(transparent)]
227#[derive(Clone, PartialEq, Eq)]
228pub struct ZExtZBuf<const ID: u8> {
229    pub value: ZBuf,
230}
231
232impl<const ID: u8> ZExtZBuf<{ ID }> {
233    pub const ID: u8 = ID;
234
235    pub const fn new(value: ZBuf) -> Self {
236        Self { value }
237    }
238
239    pub const fn id(mandatory: bool) -> u8 {
240        iext::id(ID, mandatory, iext::ENC_ZBUF)
241    }
242
243    pub const fn is_mandatory(&self) -> bool {
244        iext::is_mandatory(ID)
245    }
246
247    pub fn transmute<const DI: u8>(self) -> ZExtZBuf<{ DI }> {
248        ZExtZBuf::new(self.value)
249    }
250
251    #[cfg(feature = "test")]
252    #[doc(hidden)]
253    pub fn rand() -> Self {
254        use rand::Rng;
255
256        let mut rng = rand::thread_rng();
257        let value = ZBuf::rand(rng.gen_range(8..=64));
258        Self { value }
259    }
260}
261
262impl<const ID: u8> Debug for ZExtZBuf<{ ID }> {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        let mut s = f.debug_struct("ZExtZBuf");
265        iext::fmt(&mut s, ID);
266        s.field("Value", &self.value).finish()
267    }
268}
269
270impl<const ID: u8> TryFrom<ZExtUnknown> for ZExtZBuf<{ ID }> {
271    type Error = DidntConvert;
272
273    fn try_from(v: ZExtUnknown) -> Result<Self, Self::Error> {
274        if v.id != ID {
275            return Err(DidntConvert);
276        }
277        match v.body {
278            ZExtBody::ZBuf(v) => Ok(Self::new(v)),
279            _ => Err(DidntConvert),
280        }
281    }
282}
283
284#[derive(Clone, PartialEq, Eq)]
285pub struct ZExtZBufHeader<const ID: u8> {
286    pub len: usize,
287}
288
289impl<const ID: u8> ZExtZBufHeader<{ ID }> {
290    pub const ID: u8 = ID;
291
292    pub const fn new(len: usize) -> Self {
293        Self { len }
294    }
295
296    pub const fn id(mandatory: bool) -> u8 {
297        iext::id(ID, mandatory, iext::ENC_ZBUF)
298    }
299
300    pub const fn is_mandatory(&self) -> bool {
301        iext::is_mandatory(ID)
302    }
303}
304
305impl<const ID: u8> Debug for ZExtZBufHeader<{ ID }> {
306    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307        let mut s = f.debug_struct("ZExtZBufHeader");
308        iext::fmt(&mut s, ID);
309        s.field("Len", &self.len).finish()
310    }
311}
312
313#[derive(Debug, Default, Clone, PartialEq, Eq)]
314pub enum ZExtBody {
315    #[default]
316    Unit,
317    Z64(u64),
318    ZBuf(ZBuf),
319}
320
321impl ZExtBody {
322    #[cfg(feature = "test")]
323    #[doc(hidden)]
324    pub fn rand() -> Self {
325        use rand::{seq::SliceRandom, Rng};
326        let mut rng = rand::thread_rng();
327        [
328            ZExtBody::Unit,
329            ZExtBody::Z64(rng.gen()),
330            ZExtBody::ZBuf(ZBuf::rand(rng.gen_range(8..=64))),
331        ]
332        .choose(&mut rng)
333        .unwrap()
334        .clone()
335    }
336}
337
338#[derive(Clone, PartialEq, Eq)]
339pub struct ZExtUnknown {
340    pub id: u8,
341    pub body: ZExtBody,
342}
343
344impl ZExtUnknown {
345    pub const fn new(id: u8, mandatory: bool, body: ZExtBody) -> Self {
346        let enc = match &body {
347            ZExtBody::Unit => iext::ENC_UNIT,
348            ZExtBody::Z64(_) => iext::ENC_Z64,
349            ZExtBody::ZBuf(_) => iext::ENC_ZBUF,
350        };
351        let id = iext::id(id, mandatory, enc);
352        Self { id, body }
353    }
354
355    pub const fn is_mandatory(&self) -> bool {
356        iext::is_mandatory(self.id)
357    }
358
359    #[cfg(feature = "test")]
360    #[doc(hidden)]
361    pub fn rand() -> Self {
362        use rand::Rng;
363        let mut rng = rand::thread_rng();
364
365        let id: u8 = rng.gen_range(0x00..=iext::ID_MASK);
366        let mandatory = rng.gen_bool(0.5);
367        let body = ZExtBody::rand();
368        Self::new(id, mandatory, body)
369    }
370
371    #[cfg(feature = "test")]
372    #[doc(hidden)]
373    pub fn rand2(start: u8, mandatory: bool) -> Self {
374        use rand::Rng;
375        let mut rng = rand::thread_rng();
376
377        let id: u8 = rng.gen_range(start..=iext::ID_MASK);
378        let body = ZExtBody::rand();
379        Self::new(id, mandatory, body)
380    }
381}
382
383impl Debug for ZExtUnknown {
384    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385        let mut s = f.debug_struct("ZExtUnknown");
386        iext::fmt(&mut s, self.id);
387        match &self.body {
388            ZExtBody::Unit => {}
389            ZExtBody::Z64(v) => {
390                s.field("Value", v);
391            }
392            ZExtBody::ZBuf(v) => {
393                s.field("Value", v);
394            }
395        };
396        s.finish()
397    }
398}
399
400impl<const ID: u8> From<ZExtUnit<{ ID }>> for ZExtUnknown {
401    fn from(_: ZExtUnit<{ ID }>) -> Self {
402        ZExtUnknown {
403            id: ID,
404            body: ZExtBody::Unit,
405        }
406    }
407}
408
409impl<const ID: u8> From<ZExtZ64<{ ID }>> for ZExtUnknown {
410    fn from(e: ZExtZ64<{ ID }>) -> Self {
411        ZExtUnknown {
412            id: ID,
413            body: ZExtBody::Z64(e.value),
414        }
415    }
416}
417
418impl<const ID: u8> From<ZExtZBuf<{ ID }>> for ZExtUnknown {
419    fn from(e: ZExtZBuf<{ ID }>) -> Self {
420        ZExtUnknown {
421            id: ID,
422            body: ZExtBody::ZBuf(e.value),
423        }
424    }
425}
426
427// Macros
428#[macro_export]
429macro_rules! zextunit {
430    ($id:expr, $m:expr) => {
431        ZExtUnit<{ ZExtUnit::<$id>::id($m) }>
432    }
433}
434
435#[macro_export]
436macro_rules! zextz64 {
437    ($id:expr, $m:expr) => {
438        ZExtZ64<{ ZExtZ64::<$id>::id($m) }>
439    }
440}
441
442#[macro_export]
443macro_rules! zextzbuf {
444    ($id:expr, $m:expr) => {
445        ZExtZBuf<{ ZExtZBuf::<$id>::id($m) }>
446    }
447}