zenoh_keyexpr/key_expr/intersect/
mod.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//
14
15use super::keyexpr;
16use crate::DELIMITER;
17
18mod classical;
19pub use classical::ClassicIntersector;
20// #[deprecated = "This module hasn't been updated to support the $* DSL yet"]
21// pub(crate) mod ltr;
22// #[deprecated = "This module hasn't been updated to support the $* DSL yet"]
23// pub(crate) mod ltr_chunk;
24// #[deprecated = "This module hasn't been updated to support the $* DSL yet"]
25// pub(crate) mod middle_out;
26// pub use ltr::LeftToRightIntersector;
27// pub use ltr_chunk::LTRChunkIntersector;
28// pub use middle_out::MiddleOutIntersector;
29
30pub const DEFAULT_INTERSECTOR: ClassicIntersector = ClassicIntersector;
31
32/// The trait used to implement key expression intersectors.
33///
34/// Note that `Intersector<&keyexpr, &keyexpr>` is auto-implemented with quickchecks (`streq->true`, `strne&nowild->false`)
35/// for any `Intersector<&[u8], &[u8]>`. Implementing `Intersector<&[u8], &[u8]>` is the recommended way to implement intersectors.
36pub trait Intersector<Left, Right> {
37    fn intersect(&self, left: Left, right: Right) -> bool;
38}
39
40pub(crate) mod restriction {
41    use core::ops::Deref;
42
43    #[repr(transparent)]
44    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45    pub struct NoBigWilds<T>(pub T);
46    #[repr(transparent)]
47    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48    pub struct NoSubWilds<T>(pub T);
49
50    impl<T> Deref for NoBigWilds<T> {
51        type Target = T;
52
53        fn deref(&self) -> &Self::Target {
54            &self.0
55        }
56    }
57}
58#[repr(u8)]
59enum MatchComplexity {
60    NoWilds = 0,
61    ChunkWildsOnly = 1,
62    Dsl = 2,
63}
64trait KeyExprHelpers {
65    fn match_complexity(&self) -> MatchComplexity;
66}
67impl KeyExprHelpers for keyexpr {
68    fn match_complexity(&self) -> MatchComplexity {
69        let mut has_wilds = false;
70        for &c in self.as_bytes() {
71            match c {
72                b'*' => has_wilds = true,
73                b'$' => return MatchComplexity::Dsl,
74                _ => {}
75            }
76        }
77        if has_wilds {
78            MatchComplexity::ChunkWildsOnly
79        } else {
80            MatchComplexity::NoWilds
81        }
82    }
83}
84
85use restriction::NoSubWilds;
86impl<
87        T: for<'a> Intersector<&'a [u8], &'a [u8]>
88            + for<'a> Intersector<NoSubWilds<&'a [u8]>, NoSubWilds<&'a [u8]>>,
89    > Intersector<&keyexpr, &keyexpr> for T
90{
91    fn intersect(&self, left: &keyexpr, right: &keyexpr) -> bool {
92        let left_bytes = left.as_bytes();
93        let right_bytes = right.as_bytes();
94        if left_bytes == right_bytes {
95            return true;
96        }
97        match left.match_complexity() as u8 | right.match_complexity() as u8 {
98            0 => false,
99            1 => self.intersect(NoSubWilds(left_bytes), NoSubWilds(right_bytes)),
100            _ => self.intersect(left_bytes, right_bytes),
101        }
102    }
103}
104
105pub(crate) trait MayHaveVerbatim {
106    fn has_verbatim(&self) -> bool;
107    fn has_direct_verbatim(&self) -> bool;
108    unsafe fn has_direct_verbatim_non_empty(&self) -> bool {
109        self.has_direct_verbatim()
110    }
111}
112
113impl MayHaveVerbatim for [u8] {
114    fn has_direct_verbatim(&self) -> bool {
115        matches!(self, [b'@', ..])
116    }
117    fn has_verbatim(&self) -> bool {
118        self.split(|c| *c == DELIMITER)
119            .any(MayHaveVerbatim::has_direct_verbatim)
120    }
121    unsafe fn has_direct_verbatim_non_empty(&self) -> bool {
122        unsafe { *self.get_unchecked(0) == b'@' }
123    }
124}