1use std::{borrow::Cow, convert::TryFrom, str::FromStr};
17
18use zenoh_protocol::core::{
19 key_expr::{keyexpr, OwnedKeyExpr},
20 Parameters,
21};
22#[cfg(feature = "unstable")]
23use ::{zenoh_result::ZResult, zenoh_util::time_range::TimeRange};
24
25use crate::api::{key_expr::KeyExpr, queryable::Query};
26
27#[derive(Clone, PartialEq, Eq)]
62pub struct Selector<'a> {
63 pub(crate) key_expr: Cow<'a, KeyExpr<'a>>,
65 pub(crate) parameters: Cow<'a, Parameters<'a>>,
67}
68
69impl<'a> Selector<'a> {
70 pub fn key_expr(&self) -> &KeyExpr<'a> {
72 &self.key_expr
73 }
74
75 pub fn parameters(&self) -> &Parameters<'a> {
77 &self.parameters
78 }
79
80 pub fn split(self) -> (KeyExpr<'a>, Parameters<'a>) {
82 self.into()
83 }
84
85 pub fn owned<K, P>(key_expr: K, parameters: P) -> Self
87 where
88 K: Into<KeyExpr<'a>>,
89 P: Into<Parameters<'a>>,
90 {
91 Self {
92 key_expr: Cow::Owned(key_expr.into()),
93 parameters: Cow::Owned(parameters.into()),
94 }
95 }
96 pub fn borrowed(key_expr: &'a KeyExpr<'a>, parameters: &'a Parameters<'a>) -> Self {
99 Self {
100 key_expr: Cow::Borrowed(key_expr),
101 parameters: Cow::Borrowed(parameters),
102 }
103 }
104
105 pub fn into_owned(self) -> Selector<'static> {
107 Selector::owned(
108 self.key_expr.into_owned().into_owned(),
109 self.parameters.into_owned().into_owned(),
110 )
111 }
112}
113
114impl<'a, K, P> From<(K, P)> for Selector<'a>
115where
116 K: Into<KeyExpr<'a>>,
117 P: Into<Parameters<'a>>,
118{
119 fn from((key_expr, parameters): (K, P)) -> Self {
120 Self::owned(key_expr, parameters)
121 }
122}
123
124impl<'a> From<Selector<'a>> for (KeyExpr<'a>, Parameters<'a>) {
125 fn from(selector: Selector<'a>) -> Self {
126 (
127 selector.key_expr.into_owned(),
128 selector.parameters.into_owned(),
129 )
130 }
131}
132
133impl<'a> From<&'a Selector<'a>> for (&'a KeyExpr<'a>, &'a Parameters<'a>) {
134 fn from(selector: &'a Selector<'a>) -> Self {
135 (selector.key_expr.as_ref(), selector.parameters.as_ref())
136 }
137}
138
139pub(crate) const REPLY_KEY_EXPR_ANY_SEL_PARAM: &str = "_anyke";
140#[zenoh_macros::unstable]
141pub(crate) const TIME_RANGE_KEY: &str = "_time";
142
143#[zenoh_macros::unstable]
144pub trait ZenohParameters {
146 fn set_time_range<T: Into<Option<TimeRange>>>(&mut self, time_range: T);
151 fn set_reply_key_expr_any(&mut self);
161 fn time_range(&self) -> Option<ZResult<TimeRange>>;
165 fn reply_key_expr_any(&self) -> bool;
167}
168
169#[cfg(feature = "unstable")]
170impl ZenohParameters for Parameters<'_> {
171 fn set_time_range<T: Into<Option<TimeRange>>>(&mut self, time_range: T) {
173 let mut time_range: Option<TimeRange> = time_range.into();
174 match time_range.take() {
175 Some(tr) => self.insert(TIME_RANGE_KEY, format!("{tr}")),
176 None => self.remove(TIME_RANGE_KEY),
177 };
178 }
179
180 fn set_reply_key_expr_any(&mut self) {
183 self.insert(REPLY_KEY_EXPR_ANY_SEL_PARAM, "");
184 }
185
186 fn time_range(&self) -> Option<ZResult<TimeRange>> {
190 self.get(TIME_RANGE_KEY)
191 .map(|tr| tr.parse().map_err(Into::into))
192 }
193
194 fn reply_key_expr_any(&self) -> bool {
196 self.contains_key(REPLY_KEY_EXPR_ANY_SEL_PARAM)
197 }
198}
199
200impl std::fmt::Debug for Selector<'_> {
201 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
202 write!(f, "sel\"{self}\"")
203 }
204}
205
206impl std::fmt::Display for Selector<'_> {
207 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208 write!(f, "{}", self.key_expr)?;
209 if !self.parameters.is_empty() {
210 write!(f, "?{}", self.parameters.as_str())?;
211 }
212 Ok(())
213 }
214}
215
216impl<'a> From<&Selector<'a>> for Selector<'a> {
217 fn from(s: &Selector<'a>) -> Self {
218 s.clone()
219 }
220}
221
222impl TryFrom<String> for Selector<'_> {
223 type Error = zenoh_result::Error;
224 fn try_from(mut s: String) -> Result<Self, Self::Error> {
225 match s.find('?') {
226 Some(qmark_position) => {
227 let parameters = s[qmark_position + 1..].to_owned();
228 s.truncate(qmark_position);
229 Ok(Selector::owned(KeyExpr::try_from(s)?, parameters))
230 }
231 None => Ok(KeyExpr::try_from(s)?.into()),
232 }
233 }
234}
235
236impl<'a> TryFrom<&'a str> for Selector<'a> {
237 type Error = zenoh_result::Error;
238 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
239 match s.find('?') {
240 Some(qmark_position) => {
241 let params = &s[qmark_position + 1..];
242 Ok(Selector::owned(
243 KeyExpr::try_from(&s[..qmark_position])?,
244 params,
245 ))
246 }
247 None => Ok(KeyExpr::try_from(s)?.into()),
248 }
249 }
250}
251impl FromStr for Selector<'static> {
252 type Err = zenoh_result::Error;
253 fn from_str(s: &str) -> Result<Self, Self::Err> {
254 s.to_owned().try_into()
255 }
256}
257
258impl<'a> TryFrom<&'a String> for Selector<'a> {
259 type Error = zenoh_result::Error;
260 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
261 Self::try_from(s.as_str())
262 }
263}
264
265impl<'a> From<&'a Query> for Selector<'a> {
266 fn from(q: &'a Query) -> Self {
267 Self {
268 key_expr: Cow::Borrowed(&q.inner.key_expr),
269 parameters: Cow::Borrowed(&q.inner.parameters),
270 }
271 }
272}
273
274impl<'a> From<&'a KeyExpr<'a>> for Selector<'a> {
275 fn from(key_selector: &'a KeyExpr<'a>) -> Self {
276 Self {
277 key_expr: Cow::Borrowed(key_selector),
278 parameters: Cow::Owned("".into()),
279 }
280 }
281}
282
283impl<'a> From<&'a keyexpr> for Selector<'a> {
284 fn from(key_selector: &'a keyexpr) -> Self {
285 Self {
286 key_expr: Cow::Owned(key_selector.into()),
287 parameters: Cow::Owned("".into()),
288 }
289 }
290}
291
292impl<'a> From<&'a OwnedKeyExpr> for Selector<'a> {
293 fn from(key_selector: &'a OwnedKeyExpr) -> Self {
294 Self {
295 key_expr: Cow::Owned(key_selector.into()),
296 parameters: Cow::Owned("".into()),
297 }
298 }
299}
300
301impl From<OwnedKeyExpr> for Selector<'static> {
302 fn from(key_selector: OwnedKeyExpr) -> Self {
303 Self {
304 key_expr: Cow::Owned(key_selector.into()),
305 parameters: Cow::Owned("".into()),
306 }
307 }
308}
309
310impl<'a> From<KeyExpr<'a>> for Selector<'a> {
311 fn from(key_selector: KeyExpr<'a>) -> Self {
312 Self {
313 key_expr: Cow::Owned(key_selector),
314 parameters: Cow::Owned("".into()),
315 }
316 }
317}
318
319#[cfg(feature = "unstable")]
320#[test]
321fn selector_accessors() {
322 use std::collections::HashMap;
323
324 for s in [
325 "hello/there?_timetrick",
326 "hello/there?_timetrick;_time",
327 "hello/there?_timetrick;_time;_filter",
328 "hello/there?_timetrick;_time=[..]",
329 "hello/there?_timetrick;_time=[..];_filter",
330 ] {
331 let Selector {
332 key_expr,
333 parameters,
334 } = s.try_into().unwrap();
335 assert_eq!(key_expr.as_str(), "hello/there");
336 let mut parameters = parameters.into_owned();
337
338 println!("Parameters start: {parameters}");
339 for i in parameters.iter() {
340 println!("\t{i:?}");
341 }
342
343 assert_eq!(parameters.get("_timetrick").unwrap(), "");
344
345 const ANYKE: &str = REPLY_KEY_EXPR_ANY_SEL_PARAM;
346
347 let time_range = "[now(-2s)..now(2s)]";
348 zcondfeat!(
349 "unstable",
350 {
351 let time_range = time_range.parse().unwrap();
352 parameters.set_time_range(time_range);
353 assert_eq!(parameters.time_range().unwrap().unwrap(), time_range);
354 },
355 {
356 parameters.insert(TIME_RANGE_KEY, time_range);
357 }
358 );
359 assert_eq!(parameters.get(TIME_RANGE_KEY).unwrap(), time_range);
360
361 let hm: HashMap<&str, &str> = HashMap::from(¶meters);
362 assert!(hm.contains_key(TIME_RANGE_KEY));
363
364 parameters.insert("_filter", "");
365 assert_eq!(parameters.get("_filter").unwrap(), "");
366
367 let hm: HashMap<String, String> = HashMap::from(¶meters);
368 assert!(hm.contains_key(TIME_RANGE_KEY));
369
370 parameters.extend_from_iter(hm.iter());
371 assert_eq!(parameters.get("_filter").unwrap(), "");
372
373 parameters.insert(ANYKE, "");
374
375 println!("Parameters end: {parameters}");
376 for i in parameters.iter() {
377 println!("\t{i:?}");
378 }
379
380 assert_eq!(
381 HashMap::<String, String>::from(¶meters),
382 HashMap::<String, String>::from(Parameters::from(
383 "_anyke;_filter;_time=[now(-2s)..now(2s)];_timetrick"
384 ))
385 );
386 }
387}