zenoh_protocol/core/
wire_expr.rs1use alloc::{
17 borrow::Cow,
18 string::{String, ToString},
19};
20use core::{convert::TryInto, fmt, sync::atomic::AtomicU16};
21
22use zenoh_keyexpr::{keyexpr, OwnedKeyExpr};
23use zenoh_result::{bail, ZResult};
24
25use crate::network::Mapping;
26
27pub type ExprId = u16;
29pub type ExprLen = u16;
30
31pub type AtomicExprId = AtomicU16;
32pub const EMPTY_EXPR_ID: ExprId = 0;
33
34#[derive(PartialEq, Eq, Hash, Clone, Debug)]
60pub struct WireExpr<'a> {
61 pub scope: ExprId, pub suffix: Cow<'a, str>,
63 pub mapping: Mapping,
64}
65
66impl<'a> WireExpr<'a> {
67 pub fn empty() -> Self {
68 WireExpr {
69 scope: 0,
70 suffix: "".into(),
71 mapping: Mapping::Sender,
72 }
73 }
74
75 pub fn is_empty(&self) -> bool {
76 self.scope == 0 && self.suffix.as_ref().is_empty()
77 }
78
79 pub fn as_str(&'a self) -> &'a str {
80 if self.scope == 0 {
81 self.suffix.as_ref()
82 } else {
83 "<encoded_expr>"
84 }
85 }
86
87 pub fn try_as_str(&'a self) -> ZResult<&'a str> {
88 if self.scope == EMPTY_EXPR_ID {
89 Ok(self.suffix.as_ref())
90 } else {
91 bail!("Scoped key expression")
92 }
93 }
94
95 pub fn as_id(&'a self) -> ExprId {
96 self.scope
97 }
98
99 pub fn try_as_id(&'a self) -> ZResult<ExprId> {
100 if self.has_suffix() {
101 bail!("Suffixed key expression")
102 } else {
103 Ok(self.scope)
104 }
105 }
106
107 pub fn as_id_and_suffix(&'a self) -> (ExprId, &'a str) {
108 (self.scope, self.suffix.as_ref())
109 }
110
111 pub fn has_suffix(&self) -> bool {
112 !self.suffix.as_ref().is_empty()
113 }
114
115 pub fn to_owned(&self) -> WireExpr<'static> {
116 WireExpr {
117 scope: self.scope,
118 suffix: self.suffix.to_string().into(),
119 mapping: self.mapping,
120 }
121 }
122
123 pub fn with_suffix(mut self, suffix: &'a str) -> Self {
124 if self.suffix.is_empty() {
125 self.suffix = suffix.into();
126 } else {
127 self.suffix += suffix;
128 }
129 self
130 }
131}
132
133impl TryInto<String> for WireExpr<'_> {
134 type Error = zenoh_result::Error;
135 fn try_into(self) -> Result<String, Self::Error> {
136 if self.scope == 0 {
137 Ok(self.suffix.into_owned())
138 } else {
139 bail!("Scoped key expression")
140 }
141 }
142}
143
144impl TryInto<ExprId> for WireExpr<'_> {
145 type Error = zenoh_result::Error;
146 fn try_into(self) -> Result<ExprId, Self::Error> {
147 self.try_as_id()
148 }
149}
150
151impl From<ExprId> for WireExpr<'_> {
152 fn from(scope: ExprId) -> Self {
153 Self {
154 scope,
155 suffix: "".into(),
156 mapping: Mapping::Sender,
157 }
158 }
159}
160
161impl<'a> From<&'a OwnedKeyExpr> for WireExpr<'a> {
162 fn from(val: &'a OwnedKeyExpr) -> Self {
163 WireExpr {
164 scope: 0,
165 suffix: Cow::Borrowed(val.as_str()),
166 mapping: Mapping::Sender,
167 }
168 }
169}
170
171impl<'a> From<&'a keyexpr> for WireExpr<'a> {
172 fn from(val: &'a keyexpr) -> Self {
173 WireExpr {
174 scope: 0,
175 suffix: Cow::Borrowed(val.as_str()),
176 mapping: Mapping::Sender,
177 }
178 }
179}
180
181impl fmt::Display for WireExpr<'_> {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 if self.scope == 0 {
184 write!(f, "{}", self.suffix)
185 } else {
186 write!(f, "{}:{:?}:{}", self.scope, self.mapping, self.suffix)
187 }
188 }
189}
190
191impl<'a> From<&WireExpr<'a>> for WireExpr<'a> {
192 #[inline]
193 fn from(key: &WireExpr<'a>) -> WireExpr<'a> {
194 key.clone()
195 }
196}
197
198impl<'a> From<&'a str> for WireExpr<'a> {
199 #[inline]
200 fn from(name: &'a str) -> WireExpr<'a> {
201 WireExpr {
202 scope: 0,
203 suffix: name.into(),
204 mapping: Mapping::Sender,
205 }
206 }
207}
208
209impl From<String> for WireExpr<'_> {
210 #[inline]
211 fn from(name: String) -> WireExpr<'static> {
212 WireExpr {
213 scope: 0,
214 suffix: name.into(),
215 mapping: Mapping::Sender,
216 }
217 }
218}
219
220impl<'a> From<&'a String> for WireExpr<'a> {
221 #[inline]
222 fn from(name: &'a String) -> WireExpr<'a> {
223 WireExpr {
224 scope: 0,
225 suffix: name.into(),
226 mapping: Mapping::Sender,
227 }
228 }
229}
230
231impl WireExpr<'_> {
232 #[cfg(feature = "test")]
233 pub fn rand() -> Self {
234 use rand::{
235 distributions::{Alphanumeric, DistString},
236 Rng,
237 };
238
239 const MIN: usize = 2;
240 const MAX: usize = 64;
241
242 let mut rng = rand::thread_rng();
243
244 let scope: ExprId = rng.gen_range(0..20);
245 let suffix: String = if rng.gen_bool(0.5) {
246 let len = rng.gen_range(MIN..MAX);
247 Alphanumeric.sample_string(&mut rng, len)
248 } else {
249 String::new()
250 };
251
252 WireExpr {
253 scope,
254 suffix: suffix.into(),
255 mapping: Mapping::DEFAULT,
256 }
257 }
258}