Skip to main content

zenoh/api/
key_expr.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 std::{
15    convert::{TryFrom, TryInto},
16    future::{IntoFuture, Ready},
17    str::FromStr,
18    sync::Arc,
19};
20
21use zenoh_core::{Resolvable, Wait};
22use zenoh_keyexpr::{keyexpr, OwnedKeyExpr};
23use zenoh_protocol::{
24    core::{key_expr::canon::Canonize, ExprId, WireExpr},
25    network::Mapping,
26};
27use zenoh_result::ZResult;
28
29use crate::api::session::{Session, UndeclarableSealed, WeakSession};
30
31#[derive(Debug)]
32pub(crate) struct KeyExprWireDeclaration {
33    expr_id: ExprId,
34    prefix_len: u32,
35    session: WeakSession,
36    undeclared: bool,
37}
38
39impl KeyExprWireDeclaration {
40    pub(crate) fn new(prefix: &str, session: &Session, force: bool) -> ZResult<Option<Self>> {
41        let prefix_len = prefix.len() as u32;
42        Ok(session
43            .declare_prefix(prefix, force)
44            .wait()?
45            .map(|expr_id| Self {
46                expr_id,
47                prefix_len,
48                session: session.downgrade(),
49                undeclared: false,
50            }))
51    }
52
53    pub(crate) fn undeclare(&mut self) -> ZResult<()> {
54        if self.undeclared {
55            Ok(())
56        } else {
57            self.undeclared = true;
58            self.session.undeclare_prefix(self.expr_id)
59        }
60    }
61}
62
63impl Drop for KeyExprWireDeclaration {
64    fn drop(&mut self) {
65        let _ = self.undeclare();
66    }
67}
68
69#[derive(Clone, Debug)]
70pub(crate) enum KeyExprInner<'a> {
71    Borrowed {
72        key_expr: &'a keyexpr,
73        declaration: Option<Arc<KeyExprWireDeclaration>>,
74    },
75    Owned {
76        key_expr: OwnedKeyExpr,
77        declaration: Option<Arc<KeyExprWireDeclaration>>,
78    },
79}
80
81/// A possibly-owned version of [`keyexpr`] that may carry optimisations for use with a [`Session`] that may have declared it.
82///
83/// Check [`keyexpr`]'s documentation for detailed explanations of the Key Expression Language.
84#[repr(transparent)]
85#[derive(Clone, serde::Deserialize, serde::Serialize)]
86#[serde(from = "OwnedKeyExpr")]
87#[serde(into = "OwnedKeyExpr")]
88pub struct KeyExpr<'a>(pub(crate) KeyExprInner<'a>);
89
90// Implement RefUnwindSafe for compatibility purposes.
91// Given that all key expression public methods are immutable, they
92// do not break any key expression invariants.
93impl<'a> std::panic::RefUnwindSafe for KeyExpr<'a> {}
94impl<'a> std::panic::UnwindSafe for KeyExpr<'a> {}
95
96impl std::ops::Deref for KeyExpr<'_> {
97    type Target = keyexpr;
98    fn deref(&self) -> &Self::Target {
99        match &self.0 {
100            KeyExprInner::Borrowed { key_expr, .. } => key_expr,
101            KeyExprInner::Owned { key_expr, .. } => key_expr,
102        }
103    }
104}
105
106impl KeyExpr<'static> {
107    /// Constructs a [`KeyExpr`] without checking [`keyexpr`]'s invariants
108    /// # Safety
109    /// Key Expressions must follow some rules to be accepted by a Zenoh network.
110    /// Messages addressed with invalid key expressions will be dropped.
111    pub unsafe fn from_string_unchecked(s: String) -> Self {
112        Self(KeyExprInner::Owned {
113            key_expr: OwnedKeyExpr::from_string_unchecked(s),
114            declaration: None,
115        })
116    }
117
118    /// Constructs a [`KeyExpr`] without checking [`keyexpr`]'s invariants
119    /// # Safety
120    /// Key Expressions must follow some rules to be accepted by a Zenoh network.
121    /// Messages addressed with invalid key expressions will be dropped.
122    pub unsafe fn from_boxed_str_unchecked(s: Box<str>) -> Self {
123        Self(KeyExprInner::Owned {
124            key_expr: OwnedKeyExpr::from_boxed_str_unchecked(s),
125            declaration: None,
126        })
127    }
128}
129
130#[zenoh_macros::internal]
131static KEYEXPR_DUMMY: &keyexpr = unsafe { keyexpr::from_str_unchecked("dummy") };
132
133impl<'a> KeyExpr<'a> {
134    /// Equivalent to `<KeyExpr as TryFrom>::try_from(t)`.
135    ///
136    /// Will return an Err if `t` isn't a valid key expression.
137    /// Note that to be considered a valid key expression, a string MUST be canon.
138    ///
139    /// [`KeyExpr::autocanonize`] is an alternative constructor that will canonize the passed expression before constructing it.
140    pub fn new<T, E>(t: T) -> Result<Self, E>
141    where
142        Self: TryFrom<T, Error = E>,
143    {
144        Self::try_from(t)
145    }
146
147    /// Constructs a key expression object to be used as a dummy value
148    /// for empty objects. This method is not supposed to be called in user code,
149    /// but may be used in language bindings (zenoh-c)
150    #[zenoh_macros::internal]
151    pub fn dummy() -> Self {
152        Self(KeyExprInner::Borrowed {
153            key_expr: KEYEXPR_DUMMY,
154            declaration: None,
155        })
156    }
157
158    /// Checks if the key expression is the dummy one.
159    /// This method is not supposed to be called in user code,
160    /// but may be used in language bindings (zenoh-c)
161    #[zenoh_macros::internal]
162    pub fn is_dummy(&self) -> bool {
163        let Self(inner) = self;
164        let KeyExprInner::Borrowed { key_expr, .. } = inner else {
165            return false;
166        };
167        std::ptr::eq(*key_expr, KEYEXPR_DUMMY)
168    }
169
170    /// Constructs a new [`KeyExpr`] aliasing `self`.
171    ///
172    /// Note that [`KeyExpr`] (as well as [`OwnedKeyExpr`]) use reference counters internally, so you're probably better off using clone.
173    pub fn borrowing_clone(&'a self) -> Self {
174        let inner = match &self.0 {
175            KeyExprInner::Borrowed {
176                key_expr,
177                declaration,
178            } => KeyExprInner::Borrowed {
179                key_expr,
180                declaration: declaration.clone(),
181            },
182            KeyExprInner::Owned {
183                key_expr,
184                declaration,
185            } => KeyExprInner::Borrowed {
186                key_expr,
187                declaration: declaration.clone(),
188            },
189        };
190        Self(inner)
191    }
192
193    /// Canonizes the passed value before returning it as a `KeyExpr`.
194    ///
195    /// Will return Err if the passed value isn't a valid key expression despite canonization.
196    pub fn autocanonize<T, E>(mut t: T) -> Result<Self, E>
197    where
198        Self: TryFrom<T, Error = E>,
199        T: Canonize,
200    {
201        t.canonize();
202        Self::new(t)
203    }
204
205    /// Constructs a [`KeyExpr`] without checking [`keyexpr`]'s invariants
206    /// # Safety
207    /// Key Expressions must follow some rules to be accepted by a Zenoh network.
208    /// Messages addressed with invalid key expressions will be dropped.
209    pub unsafe fn from_str_unchecked(s: &'a str) -> Self {
210        keyexpr::from_str_unchecked(s).into()
211    }
212
213    /// Returns the borrowed version of `self`
214    pub fn as_keyexpr(&self) -> &keyexpr {
215        self
216    }
217
218    /// Ensures `self` owns all of its data, and informs rustc that it does.
219    pub fn into_owned(self) -> KeyExpr<'static> {
220        let inner = match self.0 {
221            KeyExprInner::Borrowed {
222                key_expr,
223                declaration,
224            } => KeyExprInner::Owned {
225                key_expr: key_expr.into(),
226                declaration: declaration.clone(),
227            },
228            KeyExprInner::Owned {
229                key_expr,
230                declaration,
231            } => KeyExprInner::Owned {
232                key_expr,
233                declaration,
234            },
235        };
236        KeyExpr(inner)
237    }
238
239    /// Joins both sides, inserting a `/` in between them.
240    ///
241    /// This should be your preferred method when concatenating path segments.
242    ///
243    /// # Examples
244    /// ```
245    /// # use std::convert::TryFrom;
246    /// # use zenoh::key_expr::KeyExpr;
247    /// let prefix = KeyExpr::try_from("some/prefix").unwrap();
248    /// let suffix = KeyExpr::try_from("some/suffix").unwrap();
249    /// let join = prefix.join(&suffix).unwrap();
250    /// assert_eq!(join.as_str(), "some/prefix/some/suffix");
251    /// ```
252    pub fn join<S: AsRef<str> + ?Sized>(&self, s: &S) -> ZResult<KeyExpr<'static>> {
253        Ok(KeyExpr(KeyExprInner::Owned {
254            key_expr: self.as_keyexpr().join(s)?,
255            declaration: self.declaration().clone(),
256        }))
257    }
258
259    /// Performs string concatenation and returns the result as a [`KeyExpr`] if possible.
260    ///
261    /// You should probably prefer [`KeyExpr::join`] as Zenoh may then take advantage of the hierarchical separation it inserts.
262    pub fn concat<S: AsRef<str> + ?Sized>(&self, s: &S) -> ZResult<KeyExpr<'static>> {
263        let s = s.as_ref();
264        if self.ends_with('*') && s.starts_with('*') {
265            bail!("Tried to concatenate {} (ends with *) and {} (starts with *), which would likely have caused bugs. If you're sure you want to do this, concatenate these into a string and then try to convert.", self, s)
266        }
267        Ok(KeyExpr(KeyExprInner::Owned {
268            key_expr: OwnedKeyExpr::try_from(format!("{self}{s}"))?,
269            declaration: self.declaration().clone(),
270        }))
271    }
272
273    /// Will return false and log an error in case of a `TryInto` failure.
274    #[inline]
275    pub(crate) fn keyexpr_include<'b, L, R>(left: L, right: R) -> bool
276    where
277        L: TryInto<KeyExpr<'a>>,
278        R: TryInto<KeyExpr<'b>>,
279        L::Error: std::fmt::Display,
280        R::Error: std::fmt::Display,
281    {
282        match left.try_into() {
283            Ok(l) => match right.try_into() {
284                Ok(r) => {
285                    return l.includes(&r);
286                }
287                Err(e) => {
288                    tracing::error!("{e}");
289                }
290            },
291            Err(e) => {
292                tracing::error!("{e}");
293            }
294        }
295        false
296    }
297}
298
299impl FromStr for KeyExpr<'static> {
300    type Err = zenoh_result::Error;
301    fn from_str(s: &str) -> Result<Self, Self::Err> {
302        Ok(Self(KeyExprInner::Owned {
303            key_expr: s.parse()?,
304            declaration: None,
305        }))
306    }
307}
308
309impl<'a> From<KeyExpr<'a>> for OwnedKeyExpr {
310    fn from(val: KeyExpr<'a>) -> Self {
311        match val.0 {
312            KeyExprInner::Borrowed { key_expr, .. } => key_expr.into(),
313            KeyExprInner::Owned { key_expr, .. } => key_expr,
314        }
315    }
316}
317impl AsRef<keyexpr> for KeyExpr<'_> {
318    fn as_ref(&self) -> &keyexpr {
319        self
320    }
321}
322impl AsRef<str> for KeyExpr<'_> {
323    fn as_ref(&self) -> &str {
324        self
325    }
326}
327impl<'a> From<&'a keyexpr> for KeyExpr<'a> {
328    fn from(key_expr: &'a keyexpr) -> Self {
329        Self(KeyExprInner::Borrowed {
330            key_expr,
331            declaration: None,
332        })
333    }
334}
335impl From<OwnedKeyExpr> for KeyExpr<'_> {
336    fn from(key_expr: OwnedKeyExpr) -> Self {
337        Self(KeyExprInner::Owned {
338            key_expr,
339            declaration: None,
340        })
341    }
342}
343impl<'a> From<&'a OwnedKeyExpr> for KeyExpr<'a> {
344    fn from(key_expr: &'a OwnedKeyExpr) -> Self {
345        Self(KeyExprInner::Borrowed {
346            key_expr,
347            declaration: None,
348        })
349    }
350}
351impl<'a> From<&'a KeyExpr<'a>> for KeyExpr<'a> {
352    fn from(val: &'a KeyExpr<'a>) -> Self {
353        Self(KeyExprInner::Borrowed {
354            key_expr: val.key_expr(),
355            declaration: val.declaration().clone(),
356        })
357    }
358}
359impl From<KeyExpr<'_>> for String {
360    fn from(ke: KeyExpr) -> Self {
361        match ke.0 {
362            KeyExprInner::Borrowed { key_expr, .. } => key_expr.as_str().to_owned(),
363            KeyExprInner::Owned { key_expr, .. } => key_expr.into(),
364        }
365    }
366}
367
368impl TryFrom<String> for KeyExpr<'_> {
369    type Error = zenoh_result::Error;
370    fn try_from(value: String) -> Result<Self, Self::Error> {
371        Ok(Self(KeyExprInner::Owned {
372            key_expr: value.try_into()?,
373            declaration: None,
374        }))
375    }
376}
377impl<'a> TryFrom<&'a String> for KeyExpr<'a> {
378    type Error = zenoh_result::Error;
379    fn try_from(value: &'a String) -> Result<Self, Self::Error> {
380        Self::try_from(value.as_str())
381    }
382}
383impl<'a> TryFrom<&'a mut String> for KeyExpr<'a> {
384    type Error = zenoh_result::Error;
385    fn try_from(value: &'a mut String) -> Result<Self, Self::Error> {
386        Ok(Self::from(keyexpr::new(value)?))
387    }
388}
389impl<'a> TryFrom<&'a str> for KeyExpr<'a> {
390    type Error = zenoh_result::Error;
391    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
392        Ok(Self(KeyExprInner::Borrowed {
393            key_expr: value.try_into()?,
394            declaration: None,
395        }))
396    }
397}
398impl<'a> TryFrom<&'a mut str> for KeyExpr<'a> {
399    type Error = zenoh_result::Error;
400    fn try_from(value: &'a mut str) -> Result<Self, Self::Error> {
401        Ok(Self(KeyExprInner::Borrowed {
402            key_expr: value.try_into()?,
403            declaration: None,
404        }))
405    }
406}
407impl std::fmt::Debug for KeyExpr<'_> {
408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409        std::fmt::Debug::fmt(self.as_keyexpr(), f)
410    }
411}
412impl std::fmt::Display for KeyExpr<'_> {
413    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
414        std::fmt::Display::fmt(self.as_keyexpr(), f)
415    }
416}
417impl PartialEq for KeyExpr<'_> {
418    fn eq(&self, other: &Self) -> bool {
419        self.as_keyexpr() == other.as_keyexpr()
420    }
421}
422impl<T: PartialEq<keyexpr>> PartialEq<T> for KeyExpr<'_> {
423    fn eq(&self, other: &T) -> bool {
424        other == self.as_keyexpr()
425    }
426}
427impl Eq for KeyExpr<'_> {}
428impl std::hash::Hash for KeyExpr<'_> {
429    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
430        self.as_keyexpr().hash(state);
431    }
432}
433
434impl std::ops::Div<&keyexpr> for KeyExpr<'_> {
435    type Output = KeyExpr<'static>;
436
437    fn div(self, rhs: &keyexpr) -> Self::Output {
438        KeyExpr(KeyExprInner::Owned {
439            key_expr: self.key_expr() / rhs,
440            declaration: self.into_declaration(),
441        })
442    }
443}
444impl std::ops::Div<&keyexpr> for &KeyExpr<'_> {
445    type Output = KeyExpr<'static>;
446
447    fn div(self, rhs: &keyexpr) -> Self::Output {
448        KeyExpr(KeyExprInner::Owned {
449            key_expr: self.key_expr() / rhs,
450            declaration: self.declaration().clone(),
451        })
452    }
453}
454
455impl<'a> KeyExpr<'a> {
456    fn declaration(&self) -> &Option<Arc<KeyExprWireDeclaration>> {
457        match &self.0 {
458            KeyExprInner::Borrowed { declaration, .. } => declaration,
459            KeyExprInner::Owned { declaration, .. } => declaration,
460        }
461    }
462
463    fn declaration_mut(&mut self) -> &mut Option<Arc<KeyExprWireDeclaration>> {
464        match &mut self.0 {
465            KeyExprInner::Borrowed { declaration, .. } => declaration,
466            KeyExprInner::Owned { declaration, .. } => declaration,
467        }
468    }
469
470    pub(crate) fn declare(mut self, session: &Session, force: bool) -> ZResult<Self> {
471        if !self.is_fully_optimized(session) {
472            *self.declaration_mut() =
473                KeyExprWireDeclaration::new(self.as_str(), session, force)?.map(Arc::new);
474        }
475        Ok(self)
476    }
477
478    pub(crate) fn declare_nonwild_prefix(
479        mut self,
480        session: &Session,
481        force: bool,
482    ) -> ZResult<Self> {
483        if !self.is_non_wild_prefix_optimized(session) {
484            let ke = self.as_keyexpr();
485            *self.declaration_mut() = match ke.get_nonwild_prefix() {
486                Some(prefix) => {
487                    KeyExprWireDeclaration::new(prefix.as_str(), session, force)?.map(Arc::new)
488                }
489                None => None,
490            }
491        }
492        Ok(self)
493    }
494
495    fn into_declaration(self) -> Option<Arc<KeyExprWireDeclaration>> {
496        match self.0 {
497            KeyExprInner::Borrowed { declaration, .. } => declaration,
498            KeyExprInner::Owned { declaration, .. } => declaration,
499        }
500    }
501
502    pub(crate) fn key_expr(&self) -> &keyexpr {
503        match &self.0 {
504            KeyExprInner::Borrowed { key_expr, .. } => key_expr,
505            KeyExprInner::Owned { key_expr, .. } => key_expr,
506        }
507    }
508
509    pub(crate) fn is_fully_optimized(&self, session: &Session) -> bool {
510        self.declaration()
511            .as_ref()
512            .map(|d| d.session == *session && d.prefix_len as usize == self.key_expr().len())
513            .unwrap_or(false)
514    }
515
516    pub(crate) fn is_non_wild_prefix_optimized(&self, session: &Session) -> bool {
517        self.declaration()
518            .as_ref()
519            .map(|d| {
520                d.session == *session
521                    && self
522                        .key_expr()
523                        .get_nonwild_prefix()
524                        .map(|p| p.len() == d.prefix_len as usize)
525                        .unwrap_or(d.prefix_len == 0)
526            })
527            .unwrap_or(false)
528    }
529
530    fn to_wire_inner(&'a self, session: &Session, mapping: Mapping) -> WireExpr<'a> {
531        match self.declaration() {
532            Some(d) if d.session == *session => WireExpr {
533                scope: d.expr_id,
534                suffix: std::borrow::Cow::Borrowed(
535                    &self.key_expr().as_str()[(d.prefix_len as usize)..],
536                ),
537                mapping,
538            },
539            _ => WireExpr {
540                scope: 0,
541                suffix: std::borrow::Cow::Borrowed(self.key_expr().as_str()),
542                mapping,
543            },
544        }
545    }
546
547    pub(crate) fn to_wire(&'a self, session: &Session) -> WireExpr<'a> {
548        self.to_wire_inner(session, Mapping::Sender)
549    }
550
551    pub(crate) fn to_wire_local(&'a self, session: &Session) -> WireExpr<'a> {
552        self.to_wire_inner(session, Mapping::Receiver)
553    }
554
555    fn undeclare_with_session_check(&mut self, parent_session: Option<&Session>) -> ZResult<()> {
556        match self.declaration_mut().take() {
557            Some(mut d) if self.key_expr().len() == d.prefix_len as usize => {
558                if parent_session.is_some_and(|s| d.session == *s) {
559                    Arc::get_mut(&mut d).map(|d| d.undeclare()).unwrap_or(Ok(()))
560                } else {
561                    let expr_id = self.declaration_mut().insert(d).expr_id;
562                        Err(zerror!(
563                            "Failed to undeclare expr with id {}, as it was declared by another Session",
564                            expr_id
565                        )
566                        .into())
567                }
568            },
569            _ => Err(zerror!("Failed to undeclare {}, make sure you use the result of `Session::declare_keyexpr` to call `Session::undeclare`, and that key_expression was not undeclared previously", self).into()),
570        }
571    }
572}
573
574impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> {
575    type Undeclaration = KeyExprUndeclaration<'a>;
576
577    fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration {
578        KeyExprUndeclaration {
579            session,
580            expr: self,
581        }
582    }
583}
584
585/// A [`Resolvable`] returned by [`Session::undeclare`] when undeclaring a [`KeyExpr`]
586///
587/// # Examples
588/// ```
589/// # #[tokio::main]
590/// # async fn main() {
591///
592/// let session = zenoh::open(zenoh::Config::default()).await.unwrap();
593/// let key_expr = session.declare_keyexpr("key/expression").await.unwrap();
594/// session.undeclare(key_expr).await.unwrap();
595/// # }
596/// ```
597#[must_use = "Resolvables do nothing unless you resolve them using `.await` or `zenoh::Wait::wait`"]
598pub struct KeyExprUndeclaration<'a> {
599    session: &'a Session,
600    expr: KeyExpr<'a>,
601}
602
603impl Resolvable for KeyExprUndeclaration<'_> {
604    type To = ZResult<()>;
605}
606
607impl Wait for KeyExprUndeclaration<'_> {
608    fn wait(self) -> <Self as Resolvable>::To {
609        let KeyExprUndeclaration { session, mut expr } = self;
610        expr.undeclare_with_session_check(Some(session))
611    }
612}
613
614impl IntoFuture for KeyExprUndeclaration<'_> {
615    type Output = <Self as Resolvable>::To;
616    type IntoFuture = Ready<<Self as Resolvable>::To>;
617
618    fn into_future(self) -> Self::IntoFuture {
619        std::future::ready(self.wait())
620    }
621}
622
623#[cfg(target_pointer_width = "64")]
624#[allow(non_snake_case)]
625#[test]
626fn size_of_KeyExpr() {
627    assert_eq!(
628        std::mem::size_of::<KeyExpr>(),
629        4 * std::mem::size_of::<usize>()
630    );
631    assert_eq!(
632        std::mem::size_of::<Option<KeyExpr>>(),
633        4 * std::mem::size_of::<usize>()
634    );
635}