Coverage Report

Created: 2025-12-28 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}