rumqttc_dev_patched/mqttbytes/
topic.rspub fn has_wildcards(s: &str) -> bool {
s.contains('+') || s.contains('#')
}
pub fn valid_topic(topic: &str) -> bool {
if topic.contains('+') || topic.contains('#') {
return false;
}
true
}
pub fn valid_filter(filter: &str) -> bool {
if filter.is_empty() {
return false;
}
let mut hirerarchy = filter.split('/').rev();
let last = hirerarchy.next().unwrap();
if last.len() != 1 && (last.contains('#') || last.contains('+')) {
return false;
}
for entry in hirerarchy {
if entry.contains('#') {
return false;
}
if entry.len() > 1 && entry.contains('+') {
return false;
}
}
true
}
pub fn matches(topic: &str, filter: &str) -> bool {
if !topic.is_empty() && topic[..1].contains('$') {
return false;
}
let mut topics = topic.split('/');
let mut filters = filter.split('/');
for f in filters.by_ref() {
if f == "#" {
return true;
}
let top = topics.next();
match top {
Some("#") => return false,
Some(_) if f == "+" => continue,
Some(t) if f != t => return false,
Some(_) => continue,
None => return false,
}
}
if topics.next().is_some() {
return false;
}
true
}
#[cfg(test)]
mod test {
#[test]
fn wildcards_are_detected_correctly() {
assert!(!super::has_wildcards("a/b/c"));
assert!(super::has_wildcards("a/+/c"));
assert!(super::has_wildcards("a/b/#"));
}
#[test]
fn topics_are_validated_correctly() {
assert!(!super::valid_topic("+wrong"));
assert!(!super::valid_topic("wro#ng"));
assert!(!super::valid_topic("w/r/o/n/g+"));
assert!(!super::valid_topic("wrong/#/path"));
}
#[test]
fn filters_are_validated_correctly() {
assert!(!super::valid_filter("wrong/#/filter"));
assert!(!super::valid_filter("wrong/wr#ng/filter"));
assert!(!super::valid_filter("wrong/filter#"));
assert!(super::valid_filter("correct/filter/#"));
assert!(!super::valid_filter("wr/o+/ng"));
assert!(!super::valid_filter("wr/+o+/ng"));
assert!(!super::valid_filter("wron/+g"));
assert!(super::valid_filter("cor/+/rect/+"));
}
#[test]
fn zero_len_subscriptions_are_not_allowed() {
assert!(!super::valid_filter(""));
}
#[test]
fn dollar_subscriptions_doesnt_match_dollar_topic() {
assert!(super::matches("sy$tem/metrics", "sy$tem/+"));
assert!(!super::matches("$system/metrics", "$system/+"));
assert!(!super::matches("$system/metrics", "+/+"));
}
#[test]
fn topics_match_with_filters_as_expected() {
let topic = "a/b/c";
let filter = "a/b/c";
assert!(super::matches(topic, filter));
let topic = "a/b/c";
let filter = "d/b/c";
assert!(!super::matches(topic, filter));
let topic = "a/b/c";
let filter = "a/b/e";
assert!(!super::matches(topic, filter));
let topic = "a/b/c";
let filter = "a/b/c/d";
assert!(!super::matches(topic, filter));
let topic = "a/b/c";
let filter = "#";
assert!(super::matches(topic, filter));
let topic = "a/b/c";
let filter = "a/b/c/#";
assert!(super::matches(topic, filter));
let topic = "a/b/c/d";
let filter = "a/b/c";
assert!(!super::matches(topic, filter));
let topic = "a/b/c/d";
let filter = "a/b/c/#";
assert!(super::matches(topic, filter));
let topic = "a/b/c/d/e/f";
let filter = "a/b/c/#";
assert!(super::matches(topic, filter));
let topic = "a/b/c";
let filter = "a/+/c";
assert!(super::matches(topic, filter));
let topic = "a/b/c/d/e";
let filter = "a/+/c/+/e";
assert!(super::matches(topic, filter));
let topic = "a/b";
let filter = "a/b/+";
assert!(!super::matches(topic, filter));
let filter1 = "a/b/+";
let filter2 = "a/b/#";
assert!(super::matches(filter1, filter2));
assert!(!super::matches(filter2, filter1));
let filter1 = "a/b/+";
let filter2 = "#";
assert!(super::matches(filter1, filter2));
let filter1 = "a/+/c/d";
let filter2 = "a/+/+/d";
assert!(super::matches(filter1, filter2));
assert!(!super::matches(filter2, filter1));
let filter1 = "a/b/c/d/e";
let filter2 = "a/+/+/+/e";
assert!(super::matches(filter1, filter2));
let filter1 = "a/+/c/+/e";
let filter2 = "a/+/+/+/e";
assert!(super::matches(filter1, filter2));
let filter1 = "a/+/+/+/e";
let filter2 = "a/+/+/+/e";
assert!(super::matches(filter1, filter2));
}
}