1#[cfg(feature = "internal")]
16use alloc::vec::Vec;
17use alloc::{
18 borrow::{Borrow, ToOwned},
19 format,
20 string::String,
21};
22use core::{
23 convert::{TryFrom, TryInto},
24 fmt,
25 ops::{Deref, Div},
26};
27
28use zenoh_result::{anyhow, bail, zerror, Error as ZError, ZResult};
29
30use super::{canon::Canonize, OwnedKeyExpr, OwnedNonWildKeyExpr};
31
32#[allow(non_camel_case_types)]
48#[repr(transparent)]
49#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
50pub struct keyexpr(str);
51
52impl keyexpr {
53 pub fn new<'a, T, E>(t: &'a T) -> Result<&'a Self, E>
60 where
61 &'a Self: TryFrom<&'a T, Error = E>,
62 T: ?Sized,
63 {
64 t.try_into()
65 }
66
67 pub fn autocanonize<'a, T, E>(t: &'a mut T) -> Result<&'a Self, E>
73 where
74 &'a Self: TryFrom<&'a T, Error = E>,
75 T: Canonize + ?Sized,
76 {
77 t.canonize();
78 Self::new(t)
79 }
80
81 pub fn intersects(&self, other: &Self) -> bool {
83 use super::intersect::Intersector;
84 super::intersect::DEFAULT_INTERSECTOR.intersect(self, other)
85 }
86
87 pub fn includes(&self, other: &Self) -> bool {
89 use super::include::Includer;
90 super::include::DEFAULT_INCLUDER.includes(self, other)
91 }
92
93 #[cfg(feature = "unstable")]
97 pub fn relation_to(&self, other: &Self) -> SetIntersectionLevel {
98 use SetIntersectionLevel::*;
99 if self.intersects(other) {
100 if self == other {
101 Equals
102 } else if self.includes(other) {
103 Includes
104 } else {
105 Intersects
106 }
107 } else {
108 Disjoint
109 }
110 }
111
112 pub fn join<S: AsRef<str> + ?Sized>(&self, other: &S) -> ZResult<OwnedKeyExpr> {
127 OwnedKeyExpr::autocanonize(format!("{}/{}", self, other.as_ref()))
128 }
129
130 #[cfg(feature = "internal")]
132 #[doc(hidden)]
133 pub fn is_wild(&self) -> bool {
134 self.is_wild_impl()
135 }
136 pub(crate) fn is_wild_impl(&self) -> bool {
137 self.0.contains(super::SINGLE_WILD as char)
138 }
139
140 pub(crate) const fn is_double_wild(&self) -> bool {
141 let bytes = self.0.as_bytes();
142 bytes.len() == 2 && bytes[0] == b'*'
143 }
144
145 #[cfg(feature = "internal")]
174 #[doc(hidden)]
175 pub fn get_nonwild_prefix(&self) -> Option<&keyexpr> {
176 match self.0.find('*') {
177 Some(i) => match self.0[..i].rfind('/') {
178 Some(j) => unsafe { Some(keyexpr::from_str_unchecked(&self.0[..j])) },
179 None => None, },
181 None => Some(self), }
183 }
184
185 #[cfg(feature = "internal")]
241 #[doc(hidden)]
242 pub fn strip_prefix(&self, prefix: &Self) -> Vec<&keyexpr> {
243 let mut result = alloc::vec![];
244 'chunks: for i in (0..=self.len()).rev() {
245 if if i == self.len() {
246 self.ends_with("**")
247 } else {
248 self.as_bytes()[i] == b'/'
249 } {
250 let sub_part = keyexpr::new(&self[..i]).unwrap();
251 if sub_part.intersects(prefix) {
252 let remaining = if sub_part.ends_with("**") {
254 &self[i - 2..]
255 } else {
256 &self[i + 1..]
257 };
258 let remaining: &keyexpr = if remaining.is_empty() {
259 continue 'chunks;
260 } else {
261 remaining
262 }
263 .try_into()
264 .unwrap();
265 if remaining.as_bytes() == b"**" {
267 result.clear();
268 result.push(unsafe { keyexpr::from_str_unchecked(remaining) });
269 return result;
270 }
271 for i in (0..(result.len())).rev() {
272 if result[i].includes(remaining) {
273 continue 'chunks;
274 }
275 if remaining.includes(result[i]) {
276 result.swap_remove(i);
277 }
278 }
279 result.push(remaining);
280 }
281 }
282 }
283 result
284 }
285
286 #[cfg(feature = "internal")]
291 #[doc(hidden)]
292 pub fn strip_nonwild_prefix(&self, prefix: &nonwild_keyexpr) -> Option<&keyexpr> {
293 fn is_chunk_matching(target: &[u8], prefix: &[u8]) -> bool {
294 let mut target_idx: usize = 0;
295 let mut prefix_idx: usize = 0;
296 let mut target_prev: u8 = b'/';
297 if prefix.first() == Some(&b'@') && target.first() != Some(&b'@') {
298 return false;
300 }
301
302 while target_idx < target.len() && prefix_idx < prefix.len() {
303 if target[target_idx] == b'*' {
304 if target_prev == b'*' || target_idx + 1 == target.len() {
305 return true;
307 } else if target_prev == b'$' {
308 for i in prefix_idx..prefix.len() - 1 {
309 if is_chunk_matching(&target[target_idx + 1..], &prefix[i..]) {
310 return true;
311 }
312 }
313 }
314 } else if target[target_idx] == prefix[prefix_idx] {
315 prefix_idx += 1;
316 } else if target[target_idx] != b'$' {
317 return false;
319 }
320 target_prev = target[target_idx];
321 target_idx += 1;
322 }
323 if prefix_idx != prefix.len() {
324 return false;
326 }
327 target_idx == target.len()
328 || (target_idx + 2 == target.len() && target[target_idx] == b'$')
329 }
330
331 fn strip_nonwild_prefix_inner<'a>(
332 target_bytes: &'a [u8],
333 prefix_bytes: &[u8],
334 ) -> Option<&'a keyexpr> {
335 let mut target_idx = 0;
336 let mut prefix_idx = 0;
337
338 while target_idx < target_bytes.len() && prefix_idx < prefix_bytes.len() {
339 let target_end = target_idx
340 + target_bytes[target_idx..]
341 .iter()
342 .position(|&i| i == b'/')
343 .unwrap_or(target_bytes.len() - target_idx);
344 let prefix_end = prefix_idx
345 + prefix_bytes[prefix_idx..]
346 .iter()
347 .position(|&i| i == b'/')
348 .unwrap_or(prefix_bytes.len() - prefix_idx);
349 let target_chunk = &target_bytes[target_idx..target_end];
350 if target_chunk.len() == 2 && target_chunk[0] == b'*' {
351 let remaining_prefix = &prefix_bytes[prefix_idx..];
352 return match remaining_prefix.iter().position(|&x| x == b'@') {
353 Some(mut p) => {
354 if target_end + 1 >= target_bytes.len() {
355 return None;
357 } else {
358 loop {
359 if let Some(ke) = strip_nonwild_prefix_inner(
361 &target_bytes[(target_end + 1)..],
362 &remaining_prefix[p..],
363 ) {
364 return Some(ke);
365 } else if p == 0 {
366 return None;
368 } else {
369 p -= 2;
371 while p > 0 && remaining_prefix[p - 1] != b'/' {
372 p -= 1;
373 }
374 }
375 }
376 }
377 }
378 None => unsafe {
379 Some(keyexpr::from_str_unchecked(core::str::from_utf8_unchecked(
381 &target_bytes[target_idx..],
382 )))
383 },
384 };
385 }
386 if target_end == target_bytes.len() {
387 return None;
389 }
390 let prefix_chunk = &prefix_bytes[prefix_idx..prefix_end];
391 if !is_chunk_matching(target_chunk, prefix_chunk) {
392 return None;
393 }
394 if prefix_end == prefix_bytes.len() {
395 return unsafe {
397 Some(keyexpr::from_str_unchecked(core::str::from_utf8_unchecked(
398 &target_bytes[(target_end + 1)..],
399 )))
400 };
401 }
402 target_idx = target_end + 1;
403 prefix_idx = prefix_end + 1;
404 }
405 None
406 }
407
408 let target_bytes = self.0.as_bytes();
409 let prefix_bytes = prefix.0.as_bytes();
410
411 strip_nonwild_prefix_inner(target_bytes, prefix_bytes)
412 }
413
414 pub const fn as_str(&self) -> &str {
415 &self.0
416 }
417
418 pub const unsafe fn from_str_unchecked(s: &str) -> &Self {
424 core::mem::transmute(s)
425 }
426
427 pub unsafe fn from_slice_unchecked(s: &[u8]) -> &Self {
433 core::mem::transmute(s)
434 }
435
436 #[cfg(feature = "internal")]
437 #[doc(hidden)]
438 pub const fn chunks(&self) -> Chunks<'_> {
439 self.chunks_impl()
440 }
441 pub(crate) const fn chunks_impl(&self) -> Chunks<'_> {
442 Chunks {
443 inner: self.as_str(),
444 }
445 }
446 pub(crate) fn next_delimiter(&self, i: usize) -> Option<usize> {
447 self.as_str()
448 .get(i + 1..)
449 .and_then(|s| s.find('/').map(|j| i + 1 + j))
450 }
451 pub(crate) fn previous_delimiter(&self, i: usize) -> Option<usize> {
452 self.as_str().get(..i).and_then(|s| s.rfind('/'))
453 }
454 pub(crate) fn first_byte(&self) -> u8 {
455 unsafe { *self.as_bytes().get_unchecked(0) }
456 }
457 pub(crate) fn iter_splits_ltr(&self) -> SplitsLeftToRight<'_> {
458 SplitsLeftToRight {
459 inner: self,
460 index: 0,
461 }
462 }
463 pub(crate) fn iter_splits_rtl(&self) -> SplitsRightToLeft<'_> {
464 SplitsRightToLeft {
465 inner: self,
466 index: self.len(),
467 }
468 }
469}
470#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
471pub(crate) struct SplitsLeftToRight<'a> {
472 inner: &'a keyexpr,
473 index: usize,
474}
475impl<'a> SplitsLeftToRight<'a> {
476 fn right(&self) -> &'a str {
477 &self.inner[self.index + ((self.index != 0) as usize)..]
478 }
479 fn left(&self, followed_by_double: bool) -> &'a str {
480 &self.inner[..(self.index + ((self.index != 0) as usize + 2) * followed_by_double as usize)]
481 }
482}
483impl<'a> Iterator for SplitsLeftToRight<'a> {
484 type Item = (&'a keyexpr, &'a keyexpr);
485 fn next(&mut self) -> Option<Self::Item> {
486 match self.index < self.inner.len() {
487 false => None,
488 true => {
489 let right = self.right();
490 let double_wild = right.starts_with("**");
491 let left = self.left(double_wild);
492 self.index = if left.is_empty() {
493 self.inner.next_delimiter(0).unwrap_or(self.inner.len())
494 } else {
495 self.inner
496 .next_delimiter(left.len())
497 .unwrap_or(self.inner.len() + (left.len() == self.inner.len()) as usize)
498 };
499 if left.is_empty() {
500 self.next()
501 } else {
502 (!right.is_empty()).then(|| unsafe {
504 (
505 keyexpr::from_str_unchecked(left),
506 keyexpr::from_str_unchecked(right),
507 )
508 })
509 }
510 }
511 }
512 }
513}
514#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
515pub(crate) struct SplitsRightToLeft<'a> {
516 inner: &'a keyexpr,
517 index: usize,
518}
519impl<'a> SplitsRightToLeft<'a> {
520 fn right(&self, followed_by_double: bool) -> &'a str {
521 &self.inner[(self.index
522 - ((self.index != self.inner.len()) as usize + 2) * followed_by_double as usize)..]
523 }
524 fn left(&self) -> &'a str {
525 &self.inner[..(self.index - ((self.index != self.inner.len()) as usize))]
526 }
527}
528impl<'a> Iterator for SplitsRightToLeft<'a> {
529 type Item = (&'a keyexpr, &'a keyexpr);
530 fn next(&mut self) -> Option<Self::Item> {
531 match self.index {
532 0 => None,
533 _ => {
534 let left = self.left();
535 let double_wild = left.ends_with("**");
536 let right = self.right(double_wild);
537 self.index = if right.is_empty() {
538 self.inner
539 .previous_delimiter(self.inner.len())
540 .map_or(0, |n| n + 1)
541 } else {
542 self.inner
543 .previous_delimiter(
544 self.inner.len()
545 - right.len()
546 - (self.inner.len() != right.len()) as usize,
547 )
548 .map_or(0, |n| n + 1)
549 };
550 if right.is_empty() {
551 self.next()
552 } else {
553 (!left.is_empty()).then(|| unsafe {
555 (
556 keyexpr::from_str_unchecked(left),
557 keyexpr::from_str_unchecked(right),
558 )
559 })
560 }
561 }
562 }
563 }
564}
565#[test]
566fn splits() {
567 let ke = keyexpr::new("a/**/b/c").unwrap();
568 let mut splits = ke.iter_splits_ltr();
569 assert_eq!(
570 splits.next(),
571 Some((
572 keyexpr::new("a/**").unwrap(),
573 keyexpr::new("**/b/c").unwrap()
574 ))
575 );
576 assert_eq!(
577 splits.next(),
578 Some((keyexpr::new("a/**/b").unwrap(), keyexpr::new("c").unwrap()))
579 );
580 assert_eq!(splits.next(), None);
581 let mut splits = ke.iter_splits_rtl();
582 assert_eq!(
583 splits.next(),
584 Some((keyexpr::new("a/**/b").unwrap(), keyexpr::new("c").unwrap()))
585 );
586 assert_eq!(
587 splits.next(),
588 Some((
589 keyexpr::new("a/**").unwrap(),
590 keyexpr::new("**/b/c").unwrap()
591 ))
592 );
593 assert_eq!(splits.next(), None);
594 let ke = keyexpr::new("**").unwrap();
595 let mut splits = ke.iter_splits_ltr();
596 assert_eq!(
597 splits.next(),
598 Some((keyexpr::new("**").unwrap(), keyexpr::new("**").unwrap()))
599 );
600 assert_eq!(splits.next(), None);
601 let ke = keyexpr::new("ab").unwrap();
602 let mut splits = ke.iter_splits_ltr();
603 assert_eq!(splits.next(), None);
604 let ke = keyexpr::new("ab/cd").unwrap();
605 let mut splits = ke.iter_splits_ltr();
606 assert_eq!(
607 splits.next(),
608 Some((keyexpr::new("ab").unwrap(), keyexpr::new("cd").unwrap()))
609 );
610 assert_eq!(splits.next(), None);
611 for (i, ke) in crate::fuzzer::KeyExprFuzzer(rand::thread_rng())
612 .take(100)
613 .enumerate()
614 {
615 dbg!(i, &ke);
616 let splits = ke.iter_splits_ltr().collect::<Vec<_>>();
617 assert_eq!(splits, {
618 let mut rtl_rev = ke.iter_splits_rtl().collect::<Vec<_>>();
619 rtl_rev.reverse();
620 rtl_rev
621 });
622 assert!(!splits
623 .iter()
624 .any(|s| s.0.ends_with('/') || s.1.starts_with('/')));
625 }
626}
627
628#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
629pub struct Chunks<'a> {
630 inner: &'a str,
631}
632impl<'a> Chunks<'a> {
633 pub const fn as_keyexpr(self) -> Option<&'a keyexpr> {
635 match self.inner.is_empty() {
636 true => None,
637 _ => Some(unsafe { keyexpr::from_str_unchecked(self.inner) }),
638 }
639 }
640 pub fn peek(&self) -> Option<&keyexpr> {
642 if self.inner.is_empty() {
643 None
644 } else {
645 Some(unsafe {
646 keyexpr::from_str_unchecked(
647 &self.inner[..self.inner.find('/').unwrap_or(self.inner.len())],
648 )
649 })
650 }
651 }
652 pub fn peek_back(&self) -> Option<&keyexpr> {
654 if self.inner.is_empty() {
655 None
656 } else {
657 Some(unsafe {
658 keyexpr::from_str_unchecked(
659 &self.inner[self.inner.rfind('/').map_or(0, |i| i + 1)..],
660 )
661 })
662 }
663 }
664}
665impl<'a> Iterator for Chunks<'a> {
666 type Item = &'a keyexpr;
667 fn next(&mut self) -> Option<Self::Item> {
668 if self.inner.is_empty() {
669 return None;
670 }
671 let (next, inner) = self.inner.split_once('/').unwrap_or((self.inner, ""));
672 self.inner = inner;
673 Some(unsafe { keyexpr::from_str_unchecked(next) })
674 }
675}
676impl DoubleEndedIterator for Chunks<'_> {
677 fn next_back(&mut self) -> Option<Self::Item> {
678 if self.inner.is_empty() {
679 return None;
680 }
681 let (inner, next) = self.inner.rsplit_once('/').unwrap_or(("", self.inner));
682 self.inner = inner;
683 Some(unsafe { keyexpr::from_str_unchecked(next) })
684 }
685}
686
687impl Div for &keyexpr {
688 type Output = OwnedKeyExpr;
689 fn div(self, rhs: Self) -> Self::Output {
690 self.join(rhs).unwrap() }
692}
693
694#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
700#[cfg(feature = "unstable")]
701pub enum SetIntersectionLevel {
702 Disjoint,
703 Intersects,
704 Includes,
705 Equals,
706}
707
708#[cfg(feature = "unstable")]
709#[test]
710fn intersection_level_cmp() {
711 use SetIntersectionLevel::*;
712 assert!(Disjoint < Intersects);
713 assert!(Intersects < Includes);
714 assert!(Includes < Equals);
715}
716
717impl fmt::Debug for keyexpr {
718 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719 write!(f, "ke`{}`", self.as_ref())
720 }
721}
722
723impl fmt::Display for keyexpr {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 f.write_str(self)
726 }
727}
728
729#[repr(i8)]
730enum KeyExprError {
731 LoneDollarStar = -1,
732 SingleStarAfterDoubleStar = -2,
733 DoubleStarAfterDoubleStar = -3,
734 EmptyChunk = -4,
735 StarInChunk = -5,
736 DollarAfterDollar = -6,
737 SharpOrQMark = -7,
738 UnboundDollar = -8,
739}
740
741impl KeyExprError {
742 #[cold]
743 fn into_err(self, s: &str) -> ZError {
744 let error = match &self {
745 Self::LoneDollarStar => anyhow!("Invalid Key Expr `{s}`: empty chunks are forbidden, as well as leading and trailing slashes"),
746 Self::SingleStarAfterDoubleStar => anyhow!("Invalid Key Expr `{s}`: `**/*` must be replaced by `*/**` to reach canon-form"),
747 Self::DoubleStarAfterDoubleStar => anyhow!("Invalid Key Expr `{s}`: `**/**` must be replaced by `**` to reach canon-form"),
748 Self::EmptyChunk => anyhow!("Invalid Key Expr `{s}`: empty chunks are forbidden, as well as leading and trailing slashes"),
749 Self::StarInChunk => anyhow!("Invalid Key Expr `{s}`: `*` may only be preceded by `/` or `$`"),
750 Self::DollarAfterDollar => anyhow!("Invalid Key Expr `{s}`: `$` is not allowed after `$*`"),
751 Self::SharpOrQMark => anyhow!("Invalid Key Expr `{s}`: `#` and `?` are forbidden characters"),
752 Self::UnboundDollar => anyhow!("Invalid Key Expr `{s}`: `$` is only allowed in `$*`")
753 };
754 zerror!((self) error).into()
755 }
756}
757
758impl<'a> TryFrom<&'a str> for &'a keyexpr {
759 type Error = ZError;
760
761 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
762 use KeyExprError::*;
763 if value.is_empty() || value.ends_with('/') {
765 return Err(EmptyChunk.into_err(value));
766 }
767 let bytes = value.as_bytes();
768 let mut chunk_start = 0;
770 let mut i = 0;
773 while i < bytes.len() {
774 match bytes[i] {
775 c if c > b'/' && c != b'?' => i += 1,
779 b'/' if i == chunk_start => return Err(EmptyChunk.into_err(value)),
781 b'/' => {
783 i += 1;
784 chunk_start = i;
785 }
786 b'*' if i != chunk_start => return Err(StarInChunk.into_err(value)),
788 b'*' => match bytes.get(i + 1) {
792 None => break,
794 Some(&b'/') => {
797 i += 2;
798 chunk_start = i;
799 }
800 Some(&b'*') => match bytes.get(i + 2) {
802 None => break,
804 Some(&b'/') if matches!(bytes.get(i + 3), Some(b'*')) => {
807 #[cold]
810 fn double_star_err(value: &str, i: usize) -> ZError {
811 match (value.as_bytes().get(i + 4), value.as_bytes().get(i + 5)) {
812 (None | Some(&b'/'), _) => SingleStarAfterDoubleStar,
813 (Some(&b'*'), None | Some(&b'/')) => DoubleStarAfterDoubleStar,
814 _ => StarInChunk,
815 }
816 .into_err(value)
817 }
818 return Err(double_star_err(value, i));
819 }
820 Some(&b'/') => {
823 i += 3;
824 chunk_start = i;
825 }
826 _ => return Err(StarInChunk.into_err(value)),
828 },
829 _ => return Err(StarInChunk.into_err(value)),
831 },
832 b'$' if bytes.get(i + 1) != Some(&b'*') => {
834 return Err(UnboundDollar.into_err(value))
835 }
836 b'$' => match bytes.get(i + 2) {
838 Some(&b'$') => return Err(DollarAfterDollar.into_err(value)),
840 Some(&b'/') | None if i == chunk_start => {
842 return Err(LoneDollarStar.into_err(value))
843 }
844 None => break,
846 _ => i += 2,
848 },
849 b'#' | b'?' => return Err(SharpOrQMark.into_err(value)),
851 _ => i += 1,
853 }
854 }
855 Ok(unsafe { keyexpr::from_str_unchecked(value) })
856 }
857}
858
859impl<'a> TryFrom<&'a mut str> for &'a keyexpr {
860 type Error = ZError;
861 fn try_from(value: &'a mut str) -> Result<Self, Self::Error> {
862 (value as &'a str).try_into()
863 }
864}
865
866impl<'a> TryFrom<&'a mut String> for &'a keyexpr {
867 type Error = ZError;
868 fn try_from(value: &'a mut String) -> Result<Self, Self::Error> {
869 (value.as_str()).try_into()
870 }
871}
872
873impl<'a> TryFrom<&'a String> for &'a keyexpr {
874 type Error = ZError;
875 fn try_from(value: &'a String) -> Result<Self, Self::Error> {
876 (value.as_str()).try_into()
877 }
878}
879impl<'a> TryFrom<&'a &'a str> for &'a keyexpr {
880 type Error = ZError;
881 fn try_from(value: &'a &'a str) -> Result<Self, Self::Error> {
882 (*value).try_into()
883 }
884}
885impl<'a> TryFrom<&'a &'a mut str> for &'a keyexpr {
886 type Error = ZError;
887 fn try_from(value: &'a &'a mut str) -> Result<Self, Self::Error> {
888 keyexpr::new(*value)
889 }
890}
891#[test]
892fn autocanon() {
893 let mut s: Box<str> = Box::from("hello/**/*");
894 let mut s: &mut str = &mut s;
895 assert_eq!(keyexpr::autocanonize(&mut s).unwrap(), "hello/*/**");
896}
897
898impl Deref for keyexpr {
899 type Target = str;
900 fn deref(&self) -> &Self::Target {
901 unsafe { core::mem::transmute(self) }
902 }
903}
904impl AsRef<str> for keyexpr {
905 fn as_ref(&self) -> &str {
906 self
907 }
908}
909
910impl PartialEq<str> for keyexpr {
911 fn eq(&self, other: &str) -> bool {
912 self.as_str() == other
913 }
914}
915
916impl PartialEq<keyexpr> for str {
917 fn eq(&self, other: &keyexpr) -> bool {
918 self == other.as_str()
919 }
920}
921
922impl Borrow<keyexpr> for OwnedKeyExpr {
923 fn borrow(&self) -> &keyexpr {
924 self
925 }
926}
927impl ToOwned for keyexpr {
928 type Owned = OwnedKeyExpr;
929 fn to_owned(&self) -> Self::Owned {
930 OwnedKeyExpr::from(self)
931 }
932}
933
934#[allow(non_camel_case_types)]
936#[repr(transparent)]
937#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
938pub struct nonwild_keyexpr(keyexpr);
939
940impl nonwild_keyexpr {
941 pub fn new<'a, T, E>(t: &'a T) -> Result<&'a Self, ZError>
945 where
946 &'a keyexpr: TryFrom<&'a T, Error = E>,
947 E: Into<ZError>,
948 T: ?Sized,
949 {
950 let ke: &'a keyexpr = t.try_into().map_err(|e: E| e.into())?;
951 ke.try_into()
952 }
953
954 pub const unsafe fn from_str_unchecked(s: &str) -> &Self {
960 core::mem::transmute(s)
961 }
962}
963
964impl Deref for nonwild_keyexpr {
965 type Target = keyexpr;
966 fn deref(&self) -> &Self::Target {
967 &self.0
968 }
969}
970
971impl<'a> TryFrom<&'a keyexpr> for &'a nonwild_keyexpr {
972 type Error = ZError;
973 fn try_from(value: &'a keyexpr) -> Result<Self, Self::Error> {
974 if value.is_wild_impl() {
975 bail!("nonwild_keyexpr can not contain any wild chunks")
976 }
977 Ok(unsafe { core::mem::transmute::<&keyexpr, &nonwild_keyexpr>(value) })
978 }
979}
980
981impl Borrow<nonwild_keyexpr> for OwnedNonWildKeyExpr {
982 fn borrow(&self) -> &nonwild_keyexpr {
983 self
984 }
985}
986
987impl ToOwned for nonwild_keyexpr {
988 type Owned = OwnedNonWildKeyExpr;
989 fn to_owned(&self) -> Self::Owned {
990 OwnedNonWildKeyExpr::from(self)
991 }
992}
993
994#[cfg(feature = "internal")]
995#[test]
996fn test_keyexpr_strip_prefix() {
997 let expectations = [
998 (("demo/example/test/**", "demo/example/test"), &["**"][..]),
999 (("demo/example/**", "demo/example/test"), &["**"]),
1000 (("**", "demo/example/test"), &["**"]),
1001 (
1002 ("demo/example/test/**/x$*/**", "demo/example/test"),
1003 &["**/x$*/**"],
1004 ),
1005 (("demo/**/xyz", "demo/example/test"), &["**/xyz"]),
1006 (("demo/**/test/**", "demo/example/test"), &["**"]),
1007 (
1008 ("demo/**/ex$*/*/xyz", "demo/example/test"),
1009 ["xyz", "**/ex$*/*/xyz"].as_ref(),
1010 ),
1011 (
1012 ("demo/**/ex$*/t$*/xyz", "demo/example/test"),
1013 ["xyz", "**/ex$*/t$*/xyz"].as_ref(),
1014 ),
1015 (
1016 ("demo/**/te$*/*/xyz", "demo/example/test"),
1017 ["*/xyz", "**/te$*/*/xyz"].as_ref(),
1018 ),
1019 (("demo/example/test", "demo/example/test"), [].as_ref()),
1020 ]
1021 .map(|((a, b), expected)| {
1022 (
1023 (keyexpr::new(a).unwrap(), keyexpr::new(b).unwrap()),
1024 expected
1025 .iter()
1026 .map(|s| keyexpr::new(*s).unwrap())
1027 .collect::<Vec<_>>(),
1028 )
1029 });
1030 for ((ke, prefix), expected) in expectations {
1031 dbg!(ke, prefix);
1032 assert_eq!(ke.strip_prefix(prefix), expected)
1033 }
1034}
1035
1036#[cfg(feature = "internal")]
1037#[test]
1038fn test_keyexpr_strip_nonwild_prefix() {
1039 let expectations = [
1040 (("demo/example/test/**", "demo/example/test"), Some("**")),
1041 (("demo/example/**", "demo/example/test"), Some("**")),
1042 (("**", "demo/example/test"), Some("**")),
1043 (("*/example/test/1", "demo/example/test"), Some("1")),
1044 (("demo/*/test/1", "demo/example/test"), Some("1")),
1045 (("*/*/test/1", "demo/example/test"), Some("1")),
1046 (("*/*/*/1", "demo/example/test"), Some("1")),
1047 (("*/test/1", "demo/example/test"), None),
1048 (("*/*/1", "demo/example/test"), None),
1049 (("*/*/**", "demo/example/test"), Some("**")),
1050 (
1051 ("demo/example/test/**/x$*/**", "demo/example/test"),
1052 Some("**/x$*/**"),
1053 ),
1054 (("demo/**/xyz", "demo/example/test"), Some("**/xyz")),
1055 (("demo/**/test/**", "demo/example/test"), Some("**/test/**")),
1056 (
1057 ("demo/**/ex$*/*/xyz", "demo/example/test"),
1058 Some("**/ex$*/*/xyz"),
1059 ),
1060 (
1061 ("demo/**/ex$*/t$*/xyz", "demo/example/test"),
1062 Some("**/ex$*/t$*/xyz"),
1063 ),
1064 (
1065 ("demo/**/te$*/*/xyz", "demo/example/test"),
1066 Some("**/te$*/*/xyz"),
1067 ),
1068 (("demo/example/test", "demo/example/test"), None),
1069 (("demo/example/test1/something", "demo/example/test"), None),
1070 (
1071 ("demo/example/test$*/something", "demo/example/test"),
1072 Some("something"),
1073 ),
1074 (("*/example/test/something", "@demo/example/test"), None),
1075 (("**/test/something", "@demo/example/test"), None),
1076 (("**/test/something", "demo/example/@test"), None),
1077 (
1078 ("@demo/*/test/something", "@demo/example/test"),
1079 Some("something"),
1080 ),
1081 (("@demo/*/test/something", "@demo/@example/test"), None),
1082 (("**/@demo/test/something", "@demo/test"), Some("something")),
1083 (("**/@test/something", "demo/@test"), Some("something")),
1084 (
1085 ("@demo/**/@test/something", "@demo/example/@test"),
1086 Some("something"),
1087 ),
1088 ]
1089 .map(|((a, b), expected)| {
1090 (
1091 (keyexpr::new(a).unwrap(), nonwild_keyexpr::new(b).unwrap()),
1092 expected.map(|t| keyexpr::new(t).unwrap()),
1093 )
1094 });
1095 for ((ke, prefix), expected) in expectations {
1096 dbg!(ke, prefix);
1097 assert_eq!(ke.strip_nonwild_prefix(prefix), expected)
1098 }
1099}
1100
1101#[cfg(test)]
1102mod tests {
1103 use test_case::test_case;
1104 use zenoh_result::ErrNo;
1105
1106 use crate::{
1107 key_expr::borrowed::{KeyExprError, KeyExprError::*},
1108 keyexpr,
1109 };
1110
1111 #[test_case("", EmptyChunk; "Empty")]
1112 #[test_case("demo/example/test", None; "Normal key_expr")]
1113 #[test_case("demo/*", None; "Single star at the end")]
1114 #[test_case("demo/**", None; "Double star at the end")]
1115 #[test_case("demo/*/*/test", None; "Single star after single star")]
1116 #[test_case("demo/*/**/test", None; "Double star after single star")]
1117 #[test_case("demo/example$*/test", None; "Dollar with star")]
1118 #[test_case("demo/example$*-$*/test", None; "Multiple dollar with star")]
1119 #[test_case("/demo/example/test", EmptyChunk; "Leading /")]
1120 #[test_case("demo/example/test/", EmptyChunk; "Trailing /")]
1121 #[test_case("demo/$*/test", LoneDollarStar; "Lone $*")]
1122 #[test_case("demo/$*", LoneDollarStar; "Lone $* at the end")]
1123 #[test_case("demo/example$*", None; "Trailing lone $*")]
1124 #[test_case("demo/**/*/test", SingleStarAfterDoubleStar; "Single star after double star")]
1125 #[test_case("demo/**/**/test", DoubleStarAfterDoubleStar; "Double star after double star")]
1126 #[test_case("demo//test", EmptyChunk; "Empty Chunk")]
1127 #[test_case("demo/exam*ple/test", StarInChunk; "Star in chunk")]
1128 #[test_case("demo/example$*$/test", DollarAfterDollar; "Dollar after dollar or star")]
1129 #[test_case("demo/example$*$*/test", DollarAfterDollar; "Dollar star after dollar or star")]
1130 #[test_case("demo/example#/test", SharpOrQMark; "Contain sharp")]
1131 #[test_case("demo/example?/test", SharpOrQMark; "Contain mark")]
1132 #[test_case("demo/$/test", UnboundDollar; "Contain unbounded dollar")]
1133 fn test_keyexpr_new(key_str: &str, error: impl Into<Option<KeyExprError>>) {
1134 assert_eq!(
1135 keyexpr::new(key_str).err().map(|err| {
1136 err.downcast_ref::<zenoh_result::ZError>()
1137 .unwrap()
1138 .errno()
1139 .get()
1140 }),
1141 error.into().map(|err| err as i8)
1142 );
1143 }
1144}