/rust/registry/src/index.crates.io-1949cf8c6b5b557f/dbus-0.9.7/src/message/matchrule.rs
Line | Count | Source |
1 | | use crate::{Message, MessageType}; |
2 | | use crate::strings::{BusName, Path, Interface, Member}; |
3 | | use crate::message::parser; |
4 | | |
5 | | #[derive(Clone, Debug, Default)] |
6 | | /// A "match rule", that can match Messages on its headers. |
7 | | /// |
8 | | /// A field set to "None" means no filter for that header, |
9 | | /// a field set to "Some(_)" must match exactly. |
10 | | pub struct MatchRule<'a> { |
11 | | /// Match on message type (you typically want to do this) |
12 | | pub msg_type: Option<MessageType>, |
13 | | /// Match on message sender |
14 | | pub sender: Option<BusName<'a>>, |
15 | | /// If false (the default), match if sender could possibly match, due to mismatch between unique names and taken bus names |
16 | | pub strict_sender: bool, |
17 | | /// Match on message object path |
18 | | pub path: Option<Path<'a>>, |
19 | | /// If true, will match all subpaths to the path as well as the path itself. Defaults to false. |
20 | | pub path_is_namespace: bool, |
21 | | /// Match on message interface |
22 | | pub interface: Option<Interface<'a>>, |
23 | | /// Match on message member (signal or method name) |
24 | | pub member: Option<Member<'a>>, |
25 | | /// If true, also receive messages not intended for us. Defaults to false. |
26 | | pub eavesdrop: bool, |
27 | | _more_fields_may_come: (), |
28 | | } |
29 | | |
30 | 0 | fn msg_type_str(m: MessageType) -> &'static str { |
31 | | use crate::MessageType::*; |
32 | 0 | match m { |
33 | 0 | Signal => "signal", |
34 | 0 | MethodCall => "method_call", |
35 | 0 | MethodReturn => "method_return", |
36 | 0 | Error => "error", |
37 | | } |
38 | 0 | } |
39 | | |
40 | | |
41 | | impl<'a> MatchRule<'a> { |
42 | | /// Make a string which you can use in the call to "add_match". |
43 | 0 | pub fn match_str(&self) -> String { |
44 | 0 | let mut v = vec!(); |
45 | 0 | if let Some(x) = self.msg_type { v.push(("type", msg_type_str(x))) }; |
46 | 0 | if let Some(ref x) = self.sender { v.push(("sender", &x)) }; |
47 | 0 | let pn = if self.path_is_namespace { "path_namespace" } else { "path" }; |
48 | 0 | if let Some(ref x) = self.path { v.push((pn, &x)) }; |
49 | 0 | if let Some(ref x) = self.interface { v.push(("interface", &x)) }; |
50 | 0 | if let Some(ref x) = self.member { v.push(("member", &x)) }; |
51 | 0 | if self.eavesdrop { v.push(("eavesdrop", "true")) }; |
52 | | |
53 | | // For now we don't need to worry about internal quotes in strings as those are not valid names. |
54 | | // If we start matching against arguments, we need to worry. |
55 | 0 | let v: Vec<_> = v.into_iter().map(|(k, v)| format!("{}='{}'", k, v)).collect(); |
56 | 0 | v.join(",") |
57 | 0 | } |
58 | | |
59 | 0 | fn path_match(&self, msg: &Message) -> bool { |
60 | 0 | if let Some(ref x) = self.path { |
61 | 0 | if let Some(ref p) = msg.path() { |
62 | 0 | if x != p { |
63 | 0 | if self.path_is_namespace { |
64 | 0 | p.starts_with(&**x) && &p[x.len()..x.len() + 1] == "/" |
65 | 0 | } else { false } |
66 | 0 | } else { true } |
67 | 0 | } else { false } |
68 | 0 | } else { true } |
69 | 0 | } |
70 | | |
71 | | /// Returns whether or not the message matches the rule. |
72 | 0 | pub fn matches(&self, msg: &Message) -> bool { |
73 | 0 | if let Some(x) = self.msg_type { if x != msg.msg_type() { return false; } }; |
74 | | |
75 | 0 | if let Some(ref x) = self.sender { |
76 | 0 | if let Some(s) = msg.sender() { |
77 | 0 | let check = self.strict_sender || (s.starts_with(":") == x.starts_with(":")); |
78 | 0 | if check && s != *x { return false; } |
79 | 0 | } else if self.strict_sender { return false; } |
80 | 0 | }; |
81 | 0 | if !self.path_match(msg) { return false; } |
82 | 0 | if self.interface.is_some() && msg.interface() != self.interface { return false; }; |
83 | 0 | if self.member.is_some() && msg.member() != self.member { return false; }; |
84 | 0 | true |
85 | 0 | } |
86 | | |
87 | | /// Create a new struct which matches every message. |
88 | 0 | pub fn new() -> Self { Default::default() } |
89 | | |
90 | | /// Create a new struct which matches every incoming method call message. |
91 | 0 | pub fn new_method_call() -> Self { |
92 | 0 | let mut m = Self::new(); |
93 | 0 | m.msg_type = Some(MessageType::MethodCall); |
94 | 0 | m |
95 | 0 | } |
96 | | |
97 | | /// Create a new struct which matches signals on the interface and member name. |
98 | 0 | pub fn new_signal<I: Into<Interface<'a>>, N: Into<Member<'a>>>(intf: I, name: N) -> Self { |
99 | 0 | let mut m = Self::new(); |
100 | 0 | m.msg_type = Some(MessageType::Signal); |
101 | 0 | m.interface = Some(intf.into()); |
102 | 0 | m.member = Some(name.into()); |
103 | 0 | m |
104 | 0 | } |
105 | | |
106 | | /// Returns a clone with no borrowed references |
107 | 0 | pub fn static_clone(&self) -> MatchRule<'static> { |
108 | | MatchRule { |
109 | 0 | msg_type: self.msg_type, |
110 | 0 | sender: self.sender.as_ref().map(|x| x.clone().into_static()), |
111 | 0 | strict_sender: self.strict_sender, |
112 | 0 | path: self.path.as_ref().map(|x| x.clone().into_static()), |
113 | 0 | interface: self.interface.as_ref().map(|x| x.clone().into_static()), |
114 | 0 | member: self.member.as_ref().map(|x| x.clone().into_static()), |
115 | 0 | path_is_namespace: self.path_is_namespace, |
116 | 0 | eavesdrop: self.eavesdrop, |
117 | 0 | _more_fields_may_come: (), |
118 | | } |
119 | 0 | } |
120 | | |
121 | | /// Enables eavesdropping for the generated message. |
122 | | /// You probably want to use [BecomeMonitor](https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-become-monitor) instead |
123 | 0 | pub fn with_eavesdrop(mut self) -> Self { |
124 | 0 | self.eavesdrop = true; |
125 | 0 | self |
126 | 0 | } |
127 | | |
128 | | /// Sets the MatchRule to match on the message sender |
129 | 0 | pub fn with_sender(mut self, sender: impl Into<BusName<'a>>) -> Self { |
130 | 0 | self.sender = Some(sender.into()); |
131 | 0 | self |
132 | 0 | } |
133 | | |
134 | | /// Sets the MatchRule to match on the message sender and be strict |
135 | 0 | pub fn with_strict_sender(mut self, sender: impl Into<BusName<'a>>) -> Self { |
136 | 0 | self.sender = Some(sender.into()); |
137 | 0 | self.strict_sender = true; |
138 | 0 | self |
139 | 0 | } |
140 | | |
141 | | /// Sets the MatchRule to match on the message path and treat it as a namespace |
142 | 0 | pub fn with_namespaced_path(mut self, path: impl Into<Path<'a>>) -> Self { |
143 | 0 | self.path = Some(path.into()); |
144 | 0 | self.path_is_namespace = true; |
145 | 0 | self |
146 | 0 | } |
147 | | |
148 | | /// Sets the MatchRule to match on the message path |
149 | 0 | pub fn with_path(mut self, path: impl Into<Path<'a>>) -> Self { |
150 | 0 | self.path = Some(path.into()); |
151 | 0 | self |
152 | 0 | } |
153 | | |
154 | | /// Sets the MatchRule to match on the message interface |
155 | 0 | pub fn with_interface(mut self, intf: impl Into<Interface<'a>>) -> Self { |
156 | 0 | self.interface = Some(intf.into()); |
157 | 0 | self |
158 | 0 | } |
159 | | |
160 | | /// Sets the MatchRule to match on the message member |
161 | 0 | pub fn with_member(mut self, member: impl Into<Member<'a>>) -> Self { |
162 | 0 | self.member = Some(member.into()); |
163 | 0 | self |
164 | 0 | } |
165 | | |
166 | | /// Sets the MatchRule to match on the message type. This will usually be `"signal"` |
167 | 0 | pub fn with_type(mut self, ty: MessageType) -> Self { |
168 | 0 | self.msg_type = Some(ty); |
169 | 0 | self |
170 | 0 | } |
171 | | |
172 | | /// Tries parsing a MatchRule from a String. Please note however that not all features supported |
173 | | /// by DBus are supported by dbus-rs (yet). args and destinations are not supported yet. |
174 | 0 | pub fn parse(text: &'a str) -> Result<Self, parser::Error> { |
175 | 0 | parser::Parser::new(text)?.parse() |
176 | 0 | } |
177 | | } |