zenoh_protocol_core/
wire_expr.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//
14
15//! This module defines the wire representation of Key Expressions.
16
17use crate::ExprId;
18use core::fmt;
19use std::{borrow::Cow, convert::TryInto};
20use zenoh_core::{bail, Result as ZResult};
21
22/// A zenoh **resource** is represented by a pair composed by a **key** and a
23/// **value**, such as, ```(/car/telemetry/speed, 320)```.  A **resource key**
24/// is an arbitrary array of characters, with the exclusion of the symbols
25/// ```*```, ```**```, ```?```, ```[```, ```]```, and ```#```,
26/// which have special meaning in the context of zenoh.
27///
28/// A key including any number of the wildcard symbols, ```*``` and ```**```,
29/// such as, ```/car/telemetry/*```, is called a **key expression** as it
30/// denotes a set of keys. The wildcard character ```*``` expands to an
31/// arbitrary string not including zenoh's reserved characters and the ```/```
32/// character, while the ```**``` expands to  strings that may also include the
33/// ```/``` character.  
34///
35/// Finally, it is worth mentioning that for time and space efficiency matters,
36/// zenoh will automatically map key expressions to small integers. The mapping is automatic,
37/// but it can be triggered excplicily by with `zenoh::Session::declare_keyexpr()`.
38///
39//
40//  7 6 5 4 3 2 1 0
41// +-+-+-+-+-+-+-+-+
42// ~      id       — if Expr : id=0
43// +-+-+-+-+-+-+-+-+
44// ~    suffix     ~ if flag K==1 in Message's header
45// +---------------+
46//
47#[derive(PartialEq, Eq, Hash, Clone)]
48pub struct WireExpr<'a> {
49    pub scope: ExprId, // 0 marks global scope
50    pub suffix: Cow<'a, str>,
51}
52
53impl<'a> WireExpr<'a> {
54    pub fn as_str(&'a self) -> &'a str {
55        if self.scope == 0 {
56            self.suffix.as_ref()
57        } else {
58            "<encoded_expr>"
59        }
60    }
61
62    pub fn try_as_str(&'a self) -> ZResult<&'a str> {
63        if self.scope == 0 {
64            Ok(self.suffix.as_ref())
65        } else {
66            bail!("Scoped key expression")
67        }
68    }
69
70    pub fn as_id(&'a self) -> ExprId {
71        self.scope
72    }
73
74    pub fn try_as_id(&'a self) -> ZResult<ExprId> {
75        if self.has_suffix() {
76            bail!("Suffixed key expression")
77        } else {
78            Ok(self.scope)
79        }
80    }
81
82    pub fn as_id_and_suffix(&'a self) -> (ExprId, &'a str) {
83        (self.scope, self.suffix.as_ref())
84    }
85
86    pub fn has_suffix(&self) -> bool {
87        !self.suffix.as_ref().is_empty()
88    }
89
90    pub fn to_owned(&self) -> WireExpr<'static> {
91        WireExpr {
92            scope: self.scope,
93            suffix: self.suffix.to_string().into(),
94        }
95    }
96
97    pub fn with_suffix(mut self, suffix: &'a str) -> Self {
98        if self.suffix.is_empty() {
99            self.suffix = suffix.into();
100        } else {
101            self.suffix += suffix;
102        }
103        self
104    }
105}
106
107impl TryInto<String> for WireExpr<'_> {
108    type Error = zenoh_core::Error;
109    fn try_into(self) -> Result<String, Self::Error> {
110        if self.scope == 0 {
111            Ok(self.suffix.into_owned())
112        } else {
113            bail!("Scoped key expression")
114        }
115    }
116}
117
118impl TryInto<ExprId> for WireExpr<'_> {
119    type Error = zenoh_core::Error;
120    fn try_into(self) -> Result<ExprId, Self::Error> {
121        self.try_as_id()
122    }
123}
124
125impl fmt::Debug for WireExpr<'_> {
126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127        if self.scope == 0 {
128            write!(f, "{}", self.suffix)
129        } else {
130            write!(f, "{}:{}", self.scope, self.suffix)
131        }
132    }
133}
134
135impl fmt::Display for WireExpr<'_> {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        if self.scope == 0 {
138            write!(f, "{}", self.suffix)
139        } else {
140            write!(f, "{}:{}", self.scope, self.suffix)
141        }
142    }
143}
144
145impl<'a> From<&WireExpr<'a>> for WireExpr<'a> {
146    #[inline]
147    fn from(key: &WireExpr<'a>) -> WireExpr<'a> {
148        key.clone()
149    }
150}
151
152impl From<ExprId> for WireExpr<'_> {
153    #[inline]
154    fn from(rid: ExprId) -> WireExpr<'static> {
155        WireExpr {
156            scope: rid,
157            suffix: "".into(),
158        }
159    }
160}
161
162impl From<&ExprId> for WireExpr<'_> {
163    #[inline]
164    fn from(rid: &ExprId) -> WireExpr<'static> {
165        WireExpr {
166            scope: *rid,
167            suffix: "".into(),
168        }
169    }
170}
171
172impl<'a> From<&'a str> for WireExpr<'a> {
173    #[inline]
174    fn from(name: &'a str) -> WireExpr<'a> {
175        WireExpr {
176            scope: 0,
177            suffix: name.into(),
178        }
179    }
180}
181
182impl From<String> for WireExpr<'_> {
183    #[inline]
184    fn from(name: String) -> WireExpr<'static> {
185        WireExpr {
186            scope: 0,
187            suffix: name.into(),
188        }
189    }
190}
191
192impl<'a> From<&'a String> for WireExpr<'a> {
193    #[inline]
194    fn from(name: &'a String) -> WireExpr<'a> {
195        WireExpr {
196            scope: 0,
197            suffix: name.into(),
198        }
199    }
200}