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, Default, Clone, PartialEq, Eq)]
311pub enum ZExtBody {
312    #[default]
313    Unit,
314    Z64(u64),
315    ZBuf(ZBuf),
316}
317
318impl ZExtBody {
319    #[cfg(feature = "test")]
320    pub fn rand() -> Self {
321        use rand::{seq::SliceRandom, Rng};
322        let mut rng = rand::thread_rng();
323        [
324            ZExtBody::Unit,
325            ZExtBody::Z64(rng.gen()),
326            ZExtBody::ZBuf(ZBuf::rand(rng.gen_range(8..=64))),
327        ]
328        .choose(&mut rng)
329        .unwrap()
330        .clone()
331    }
332}
333
334#[derive(Clone, PartialEq, Eq)]
335pub struct ZExtUnknown {
336    pub id: u8,
337    pub body: ZExtBody,
338}
339
340impl ZExtUnknown {
341    pub const fn new(id: u8, mandatory: bool, body: ZExtBody) -> Self {
342        let enc = match &body {
343            ZExtBody::Unit => iext::ENC_UNIT,
344            ZExtBody::Z64(_) => iext::ENC_Z64,
345            ZExtBody::ZBuf(_) => iext::ENC_ZBUF,
346        };
347        let id = iext::id(id, mandatory, enc);
348        Self { id, body }
349    }
350
351    pub const fn is_mandatory(&self) -> bool {
352        iext::is_mandatory(self.id)
353    }
354
355    #[cfg(feature = "test")]
356    pub fn rand() -> Self {
357        use rand::Rng;
358        let mut rng = rand::thread_rng();
359
360        let id: u8 = rng.gen_range(0x00..=iext::ID_MASK);
361        let mandatory = rng.gen_bool(0.5);
362        let body = ZExtBody::rand();
363        Self::new(id, mandatory, body)
364    }
365
366    #[cfg(feature = "test")]
367    pub fn rand2(start: u8, mandatory: bool) -> Self {
368        use rand::Rng;
369        let mut rng = rand::thread_rng();
370
371        let id: u8 = rng.gen_range(start..=iext::ID_MASK);
372        let body = ZExtBody::rand();
373        Self::new(id, mandatory, body)
374    }
375}
376
377impl Debug for ZExtUnknown {
378    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379        let mut s = f.debug_struct("ZExtUnknown");
380        iext::fmt(&mut s, self.id);
381        match &self.body {
382            ZExtBody::Unit => {}
383            ZExtBody::Z64(v) => {
384                s.field("Value", v);
385            }
386            ZExtBody::ZBuf(v) => {
387                s.field("Value", v);
388            }
389        };
390        s.finish()
391    }
392}
393
394impl<const ID: u8> From<ZExtUnit<{ ID }>> for ZExtUnknown {
395    fn from(_: ZExtUnit<{ ID }>) -> Self {
396        ZExtUnknown {
397            id: ID,
398            body: ZExtBody::Unit,
399        }
400    }
401}
402
403impl<const ID: u8> From<ZExtZ64<{ ID }>> for ZExtUnknown {
404    fn from(e: ZExtZ64<{ ID }>) -> Self {
405        ZExtUnknown {
406            id: ID,
407            body: ZExtBody::Z64(e.value),
408        }
409    }
410}
411
412impl<const ID: u8> From<ZExtZBuf<{ ID }>> for ZExtUnknown {
413    fn from(e: ZExtZBuf<{ ID }>) -> Self {
414        ZExtUnknown {
415            id: ID,
416            body: ZExtBody::ZBuf(e.value),
417        }
418    }
419}
420
421// Macros
422#[macro_export]
423macro_rules! zextunit {
424    ($id:expr, $m:expr) => {
425        ZExtUnit<{ ZExtUnit::<$id>::id($m) }>
426    }
427}
428
429#[macro_export]
430macro_rules! zextz64 {
431    ($id:expr, $m:expr) => {
432        ZExtZ64<{ ZExtZ64::<$id>::id($m) }>
433    }
434}
435
436#[macro_export]
437macro_rules! zextzbuf {
438    ($id:expr, $m:expr) => {
439        ZExtZBuf<{ ZExtZBuf::<$id>::id($m) }>
440    }
441}