use crate::{Message, MessageType};
use crate::strings::{BusName, Path, Interface, Member};
use crate::message::parser;
#[derive(Clone, Debug, Default)]
pub struct MatchRule<'a> {
pub msg_type: Option<MessageType>,
pub sender: Option<BusName<'a>>,
pub strict_sender: bool,
pub path: Option<Path<'a>>,
pub path_is_namespace: bool,
pub interface: Option<Interface<'a>>,
pub member: Option<Member<'a>>,
pub eavesdrop: bool,
_more_fields_may_come: (),
}
fn msg_type_str(m: MessageType) -> &'static str {
use crate::MessageType::*;
match m {
Signal => "signal",
MethodCall => "method_call",
MethodReturn => "method_return",
Error => "error",
}
}
impl<'a> MatchRule<'a> {
pub fn match_str(&self) -> String {
let mut v = vec!();
if let Some(x) = self.msg_type { v.push(("type", msg_type_str(x))) };
if let Some(ref x) = self.sender { v.push(("sender", &x)) };
let pn = if self.path_is_namespace { "path_namespace" } else { "path" };
if let Some(ref x) = self.path { v.push((pn, &x)) };
if let Some(ref x) = self.interface { v.push(("interface", &x)) };
if let Some(ref x) = self.member { v.push(("member", &x)) };
if self.eavesdrop { v.push(("eavesdrop", "true")) };
let v: Vec<_> = v.into_iter().map(|(k, v)| format!("{}='{}'", k, v)).collect();
v.join(",")
}
fn path_match(&self, msg: &Message) -> bool {
if let Some(ref x) = self.path {
if let Some(ref p) = msg.path() {
if x != p {
if self.path_is_namespace {
p.starts_with(&**x) && &p[x.len()..x.len() + 1] == "/"
} else { false }
} else { true }
} else { false }
} else { true }
}
pub fn matches(&self, msg: &Message) -> bool {
if let Some(x) = self.msg_type { if x != msg.msg_type() { return false; } };
if let Some(ref x) = self.sender {
if let Some(s) = msg.sender() {
let check = self.strict_sender || (s.starts_with(":") == x.starts_with(":"));
if check && s != *x { return false; }
} else if self.strict_sender { return false; }
};
if !self.path_match(msg) { return false; }
if self.interface.is_some() && msg.interface() != self.interface { return false; };
if self.member.is_some() && msg.member() != self.member { return false; };
true
}
pub fn new() -> Self { Default::default() }
pub fn new_method_call() -> Self {
let mut m = Self::new();
m.msg_type = Some(MessageType::MethodCall);
m
}
pub fn new_signal<I: Into<Interface<'a>>, N: Into<Member<'a>>>(intf: I, name: N) -> Self {
let mut m = Self::new();
m.msg_type = Some(MessageType::Signal);
m.interface = Some(intf.into());
m.member = Some(name.into());
m
}
pub fn static_clone(&self) -> MatchRule<'static> {
MatchRule {
msg_type: self.msg_type,
sender: self.sender.as_ref().map(|x| x.clone().into_static()),
strict_sender: self.strict_sender,
path: self.path.as_ref().map(|x| x.clone().into_static()),
interface: self.interface.as_ref().map(|x| x.clone().into_static()),
member: self.member.as_ref().map(|x| x.clone().into_static()),
path_is_namespace: self.path_is_namespace,
eavesdrop: self.eavesdrop,
_more_fields_may_come: (),
}
}
pub fn with_eavesdrop(mut self) -> Self {
self.eavesdrop = true;
self
}
pub fn with_sender(mut self, sender: impl Into<BusName<'a>>) -> Self {
self.sender = Some(sender.into());
self
}
pub fn with_strict_sender(mut self, sender: impl Into<BusName<'a>>) -> Self {
self.sender = Some(sender.into());
self.strict_sender = true;
self
}
pub fn with_namespaced_path(mut self, path: impl Into<Path<'a>>) -> Self {
self.path = Some(path.into());
self.path_is_namespace = true;
self
}
pub fn with_path(mut self, path: impl Into<Path<'a>>) -> Self {
self.path = Some(path.into());
self
}
pub fn with_interface(mut self, intf: impl Into<Interface<'a>>) -> Self {
self.interface = Some(intf.into());
self
}
pub fn with_member(mut self, member: impl Into<Member<'a>>) -> Self {
self.member = Some(member.into());
self
}
pub fn with_type(mut self, ty: MessageType) -> Self {
self.msg_type = Some(ty);
self
}
pub fn parse(text: &'a str) -> Result<Self, parser::Error> {
parser::Parser::new(text)?.parse()
}
}