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