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