zenoh_codec/scouting/
scout.rs

1//
2// Copyright (c) 2023 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::convert::TryFrom;
15
16use zenoh_buffers::{
17    reader::{DidntRead, Reader},
18    writer::{DidntWrite, Writer},
19};
20use zenoh_protocol::{
21    common::{imsg, ZExtUnknown},
22    core::{whatami::WhatAmIMatcher, ZenohIdProto},
23    scouting::{
24        id,
25        scout::{flag, Scout},
26    },
27};
28
29use crate::{RCodec, WCodec, Zenoh080, Zenoh080Header, Zenoh080Length};
30
31impl<W> WCodec<&Scout, &mut W> for Zenoh080
32where
33    W: Writer,
34{
35    type Output = Result<(), DidntWrite>;
36
37    fn write(self, writer: &mut W, x: &Scout) -> Self::Output {
38        let Scout { version, what, zid } = x;
39
40        // Header
41        let header = id::SCOUT;
42        self.write(&mut *writer, header)?;
43
44        // Body
45        self.write(&mut *writer, version)?;
46
47        let mut flags: u8 = 0;
48        let what: u8 = (*what).into();
49        flags |= what & 0b111;
50        if let Some(zid) = zid.as_ref() {
51            flags |= (((zid.size() - 1) as u8) << 4) | flag::I;
52        };
53        self.write(&mut *writer, flags)?;
54
55        if let Some(zid) = zid.as_ref() {
56            let lodec = Zenoh080Length::new(zid.size());
57            lodec.write(&mut *writer, zid)?;
58        }
59
60        Ok(())
61    }
62}
63
64impl<R> RCodec<Scout, &mut R> for Zenoh080
65where
66    R: Reader,
67{
68    type Error = DidntRead;
69
70    fn read(self, reader: &mut R) -> Result<Scout, Self::Error> {
71        let header: u8 = self.read(&mut *reader)?;
72        let codec = Zenoh080Header::new(header);
73
74        codec.read(reader)
75    }
76}
77
78impl<R> RCodec<Scout, &mut R> for Zenoh080Header
79where
80    R: Reader,
81{
82    type Error = DidntRead;
83
84    fn read(self, reader: &mut R) -> Result<Scout, Self::Error> {
85        if imsg::mid(self.header) != id::SCOUT {
86            return Err(DidntRead);
87        }
88
89        // Body
90        let version: u8 = self.codec.read(&mut *reader)?;
91        let flags: u8 = self.codec.read(&mut *reader)?;
92        let what = WhatAmIMatcher::try_from(flags & 0b111).map_err(|_| DidntRead)?;
93        let zid = if imsg::has_flag(flags, flag::I) {
94            let length = 1 + ((flags >> 4) as usize);
95            let lodec = Zenoh080Length::new(length);
96            let zid: ZenohIdProto = lodec.read(&mut *reader)?;
97            Some(zid)
98        } else {
99            None
100        };
101
102        // Extensions
103        let mut has_extensions = imsg::has_flag(self.header, flag::Z);
104        while has_extensions {
105            let (_, more): (ZExtUnknown, bool) = self.codec.read(&mut *reader)?;
106            has_extensions = more;
107        }
108
109        Ok(Scout { version, what, zid })
110    }
111}