Skip to content

Commit

Permalink
Verbatim chunks for Key Expressions (#655)
Browse files Browse the repository at this point in the history
* implement key expression namespaces

* implement verbatim chunks

* fix bug in includes

---------

Co-authored-by: Pierre Avital <[email protected]>
  • Loading branch information
p-avital and Pierre Avital authored Jan 23, 2024
1 parent 05c7a3e commit c6d7257
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 11 deletions.
17 changes: 13 additions & 4 deletions commons/zenoh-keyexpr/src/key_expr/include.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Contributors:
// ZettaScale Zenoh Team, <[email protected]>
//
use super::{keyexpr, utils::Split, DELIMITER, DOUBLE_WILD, STAR_DSL};
use super::{intersect::MayHaveVerbatim, keyexpr, utils::Split, DELIMITER, DOUBLE_WILD, STAR_DSL};

pub const DEFAULT_INCLUDER: LTRIncluder = LTRIncluder;

Expand All @@ -24,7 +24,7 @@ impl<T: for<'a> Includer<&'a [u8], &'a [u8]>> Includer<&keyexpr, &keyexpr> for T
fn includes(&self, left: &keyexpr, right: &keyexpr) -> bool {
let left = left.as_bytes();
let right = right.as_bytes();
if left == right || left == b"**" {
if left == right {
return true;
}
self.includes(left, right)
Expand All @@ -38,9 +38,12 @@ impl Includer<&[u8], &[u8]> for LTRIncluder {
let (lchunk, lrest) = left.split_once(&DELIMITER);
let lempty = lrest.is_empty();
if lchunk == DOUBLE_WILD {
if lempty || self.includes(lrest, right) {
if (lempty && !right.has_verbatim()) || (!lempty && self.includes(lrest, right)) {
return true;
}
if unsafe { right.has_direct_verbatim_non_empty() } {
return false;
}
right = right.split_once(&DELIMITER).1;
if right.is_empty() {
return false;
Expand All @@ -66,7 +69,13 @@ impl Includer<&[u8], &[u8]> for LTRIncluder {

impl LTRIncluder {
fn non_double_wild_chunk_includes(&self, lchunk: &[u8], rchunk: &[u8]) -> bool {
if lchunk == b"*" || lchunk == rchunk {
if lchunk == rchunk {
true
} else if unsafe {
lchunk.has_direct_verbatim_non_empty() || rchunk.has_direct_verbatim_non_empty()
} {
false
} else if lchunk == b"*" {
true
} else if lchunk.contains(&b'$') {
let mut spleft = lchunk.splitter(STAR_DSL);
Expand Down
23 changes: 16 additions & 7 deletions commons/zenoh-keyexpr/src/key_expr/intersect/classical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ fn chunk_intersect<const STAR_DSL: bool>(c1: &[u8], c2: &[u8]) -> bool {
if c1 == c2 {
return true;
}
if c1.has_direct_verbatim() || c2.has_direct_verbatim() {
return false;
}
chunk_it_intersect::<STAR_DSL>(c1, c2)
}

Expand All @@ -83,14 +86,20 @@ fn it_intersect<const STAR_DSL: bool>(mut it1: &[u8], mut it2: &[u8]) -> bool {
let (current2, advanced2) = next(it2);
match (current1, current2) {
(b"**", _) => {
return advanced1.is_empty()
|| it_intersect::<STAR_DSL>(advanced1, it2)
|| it_intersect::<STAR_DSL>(it1, advanced2);
if advanced1.is_empty() {
return !it2.has_verbatim();
}
return (!unsafe { current2.has_direct_verbatim_non_empty() }
&& it_intersect::<STAR_DSL>(it1, advanced2))
|| it_intersect::<STAR_DSL>(advanced1, it2);
}
(_, b"**") => {
return advanced2.is_empty()
|| it_intersect::<STAR_DSL>(it1, advanced2)
|| it_intersect::<STAR_DSL>(advanced1, it2);
if advanced2.is_empty() {
return !it1.has_verbatim();
}
return (!unsafe { current1.has_direct_verbatim_non_empty() }
&& it_intersect::<STAR_DSL>(advanced1, it2))
|| it_intersect::<STAR_DSL>(it1, advanced2);
}
(sub1, sub2) if chunk_intersect::<STAR_DSL>(sub1, sub2) => {
it1 = advanced1;
Expand All @@ -111,7 +120,7 @@ pub fn intersect<const STAR_DSL: bool>(s1: &[u8], s2: &[u8]) -> bool {
}

use super::restiction::NoSubWilds;
use super::Intersector;
use super::{Intersector, MayHaveVerbatim};

pub struct ClassicIntersector;
impl Intersector<NoSubWilds<&[u8]>, NoSubWilds<&[u8]>> for ClassicIntersector {
Expand Down
23 changes: 23 additions & 0 deletions commons/zenoh-keyexpr/src/key_expr/intersect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// ZettaScale Zenoh Team, <[email protected]>
//

use crate::DELIMITER;

use super::keyexpr;

mod classical;
Expand Down Expand Up @@ -100,3 +102,24 @@ impl<
}
}
}

pub(crate) trait MayHaveVerbatim {
fn has_verbatim(&self) -> bool;
fn has_direct_verbatim(&self) -> bool;
unsafe fn has_direct_verbatim_non_empty(&self) -> bool {
self.has_direct_verbatim()
}
}

impl MayHaveVerbatim for [u8] {
fn has_direct_verbatim(&self) -> bool {
matches!(self, [b'@', ..])
}
fn has_verbatim(&self) -> bool {
self.split(|c| *c == DELIMITER)
.any(MayHaveVerbatim::has_direct_verbatim)
}
unsafe fn has_direct_verbatim_non_empty(&self) -> bool {
unsafe { *self.get_unchecked(0) == b'@' }
}
}
39 changes: 39 additions & 0 deletions commons/zenoh-keyexpr/src/key_expr/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,30 @@ fn intersections() {
assert!(intersect("x/a$*d$*e", "x/ade"));
assert!(!intersect("x/c$*", "x/abc$*"));
assert!(!intersect("x/$*d", "x/$*e"));

assert!(intersect("@a", "@a"));
assert!(!intersect("@a", "@ab"));
assert!(!intersect("@a", "@a/b"));
assert!(!intersect("@a", "@a/*"));
assert!(!intersect("@a", "@a/*/**"));
assert!(!intersect("@a", "@a$*/**"));
assert!(intersect("@a", "@a/**"));
assert!(!intersect("**/xyz$*xyz", "@a/b/xyzdefxyz"));
assert!(intersect("@a/**/c/**/e", "@a/b/b/b/c/d/d/d/e"));
assert!(!intersect("@a/**/c/**/e", "@a/@b/b/b/c/d/d/d/e"));
assert!(intersect("@a/**/@c/**/e", "@a/b/b/b/@c/d/d/d/e"));
assert!(intersect("@a/**/e", "@a/b/b/d/d/d/e"));
assert!(intersect("@a/**/e", "@a/b/b/b/d/d/d/e"));
assert!(intersect("@a/**/e", "@a/b/b/c/d/d/d/e"));
assert!(!intersect("@a/**/e", "@a/b/b/@c/b/d/d/d/e"));
assert!(!intersect("@a/*", "@a/@b"));
assert!(!intersect("@a/**", "@a/@b"));
assert!(intersect("@a/**/@b", "@a/@b"));
assert!(intersect("@a/@b/**", "@a/@b"));
assert!(intersect("@a/**/@c/**/@b", "@a/**/@c/@b"));
assert!(intersect("@a/**/@c/**/@b", "@a/@c/**/@b"));
assert!(intersect("@a/**/@c/@b", "@a/@c/**/@b"));
assert!(!intersect("@a/**/@b", "@a/**/@c/**/@b"));
}

fn includes<
Expand Down Expand Up @@ -146,6 +170,21 @@ fn inclusions() {
assert!(!includes("x/c$*", "x/abc$*"));
assert!(includes("x/$*c$*", "x/abc$*"));
assert!(!includes("x/$*d", "x/$*e"));

assert!(includes("@a", "@a"));
assert!(!includes("@a", "@ab"));
assert!(!includes("@a", "@a/b"));
assert!(!includes("@a", "@a/*"));
assert!(!includes("@a", "@a/*/**"));
assert!(!includes("@a$*/**", "@a"));
assert!(!includes("@a", "@a/**"));
assert!(includes("@a/**", "@a"));
assert!(!includes("**/xyz$*xyz", "@a/b/xyzdefxyz"));
assert!(includes("@a/**/c/**/e", "@a/b/b/b/c/d/d/d/e"));
assert!(!includes("@a/*", "@a/@b"));
assert!(!includes("@a/**", "@a/@b"));
assert!(includes("@a/**/@b", "@a/@b"));
assert!(includes("@a/@b/**", "@a/@b"));
}

#[test]
Expand Down

0 comments on commit c6d7257

Please sign in to comment.