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])) },
180 None => None, },
182 None => Some(self), }
184 }
185
186 #[cfg(feature = "internal")]
242 #[doc(hidden)]
243 pub fn strip_prefix(&self, prefix: &Self) -> Vec<&keyexpr> {
244 let mut result = alloc::vec![];
245 'chunks: for i in (0..=self.len()).rev() {
246 if if i == self.len() {
247 self.ends_with("**")
248 } else {
249 self.as_bytes()[i] == b'/'
250 } {
251 let sub_part = keyexpr::new(&self[..i]).unwrap();
252 if sub_part.intersects(prefix) {
253 let remaining = if sub_part.ends_with("**") {
255 &self[i - 2..]
256 } else {
257 &self[i + 1..]
258 };
259 let remaining: &keyexpr = if remaining.is_empty() {
260 continue 'chunks;
261 } else {
262 remaining
263 }
264 .try_into()
265 .unwrap();
266 if remaining.as_bytes() == b"**" {
268 result.clear();
269 result.push(unsafe { keyexpr::from_str_unchecked(remaining) });
271 return result;
272 }
273 for i in (0..(result.len())).rev() {
274 if result[i].includes(remaining) {
275 continue 'chunks;
276 }
277 if remaining.includes(result[i]) {
278 result.swap_remove(i);
279 }
280 }
281 result.push(remaining);
282 }
283 }
284 }
285 result
286 }
287
288 #[cfg(feature = "internal")]
293 #[doc(hidden)]
294 pub fn strip_nonwild_prefix(&self, prefix: &nonwild_keyexpr) -> Option<&keyexpr> {
295 fn is_chunk_matching(target: &[u8], prefix: &[u8]) -> bool {
296 let mut target_idx: usize = 0;
297 let mut prefix_idx: usize = 0;
298 let mut target_prev: u8 = b'/';
299 if prefix.first() == Some(&b'@') && target.first() != Some(&b'@') {
300 return false;
302 }
303
304 while target_idx < target.len() && prefix_idx < prefix.len() {
305 if target[target_idx] == b'*' {
306 if target_prev == b'*' || target_idx + 1 == target.len() {
307 return true;
309 } else if target_prev == b'$' {
310 for i in prefix_idx..prefix.len() - 1 {
311 if is_chunk_matching(&target[target_idx + 1..], &prefix[i..]) {
312 return true;
313 }
314 }
315 }
316 } else if target[target_idx] == prefix[prefix_idx] {
317 prefix_idx += 1;
318 } else if target[target_idx] != b'$' {
319 return false;
321 }
322 target_prev = target[target_idx];
323 target_idx += 1;
324 }
325 if prefix_idx != prefix.len() {
326 return false;
328 }
329 target_idx == target.len()
330 || (target_idx + 2 == target.len() && target[target_idx] == b'$')
331 }
332
333 fn strip_nonwild_prefix_inner<'a>(
334 target_bytes: &'a [u8],
335 prefix_bytes: &[u8],
336 ) -> Option<&'a keyexpr> {
337 let mut target_idx = 0;
338 let mut prefix_idx = 0;
339
340 while target_idx < target_bytes.len() && prefix_idx < prefix_bytes.len() {
341 let target_end = target_idx
342 + target_bytes[target_idx..]
343 .iter()
344 .position(|&i| i == b'/')
345 .unwrap_or(target_bytes.len() - target_idx);
346 let prefix_end = prefix_idx
347 + prefix_bytes[prefix_idx..]
348 .iter()
349 .position(|&i| i == b'/')
350 .unwrap_or(prefix_bytes.len() - prefix_idx);
351 let target_chunk = &target_bytes[target_idx..target_end];
352 if target_chunk.len() == 2 && target_chunk[0] == b'*' {
353 let remaining_prefix = &prefix_bytes[prefix_idx..];
354 return match remaining_prefix.iter().position(|&x| x == b'@') {
355 Some(mut p) => {
356 if target_end + 1 >= target_bytes.len() {
357 return None;
359 } else {
360 loop {
361 if let Some(ke) = strip_nonwild_prefix_inner(
363 &target_bytes[(target_end + 1)..],
364 &remaining_prefix[p..],
365 ) {
366 return Some(ke);
367 } else if p == 0 {
368 return None;
370 } else {
371 p -= 2;
373 while p > 0 && remaining_prefix[p - 1] != b'/' {
374 p -= 1;
375 }
376 }
377 }
378 }
379 }
380 None => unsafe {
382 Some(keyexpr::from_str_unchecked(core::str::from_utf8_unchecked(
384 &target_bytes[target_idx..],
385 )))
386 },
387 };
388 }
389 if target_end == target_bytes.len() {
390 return None;
392 }
393 let prefix_chunk = &prefix_bytes[prefix_idx..prefix_end];
394 if !is_chunk_matching(target_chunk, prefix_chunk) {
395 return None;
396 }
397 if prefix_end == prefix_bytes.len() {
398 return unsafe {
400 Some(keyexpr::from_str_unchecked(core::str::from_utf8_unchecked(
401 &target_bytes[(target_end + 1)..],
402 )))
403 };
404 }
405 target_idx = target_end + 1;
406 prefix_idx = prefix_end + 1;
407 }
408 None
409 }
410
411 let target_bytes = self.0.as_bytes();
412 let prefix_bytes = prefix.0.as_bytes();
413
414 strip_nonwild_prefix_inner(target_bytes, prefix_bytes)
415 }
416
417 pub const fn as_str(&self) -> &str {
418 &self.0
419 }
420
421 pub const unsafe fn from_str_unchecked(s: &str) -> &Self {
427 unsafe { core::mem::transmute(s) }
429 }
430
431 pub unsafe fn from_slice_unchecked(s: &[u8]) -> &Self {
437 unsafe { core::mem::transmute(s) }
439 }
440
441 #[cfg(feature = "internal")]
442 #[doc(hidden)]
443 pub const fn chunks(&self) -> Chunks<'_> {
444 self.chunks_impl()
445 }
446 pub(crate) const fn chunks_impl(&self) -> Chunks<'_> {
447 Chunks {
448 inner: self.as_str(),
449 }
450 }
451 pub(crate) fn next_delimiter(&self, i: usize) -> Option<usize> {
452 self.as_str()
453 .get(i + 1..)
454 .and_then(|s| s.find('/').map(|j| i + 1 + j))
455 }
456 pub(crate) fn previous_delimiter(&self, i: usize) -> Option<usize> {
457 self.as_str().get(..i).and_then(|s| s.rfind('/'))
458 }
459 pub(crate) fn first_byte(&self) -> u8 {
460 unsafe { *self.as_bytes().get_unchecked(0) }
462 }
463 pub(crate) fn iter_splits_ltr(&self) -> SplitsLeftToRight<'_> {
464 SplitsLeftToRight {
465 inner: self,
466 index: 0,
467 }
468 }
469 pub(crate) fn iter_splits_rtl(&self) -> SplitsRightToLeft<'_> {
470 SplitsRightToLeft {
471 inner: self,
472 index: self.len(),
473 }
474 }
475}
476#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
477pub(crate) struct SplitsLeftToRight<'a> {
478 inner: &'a keyexpr,
479 index: usize,
480}
481impl<'a> SplitsLeftToRight<'a> {
482 fn right(&self) -> &'a str {
483 &self.inner[self.index + ((self.index != 0) as usize)..]
484 }
485 fn left(&self, followed_by_double: bool) -> &'a str {
486 &self.inner[..(self.index + ((self.index != 0) as usize + 2) * followed_by_double as usize)]
487 }
488}
489impl<'a> Iterator for SplitsLeftToRight<'a> {
490 type Item = (&'a keyexpr, &'a keyexpr);
491 fn next(&mut self) -> Option<Self::Item> {
492 match self.index < self.inner.len() {
493 false => None,
494 true => {
495 let right = self.right();
496 let double_wild = right.starts_with("**");
497 let left = self.left(double_wild);
498 self.index = if left.is_empty() {
499 self.inner.next_delimiter(0).unwrap_or(self.inner.len())
500 } else {
501 self.inner
502 .next_delimiter(left.len())
503 .unwrap_or(self.inner.len() + (left.len() == self.inner.len()) as usize)
504 };
505 if left.is_empty() {
506 self.next()
507 } else {
508 (!right.is_empty()).then(|| unsafe {
510 (
511 keyexpr::from_str_unchecked(left),
512 keyexpr::from_str_unchecked(right),
513 )
514 })
515 }
516 }
517 }
518 }
519}
520#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
521pub(crate) struct SplitsRightToLeft<'a> {
522 inner: &'a keyexpr,
523 index: usize,
524}
525impl<'a> SplitsRightToLeft<'a> {
526 fn right(&self, followed_by_double: bool) -> &'a str {
527 &self.inner[(self.index
528 - ((self.index != self.inner.len()) as usize + 2) * followed_by_double as usize)..]
529 }
530 fn left(&self) -> &'a str {
531 &self.inner[..(self.index - ((self.index != self.inner.len()) as usize))]
532 }
533}
534impl<'a> Iterator for SplitsRightToLeft<'a> {
535 type Item = (&'a keyexpr, &'a keyexpr);
536 fn next(&mut self) -> Option<Self::Item> {
537 match self.index {
538 0 => None,
539 _ => {
540 let left = self.left();
541 let double_wild = left.ends_with("**");
542 let right = self.right(double_wild);
543 self.index = if right.is_empty() {
544 self.inner
545 .previous_delimiter(self.inner.len())
546 .map_or(0, |n| n + 1)
547 } else {
548 self.inner
549 .previous_delimiter(
550 self.inner.len()
551 - right.len()
552 - (self.inner.len() != right.len()) as usize,
553 )
554 .map_or(0, |n| n + 1)
555 };
556 if right.is_empty() {
557 self.next()
558 } else {
559 (!left.is_empty()).then(|| unsafe {
561 (
562 keyexpr::from_str_unchecked(left),
563 keyexpr::from_str_unchecked(right),
564 )
565 })
566 }
567 }
568 }
569 }
570}
571#[test]
572fn splits() {
573 let ke = keyexpr::new("a/**/b/c").unwrap();
574 let mut splits = ke.iter_splits_ltr();
575 assert_eq!(
576 splits.next(),
577 Some((
578 keyexpr::new("a/**").unwrap(),
579 keyexpr::new("**/b/c").unwrap()
580 ))
581 );
582 assert_eq!(
583 splits.next(),
584 Some((keyexpr::new("a/**/b").unwrap(), keyexpr::new("c").unwrap()))
585 );
586 assert_eq!(splits.next(), None);
587 let mut splits = ke.iter_splits_rtl();
588 assert_eq!(
589 splits.next(),
590 Some((keyexpr::new("a/**/b").unwrap(), keyexpr::new("c").unwrap()))
591 );
592 assert_eq!(
593 splits.next(),
594 Some((
595 keyexpr::new("a/**").unwrap(),
596 keyexpr::new("**/b/c").unwrap()
597 ))
598 );
599 assert_eq!(splits.next(), None);
600 let ke = keyexpr::new("**").unwrap();
601 let mut splits = ke.iter_splits_ltr();
602 assert_eq!(
603 splits.next(),
604 Some((keyexpr::new("**").unwrap(), keyexpr::new("**").unwrap()))
605 );
606 assert_eq!(splits.next(), None);
607 let ke = keyexpr::new("ab").unwrap();
608 let mut splits = ke.iter_splits_ltr();
609 assert_eq!(splits.next(), None);
610 let ke = keyexpr::new("ab/cd").unwrap();
611 let mut splits = ke.iter_splits_ltr();
612 assert_eq!(
613 splits.next(),
614 Some((keyexpr::new("ab").unwrap(), keyexpr::new("cd").unwrap()))
615 );
616 assert_eq!(splits.next(), None);
617 for (i, ke) in crate::fuzzer::KeyExprFuzzer(rand::thread_rng())
618 .take(100)
619 .enumerate()
620 {
621 dbg!(i, &ke);
622 let splits = ke.iter_splits_ltr().collect::<Vec<_>>();
623 assert_eq!(splits, {
624 let mut rtl_rev = ke.iter_splits_rtl().collect::<Vec<_>>();
625 rtl_rev.reverse();
626 rtl_rev
627 });
628 assert!(!splits
629 .iter()
630 .any(|s| s.0.ends_with('/') || s.1.starts_with('/')));
631 }
632}
633
634#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
635pub struct Chunks<'a> {
636 inner: &'a str,
637}
638impl<'a> Chunks<'a> {
639 pub const fn as_keyexpr(self) -> Option<&'a keyexpr> {
641 match self.inner.is_empty() {
642 true => None,
643 _ => Some(unsafe { keyexpr::from_str_unchecked(self.inner) }),
645 }
646 }
647 pub fn peek(&self) -> Option<&keyexpr> {
649 if self.inner.is_empty() {
650 None
651 } else {
652 Some(unsafe {
654 keyexpr::from_str_unchecked(
655 &self.inner[..self.inner.find('/').unwrap_or(self.inner.len())],
656 )
657 })
658 }
659 }
660 pub fn peek_back(&self) -> Option<&keyexpr> {
662 if self.inner.is_empty() {
663 None
664 } else {
665 Some(unsafe {
667 keyexpr::from_str_unchecked(
668 &self.inner[self.inner.rfind('/').map_or(0, |i| i + 1)..],
669 )
670 })
671 }
672 }
673}
674impl<'a> Iterator for Chunks<'a> {
675 type Item = &'a keyexpr;
676 fn next(&mut self) -> Option<Self::Item> {
677 if self.inner.is_empty() {
678 return None;
679 }
680 let (next, inner) = self.inner.split_once('/').unwrap_or((self.inner, ""));
681 self.inner = inner;
682 Some(unsafe { keyexpr::from_str_unchecked(next) })
684 }
685}
686impl DoubleEndedIterator for Chunks<'_> {
687 fn next_back(&mut self) -> Option<Self::Item> {
688 if self.inner.is_empty() {
689 return None;
690 }
691 let (inner, next) = self.inner.rsplit_once('/').unwrap_or(("", self.inner));
692 self.inner = inner;
693 Some(unsafe { keyexpr::from_str_unchecked(next) })
695 }
696}
697
698impl Div for &keyexpr {
699 type Output = OwnedKeyExpr;
700 fn div(self, rhs: Self) -> Self::Output {
701 self.join(rhs).unwrap() }
703}
704
705#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
723#[cfg(feature = "unstable")]
724pub enum SetIntersectionLevel {
725 Disjoint,
726 Intersects,
727 Includes,
728 Equals,
729}
730
731#[cfg(feature = "unstable")]
732#[test]
733fn intersection_level_cmp() {
734 use SetIntersectionLevel::*;
735 assert!(Disjoint < Intersects);
736 assert!(Intersects < Includes);
737 assert!(Includes < Equals);
738}
739
740impl fmt::Debug for keyexpr {
741 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
742 write!(f, "ke`{}`", self.as_ref())
743 }
744}
745
746impl fmt::Display for keyexpr {
747 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
748 f.write_str(self)
749 }
750}
751
752#[repr(i8)]
753enum KeyExprError {
754 LoneDollarStar = -1,
755 SingleStarAfterDoubleStar = -2,
756 DoubleStarAfterDoubleStar = -3,
757 EmptyChunk = -4,
758 StarInChunk = -5,
759 DollarAfterDollar = -6,
760 SharpOrQMark = -7,
761 UnboundDollar = -8,
762}
763
764impl KeyExprError {
765 #[cold]
766 fn into_err(self, s: &str) -> ZError {
767 let error = match &self {
768 Self::LoneDollarStar => anyhow!("Invalid Key Expr `{s}`: empty chunks are forbidden, as well as leading and trailing slashes"),
769 Self::SingleStarAfterDoubleStar => anyhow!("Invalid Key Expr `{s}`: `**/*` must be replaced by `*/**` to reach canon-form"),
770 Self::DoubleStarAfterDoubleStar => anyhow!("Invalid Key Expr `{s}`: `**/**` must be replaced by `**` to reach canon-form"),
771 Self::EmptyChunk => anyhow!("Invalid Key Expr `{s}`: empty chunks are forbidden, as well as leading and trailing slashes"),
772 Self::StarInChunk => anyhow!("Invalid Key Expr `{s}`: `*` may only be preceded by `/` or `$`"),
773 Self::DollarAfterDollar => anyhow!("Invalid Key Expr `{s}`: `$` is not allowed after `$*`"),
774 Self::SharpOrQMark => anyhow!("Invalid Key Expr `{s}`: `#` and `?` are forbidden characters"),
775 Self::UnboundDollar => anyhow!("Invalid Key Expr `{s}`: `$` is only allowed in `$*`")
776 };
777 zerror!((self) error).into()
778 }
779}
780
781impl<'a> TryFrom<&'a str> for &'a keyexpr {
782 type Error = ZError;
783
784 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
785 use KeyExprError::*;
786 if value.is_empty() || value.ends_with('/') {
788 return Err(EmptyChunk.into_err(value));
789 }
790 let bytes = value.as_bytes();
791 let mut chunk_start = 0;
793 let mut i = 0;
796 while i < bytes.len() {
797 match bytes[i] {
798 c if c > b'/' && c != b'?' => i += 1,
802 b'/' if i == chunk_start => return Err(EmptyChunk.into_err(value)),
804 b'/' => {
806 i += 1;
807 chunk_start = i;
808 }
809 b'*' if i != chunk_start => return Err(StarInChunk.into_err(value)),
811 b'*' => match bytes.get(i + 1) {
815 None => break,
817 Some(&b'/') => {
820 i += 2;
821 chunk_start = i;
822 }
823 Some(&b'*') => match bytes.get(i + 2) {
825 None => break,
827 Some(&b'/') if matches!(bytes.get(i + 3), Some(b'*')) => {
830 #[cold]
833 fn double_star_err(value: &str, i: usize) -> ZError {
834 match (value.as_bytes().get(i + 4), value.as_bytes().get(i + 5)) {
835 (None | Some(&b'/'), _) => SingleStarAfterDoubleStar,
836 (Some(&b'*'), None | Some(&b'/')) => DoubleStarAfterDoubleStar,
837 _ => StarInChunk,
838 }
839 .into_err(value)
840 }
841 return Err(double_star_err(value, i));
842 }
843 Some(&b'/') => {
846 i += 3;
847 chunk_start = i;
848 }
849 _ => return Err(StarInChunk.into_err(value)),
851 },
852 _ => return Err(StarInChunk.into_err(value)),
854 },
855 b'$' if bytes.get(i + 1) != Some(&b'*') => {
857 return Err(UnboundDollar.into_err(value))
858 }
859 b'$' => match bytes.get(i + 2) {
861 Some(&b'$') => return Err(DollarAfterDollar.into_err(value)),
863 Some(&b'/') | None if i == chunk_start => {
865 return Err(LoneDollarStar.into_err(value))
866 }
867 None => break,
869 _ => i += 2,
871 },
872 b'#' | b'?' => return Err(SharpOrQMark.into_err(value)),
874 _ => i += 1,
876 }
877 }
878 Ok(unsafe { keyexpr::from_str_unchecked(value) })
880 }
881}
882
883impl<'a> TryFrom<&'a mut str> for &'a keyexpr {
884 type Error = ZError;
885 fn try_from(value: &'a mut str) -> Result<Self, Self::Error> {
886 (value as &'a str).try_into()
887 }
888}
889
890impl<'a> TryFrom<&'a mut String> for &'a keyexpr {
891 type Error = ZError;
892 fn try_from(value: &'a mut String) -> Result<Self, Self::Error> {
893 (value.as_str()).try_into()
894 }
895}
896
897impl<'a> TryFrom<&'a String> for &'a keyexpr {
898 type Error = ZError;
899 fn try_from(value: &'a String) -> Result<Self, Self::Error> {
900 (value.as_str()).try_into()
901 }
902}
903impl<'a> TryFrom<&'a &'a str> for &'a keyexpr {
904 type Error = ZError;
905 fn try_from(value: &'a &'a str) -> Result<Self, Self::Error> {
906 (*value).try_into()
907 }
908}
909impl<'a> TryFrom<&'a &'a mut str> for &'a keyexpr {
910 type Error = ZError;
911 fn try_from(value: &'a &'a mut str) -> Result<Self, Self::Error> {
912 keyexpr::new(*value)
913 }
914}
915#[test]
916fn autocanon() {
917 let mut s: Box<str> = Box::from("hello/**/*");
918 let mut s: &mut str = &mut s;
919 assert_eq!(keyexpr::autocanonize(&mut s).unwrap(), "hello/*/**");
920}
921
922impl Deref for keyexpr {
923 type Target = str;
924 fn deref(&self) -> &Self::Target {
925 unsafe { core::mem::transmute(self) }
927 }
928}
929impl AsRef<str> for keyexpr {
930 fn as_ref(&self) -> &str {
931 self
932 }
933}
934
935impl PartialEq<str> for keyexpr {
936 fn eq(&self, other: &str) -> bool {
937 self.as_str() == other
938 }
939}
940
941impl PartialEq<keyexpr> for str {
942 fn eq(&self, other: &keyexpr) -> bool {
943 self == other.as_str()
944 }
945}
946
947impl Borrow<keyexpr> for OwnedKeyExpr {
948 fn borrow(&self) -> &keyexpr {
949 self
950 }
951}
952impl ToOwned for keyexpr {
953 type Owned = OwnedKeyExpr;
954 fn to_owned(&self) -> Self::Owned {
955 OwnedKeyExpr::from(self)
956 }
957}
958
959#[allow(non_camel_case_types)]
961#[repr(transparent)]
962#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
963pub struct nonwild_keyexpr(keyexpr);
964
965impl nonwild_keyexpr {
966 pub fn new<'a, T, E>(t: &'a T) -> Result<&'a Self, ZError>
970 where
971 &'a keyexpr: TryFrom<&'a T, Error = E>,
972 E: Into<ZError>,
973 T: ?Sized,
974 {
975 let ke: &'a keyexpr = t.try_into().map_err(|e: E| e.into())?;
976 ke.try_into()
977 }
978
979 pub const unsafe fn from_str_unchecked(s: &str) -> &Self {
985 unsafe { core::mem::transmute(s) }
987 }
988}
989
990impl Deref for nonwild_keyexpr {
991 type Target = keyexpr;
992 fn deref(&self) -> &Self::Target {
993 &self.0
994 }
995}
996
997impl<'a> TryFrom<&'a keyexpr> for &'a nonwild_keyexpr {
998 type Error = ZError;
999 fn try_from(value: &'a keyexpr) -> Result<Self, Self::Error> {
1000 if value.is_wild_impl() {
1001 bail!("nonwild_keyexpr can not contain any wild chunks")
1002 }
1003 Ok(unsafe { core::mem::transmute::<&keyexpr, &nonwild_keyexpr>(value) })
1005 }
1006}
1007
1008impl Borrow<nonwild_keyexpr> for OwnedNonWildKeyExpr {
1009 fn borrow(&self) -> &nonwild_keyexpr {
1010 self
1011 }
1012}
1013
1014impl ToOwned for nonwild_keyexpr {
1015 type Owned = OwnedNonWildKeyExpr;
1016 fn to_owned(&self) -> Self::Owned {
1017 OwnedNonWildKeyExpr::from(self)
1018 }
1019}
1020
1021#[cfg(feature = "internal")]
1022#[test]
1023fn test_keyexpr_strip_prefix() {
1024 let expectations = [
1025 (("demo/example/test/**", "demo/example/test"), &["**"][..]),
1026 (("demo/example/**", "demo/example/test"), &["**"]),
1027 (("**", "demo/example/test"), &["**"]),
1028 (
1029 ("demo/example/test/**/x$*/**", "demo/example/test"),
1030 &["**/x$*/**"],
1031 ),
1032 (("demo/**/xyz", "demo/example/test"), &["**/xyz"]),
1033 (("demo/**/test/**", "demo/example/test"), &["**"]),
1034 (
1035 ("demo/**/ex$*/*/xyz", "demo/example/test"),
1036 ["xyz", "**/ex$*/*/xyz"].as_ref(),
1037 ),
1038 (
1039 ("demo/**/ex$*/t$*/xyz", "demo/example/test"),
1040 ["xyz", "**/ex$*/t$*/xyz"].as_ref(),
1041 ),
1042 (
1043 ("demo/**/te$*/*/xyz", "demo/example/test"),
1044 ["*/xyz", "**/te$*/*/xyz"].as_ref(),
1045 ),
1046 (("demo/example/test", "demo/example/test"), [].as_ref()),
1047 ]
1048 .map(|((a, b), expected)| {
1049 (
1050 (keyexpr::new(a).unwrap(), keyexpr::new(b).unwrap()),
1051 expected
1052 .iter()
1053 .map(|s| keyexpr::new(*s).unwrap())
1054 .collect::<Vec<_>>(),
1055 )
1056 });
1057 for ((ke, prefix), expected) in expectations {
1058 dbg!(ke, prefix);
1059 assert_eq!(ke.strip_prefix(prefix), expected)
1060 }
1061}
1062
1063#[cfg(feature = "internal")]
1064#[test]
1065fn test_keyexpr_strip_nonwild_prefix() {
1066 let expectations = [
1067 (("demo/example/test/**", "demo/example/test"), Some("**")),
1068 (("demo/example/**", "demo/example/test"), Some("**")),
1069 (("**", "demo/example/test"), Some("**")),
1070 (("*/example/test/1", "demo/example/test"), Some("1")),
1071 (("demo/*/test/1", "demo/example/test"), Some("1")),
1072 (("*/*/test/1", "demo/example/test"), Some("1")),
1073 (("*/*/*/1", "demo/example/test"), Some("1")),
1074 (("*/test/1", "demo/example/test"), None),
1075 (("*/*/1", "demo/example/test"), None),
1076 (("*/*/**", "demo/example/test"), Some("**")),
1077 (
1078 ("demo/example/test/**/x$*/**", "demo/example/test"),
1079 Some("**/x$*/**"),
1080 ),
1081 (("demo/**/xyz", "demo/example/test"), Some("**/xyz")),
1082 (("demo/**/test/**", "demo/example/test"), Some("**/test/**")),
1083 (
1084 ("demo/**/ex$*/*/xyz", "demo/example/test"),
1085 Some("**/ex$*/*/xyz"),
1086 ),
1087 (
1088 ("demo/**/ex$*/t$*/xyz", "demo/example/test"),
1089 Some("**/ex$*/t$*/xyz"),
1090 ),
1091 (
1092 ("demo/**/te$*/*/xyz", "demo/example/test"),
1093 Some("**/te$*/*/xyz"),
1094 ),
1095 (("demo/example/test", "demo/example/test"), None),
1096 (("demo/example/test1/something", "demo/example/test"), None),
1097 (
1098 ("demo/example/test$*/something", "demo/example/test"),
1099 Some("something"),
1100 ),
1101 (("*/example/test/something", "@demo/example/test"), None),
1102 (("**/test/something", "@demo/example/test"), None),
1103 (("**/test/something", "demo/example/@test"), None),
1104 (
1105 ("@demo/*/test/something", "@demo/example/test"),
1106 Some("something"),
1107 ),
1108 (("@demo/*/test/something", "@demo/@example/test"), None),
1109 (("**/@demo/test/something", "@demo/test"), Some("something")),
1110 (("**/@test/something", "demo/@test"), Some("something")),
1111 (
1112 ("@demo/**/@test/something", "@demo/example/@test"),
1113 Some("something"),
1114 ),
1115 ]
1116 .map(|((a, b), expected)| {
1117 (
1118 (keyexpr::new(a).unwrap(), nonwild_keyexpr::new(b).unwrap()),
1119 expected.map(|t| keyexpr::new(t).unwrap()),
1120 )
1121 });
1122 for ((ke, prefix), expected) in expectations {
1123 dbg!(ke, prefix);
1124 assert_eq!(ke.strip_nonwild_prefix(prefix), expected)
1125 }
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130 use test_case::test_case;
1131 use zenoh_result::ErrNo;
1132
1133 use crate::{
1134 key_expr::borrowed::{KeyExprError, KeyExprError::*},
1135 keyexpr,
1136 };
1137
1138 #[test_case("", EmptyChunk; "Empty")]
1139 #[test_case("demo/example/test", None; "Normal key_expr")]
1140 #[test_case("demo/*", None; "Single star at the end")]
1141 #[test_case("demo/**", None; "Double star at the end")]
1142 #[test_case("demo/*/*/test", None; "Single star after single star")]
1143 #[test_case("demo/*/**/test", None; "Double star after single star")]
1144 #[test_case("demo/example$*/test", None; "Dollar with star")]
1145 #[test_case("demo/example$*-$*/test", None; "Multiple dollar with star")]
1146 #[test_case("/demo/example/test", EmptyChunk; "Leading /")]
1147 #[test_case("demo/example/test/", EmptyChunk; "Trailing /")]
1148 #[test_case("demo/$*/test", LoneDollarStar; "Lone $*")]
1149 #[test_case("demo/$*", LoneDollarStar; "Lone $* at the end")]
1150 #[test_case("demo/example$*", None; "Trailing lone $*")]
1151 #[test_case("demo/**/*/test", SingleStarAfterDoubleStar; "Single star after double star")]
1152 #[test_case("demo/**/**/test", DoubleStarAfterDoubleStar; "Double star after double star")]
1153 #[test_case("demo//test", EmptyChunk; "Empty Chunk")]
1154 #[test_case("demo/exam*ple/test", StarInChunk; "Star in chunk")]
1155 #[test_case("demo/example$*$/test", DollarAfterDollar; "Dollar after dollar or star")]
1156 #[test_case("demo/example$*$*/test", DollarAfterDollar; "Dollar star after dollar or star")]
1157 #[test_case("demo/example#/test", SharpOrQMark; "Contain sharp")]
1158 #[test_case("demo/example?/test", SharpOrQMark; "Contain mark")]
1159 #[test_case("demo/$/test", UnboundDollar; "Contain unbounded dollar")]
1160 fn test_keyexpr_new(key_str: &str, error: impl Into<Option<KeyExprError>>) {
1161 assert_eq!(
1162 keyexpr::new(key_str).err().map(|err| {
1163 err.downcast_ref::<zenoh_result::ZError>()
1164 .unwrap()
1165 .errno()
1166 .get()
1167 }),
1168 error.into().map(|err| err as i8)
1169 );
1170 }
1171}