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/blocking.rs
Line
Count
Source
1
//! Connections and proxies that make blocking method calls.
2
3
4
use crate::strings::{BusName, Path, Interface, Member};
5
use crate::arg::{AppendAll, ReadAll, IterAppend};
6
use crate::{channel, Error, Message};
7
use crate::message::{MatchRule, SignalArgs, MessageType};
8
use crate::channel::{Channel, BusType, Token};
9
use std::{cell::RefCell, time::Duration, sync::Mutex};
10
use std::sync::atomic::{AtomicBool, Ordering};
11
use crate::filters::Filters;
12
13
#[allow(missing_docs)]
14
mod generated_org_freedesktop_standard_interfaces;
15
mod generated_org_freedesktop_dbus;
16
17
/// This module contains some standard interfaces and an easy way to call them.
18
///
19
/// See the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces) for more information about these standard interfaces.
20
///
21
/// The code was created by dbus-codegen.
22
pub mod stdintf {
23
    #[allow(missing_docs)]
24
    pub mod org_freedesktop_dbus {
25
        pub use super::super::generated_org_freedesktop_standard_interfaces::*;
26
27
        #[derive(Debug, PartialEq, Eq, Copy, Clone)]
28
        pub enum RequestNameReply {
29
            PrimaryOwner = 1,
30
            InQueue = 2,
31
            Exists = 3,
32
            AlreadyOwner = 4,
33
        }
34
35
        #[derive(Debug, PartialEq, Eq, Copy, Clone)]
36
        pub enum ReleaseNameReply {
37
            Released = 1,
38
            NonExistent = 2,
39
            NotOwner = 3,
40
        }
41
42
        #[derive(Debug, PartialEq, Eq, Copy, Clone)]
43
        pub enum EmitsChangedSignal {
44
            True,
45
            Invalidates,
46
            Const,
47
            False,
48
        }
49
50
0
        pub (crate) fn request_name<S: crate::blocking::BlockingSender>(s: &S, name: &str, allow_replacement: bool, replace_existing: bool, do_not_queue: bool)
51
0
            -> Result<RequestNameReply, crate::Error> {
52
0
            let flags: u32 =
53
0
                if allow_replacement { 1 } else { 0 } +
54
0
                if replace_existing { 2 } else { 0 } +
55
0
                if do_not_queue { 4 } else { 0 };
56
0
            let proxy = super::proxy(s);
57
            use super::org_freedesktop::DBus;
58
0
            let r = proxy.request_name(name, flags)?;
59
            use RequestNameReply::*;
60
0
            let all = [PrimaryOwner, InQueue, Exists, AlreadyOwner];
61
0
            all.iter().find(|x| **x as u32 == r).copied().ok_or_else(||
62
0
                crate::Error::new_failed("Invalid reply from DBus server")
63
            )
64
0
        }
65
66
0
        pub (crate) fn release_name<S: crate::blocking::BlockingSender>(s: &S, name: &str)
67
0
            -> Result<ReleaseNameReply, crate::Error> {
68
69
0
            let proxy = super::proxy(s);
70
            use super::org_freedesktop::DBus;
71
0
            let r = proxy.release_name(name)?;
72
            use ReleaseNameReply::*;
73
0
            let all = [Released, NonExistent, NotOwner];
74
0
            all.iter().find(|x| **x as u32 == r).copied().ok_or_else(||
75
0
                crate::Error::new_failed("Invalid reply from DBus server")
76
            )
77
0
        }
78
79
        use crate::arg;
80
        impl PropertiesPropertiesChanged {
81
0
            pub fn add_prop<F: FnOnce() -> Box<dyn arg::RefArg>>(&mut self, prop_name: &str, emits: EmitsChangedSignal, f: F) -> bool {
82
0
                match emits {
83
0
                    EmitsChangedSignal::False => { false },
84
                    EmitsChangedSignal::Invalidates => {
85
0
                        if !self.invalidated_properties.iter().any(|x| x == prop_name) {
86
0
                            self.invalidated_properties.push(prop_name.into())
87
0
                        }
88
0
                        true
89
                    }
90
                    EmitsChangedSignal::True => {
91
0
                        let val = f();
92
0
                        self.changed_properties.insert(prop_name.into(), arg::Variant(val));
93
0
                        true
94
                    }
95
0
                    EmitsChangedSignal::Const => panic!("Called add_prop with EmitsChangedSignal::Const")
96
                }
97
0
            }
98
        }
99
    }
100
101
    // Not public yet, because of lack of named arguments
102
    pub (super) mod org_freedesktop {
103
        pub(crate) use super::super::generated_org_freedesktop_dbus::*;
104
    }
105
106
0
    pub (crate) fn proxy<C>(c: C) -> crate::blocking::Proxy<'static, C> {
107
0
        super::Proxy::new("org.freedesktop.DBus", "/org/freedesktop/DBus", std::time::Duration::from_millis(5000), c)
108
0
    }
Unexecuted instantiation: dbus::blocking::stdintf::proxy::<&dbus::blocking::Connection>
Unexecuted instantiation: dbus::blocking::stdintf::proxy::<&dbus::blocking::SyncConnection>
Unexecuted instantiation: dbus::blocking::stdintf::proxy::<&dbus::blocking::LocalConnection>
109
}
110
111
/// A connection to D-Bus, thread local + non-async version
112
pub struct LocalConnection {
113
    channel: Channel,
114
    filters: RefCell<Filters<LocalFilterCb>>,
115
    all_signal_matches: AtomicBool,
116
}
117
118
/// A connection to D-Bus, non-async version where callbacks are Send but not Sync.
119
pub struct Connection {
120
    channel: Channel,
121
    filters: RefCell<Filters<FilterCb>>,
122
    all_signal_matches: AtomicBool,
123
}
124
125
/// A connection to D-Bus, Send + Sync + non-async version
126
pub struct SyncConnection {
127
    channel: Channel,
128
    filters: Mutex<Filters<SyncFilterCb>>,
129
    all_signal_matches: AtomicBool,
130
}
131
132
use crate::blocking::stdintf::org_freedesktop_dbus;
133
134
macro_rules! connimpl {
135
     ($c: ident, $cb: ident $(, $ss:tt)*) =>  {
136
137
type
138
    $cb = Box<dyn FnMut(Message, &$c) -> bool $(+ $ss)* + 'static>;
139
140
141
impl $c {
142
143
    /// Create a new connection to the session bus.
144
0
    pub fn new_session() -> Result<Self, Error> {
145
0
        Channel::get_private(BusType::Session).map(From::from)
146
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::new_session
Unexecuted instantiation: <dbus::blocking::LocalConnection>::new_session
Unexecuted instantiation: <dbus::blocking::SyncConnection>::new_session
147
148
    /// Create a new connection to the system-wide bus.
149
0
    pub fn new_system() -> Result<Self, Error> {
150
0
        Channel::get_private(BusType::System).map(From::from)
151
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::new_system
Unexecuted instantiation: <dbus::blocking::LocalConnection>::new_system
Unexecuted instantiation: <dbus::blocking::SyncConnection>::new_system
152
153
    /// Get the connection's unique name.
154
    ///
155
    /// It's usually something like ":1.54"
156
0
    pub fn unique_name(&self) -> BusName { self.channel.unique_name().unwrap().into() }
Unexecuted instantiation: <dbus::blocking::Connection>::unique_name
Unexecuted instantiation: <dbus::blocking::LocalConnection>::unique_name
Unexecuted instantiation: <dbus::blocking::SyncConnection>::unique_name
157
158
    /// Create a convenience struct for easier calling of many methods on the same destination and path.
159
0
    pub fn with_proxy<'a, 'b, D: Into<BusName<'a>>, P: Into<Path<'a>>>(&'b self, dest: D, path: P, timeout: Duration) ->
160
0
    Proxy<'a, &'b Self> {
161
0
        Proxy { connection: self, destination: dest.into(), path: path.into(), timeout }
162
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::with_proxy::<_, _>
Unexecuted instantiation: <dbus::blocking::LocalConnection>::with_proxy::<_, _>
Unexecuted instantiation: <dbus::blocking::SyncConnection>::with_proxy::<_, _>
163
164
165
    /// Request a name on the D-Bus.
166
    ///
167
    /// For detailed information on the flags and return values, see the libdbus documentation.
168
0
    pub fn request_name<'a, N: Into<BusName<'a>>>(&self, name: N, allow_replacement: bool, replace_existing: bool, do_not_queue: bool)
169
0
    -> Result<org_freedesktop_dbus::RequestNameReply, Error> {
170
0
        org_freedesktop_dbus::request_name(&self.channel, &name.into(), allow_replacement, replace_existing, do_not_queue)
171
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::request_name::<_>
Unexecuted instantiation: <dbus::blocking::LocalConnection>::request_name::<_>
Unexecuted instantiation: <dbus::blocking::SyncConnection>::request_name::<_>
172
173
    /// Release a previously requested name on the D-Bus.
174
0
    pub fn release_name<'a, N: Into<BusName<'a>>>(&self, name: N) -> Result<org_freedesktop_dbus::ReleaseNameReply, Error> {
175
0
        org_freedesktop_dbus::release_name(&self.channel, &name.into())
176
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::release_name::<_>
Unexecuted instantiation: <dbus::blocking::LocalConnection>::release_name::<_>
Unexecuted instantiation: <dbus::blocking::SyncConnection>::release_name::<_>
177
178
    /// Adds a new match to the connection, and sets up a callback when this message arrives.
179
    ///
180
    /// If multiple [`MatchRule`]s match the same message, then by default only the first match will
181
  /// get the callback. This behaviour can be changed for signal messages by calling
182
  /// [`set_signal_match_mode`](Self::set_signal_match_mode).
183
    ///
184
    /// The returned value can be used to remove the match. The match is also removed if the callback
185
    /// returns "false".
186
0
    pub fn add_match<S: ReadAll, F>(&self, match_rule: MatchRule<'static>, f: F) -> Result<Token, Error>
187
0
    where F: FnMut(S, &Self, &Message) -> bool $(+ $ss)* + 'static {
188
0
        let m = match_rule.match_str();
189
0
        self.add_match_no_cb(&m)?;
190
        use channel::MatchingReceiver;
191
0
        Ok(self.start_receive(match_rule, MakeSignal::make(f, m)))
192
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::add_match::<_, _>
Unexecuted instantiation: <dbus::blocking::LocalConnection>::add_match::<_, _>
Unexecuted instantiation: <dbus::blocking::SyncConnection>::add_match::<_, _>
193
194
    /// Adds a new match to the connection, without setting up a callback when this message arrives.
195
0
    pub fn add_match_no_cb(&self, match_str: &str) -> Result<(), Error> {
196
        use crate::blocking::stdintf::org_freedesktop::DBus;
197
0
        let proxy = stdintf::proxy(self);
198
0
        proxy.add_match(match_str)
199
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::add_match_no_cb
Unexecuted instantiation: <dbus::blocking::LocalConnection>::add_match_no_cb
Unexecuted instantiation: <dbus::blocking::SyncConnection>::add_match_no_cb
200
201
    /// Removes a match from the connection, without removing any callbacks.
202
0
    pub fn remove_match_no_cb(&self, match_str: &str) -> Result<(), Error> {
203
        use crate::blocking::stdintf::org_freedesktop::DBus;
204
0
        let proxy = stdintf::proxy(self);
205
0
        proxy.remove_match(match_str)
206
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::remove_match_no_cb
Unexecuted instantiation: <dbus::blocking::LocalConnection>::remove_match_no_cb
Unexecuted instantiation: <dbus::blocking::SyncConnection>::remove_match_no_cb
207
208
    /// Removes a previously added match and callback from the connection.
209
0
    pub fn remove_match(&self, id: Token) -> Result<(), Error> {
210
        use channel::MatchingReceiver;
211
0
        let (mr, _) = self.stop_receive(id).ok_or_else(|| Error::new_failed("No match with that id found"))?;
Unexecuted instantiation: <dbus::blocking::Connection>::remove_match::{closure#0}
Unexecuted instantiation: <dbus::blocking::LocalConnection>::remove_match::{closure#0}
Unexecuted instantiation: <dbus::blocking::SyncConnection>::remove_match::{closure#0}
212
0
        self.remove_match_no_cb(&mr.match_str())
213
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::remove_match
Unexecuted instantiation: <dbus::blocking::LocalConnection>::remove_match
Unexecuted instantiation: <dbus::blocking::SyncConnection>::remove_match
214
215
    /// If true, configures the connection to send signal messages to all matching [`MatchRule`]
216
    /// filters added with [`add_match`](Self::add_match) rather than just the first one. This comes
217
    /// with the following gotchas:
218
    ///
219
    ///  * The messages might be duplicated, so the message serial might be lost (this is
220
    ///    generally not a problem for signals).
221
    ///  * Panicking inside a match callback might mess with other callbacks, causing them
222
    ///    to be permanently dropped.
223
    ///  * Removing other matches from inside a match callback is not supported.
224
    ///
225
    /// This is false by default, for a newly-created connection.
226
0
    pub fn set_signal_match_mode(&self, match_all: bool) {
227
0
        self.all_signal_matches.store(match_all, Ordering::Release);
228
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::set_signal_match_mode
Unexecuted instantiation: <dbus::blocking::LocalConnection>::set_signal_match_mode
Unexecuted instantiation: <dbus::blocking::SyncConnection>::set_signal_match_mode
229
230
    /// Tries to handle an incoming message if there is one. If there isn't one,
231
    /// it will wait up to timeout
232
    ///
233
    /// This method only takes "&self" instead of "&mut self", but it is a logic error to call
234
    /// it recursively and might lead to panics or deadlocks.
235
    ///
236
    /// For `SyncConnection`: It is also a logic error to call this method from one thread, while
237
    /// calling this or other methods from other threads. This can lead to messages being lost.
238
0
    pub fn process(&self, timeout: Duration) -> Result<bool, Error> {
239
0
        if let Some(msg) = self.channel.blocking_pop_message(timeout)? {
240
0
            if self.all_signal_matches.load(Ordering::Acquire) && msg.msg_type() == MessageType::Signal {
241
                // If it's a signal and the mode is enabled, send a copy of the message to all
242
                // matching filters.
243
0
                let matching_filters = self.filters_mut().remove_all_matching(&msg);
244
                // `matching_filters` needs to be a separate variable and not inlined here, because
245
                // if it's inline then the `MutexGuard` will live too long and we'll get a deadlock
246
                // on the next call to `filters_mut()` below.
247
0
                for mut ff in matching_filters {
248
0
                    if let Ok(copy) = msg.duplicate() {
249
0
                        if ff.2(copy, self) {
250
0
                            self.filters_mut().insert(ff);
251
0
                        }
252
0
                    } else {
253
0
                        // Silently drop the message, but add the filter back.
254
0
                        self.filters_mut().insert(ff);
255
0
                    }
256
                }
257
            } else {
258
                // Otherwise, send the original message to only the first matching filter.
259
0
                let ff = self.filters_mut().remove_first_matching(&msg);
260
0
                if let Some(mut ff) = ff {
261
0
                    if ff.2(msg, self) {
262
0
                        self.filters_mut().insert(ff);
263
0
                    }
264
0
                } else if let Some(reply) = crate::channel::default_reply(&msg) {
265
0
                    let _ = self.channel.send(reply);
266
0
                }
267
            }
268
0
            Ok(true)
269
        } else {
270
0
            Ok(false)
271
        }
272
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::process
Unexecuted instantiation: <dbus::blocking::LocalConnection>::process
Unexecuted instantiation: <dbus::blocking::SyncConnection>::process
273
274
    /// The channel for this connection
275
0
    pub fn channel(&self) -> &Channel {
276
0
        &self.channel
277
0
    }
Unexecuted instantiation: <dbus::blocking::Connection>::channel
Unexecuted instantiation: <dbus::blocking::LocalConnection>::channel
Unexecuted instantiation: <dbus::blocking::SyncConnection>::channel
278
}
279
280
impl BlockingSender for $c {
281
0
    fn send_with_reply_and_block(&self, msg: Message, timeout: Duration) -> Result<Message, Error> {
282
0
        self.channel.send_with_reply_and_block(msg, timeout)
283
0
    }
Unexecuted instantiation: <dbus::blocking::Connection as dbus::blocking::BlockingSender>::send_with_reply_and_block
Unexecuted instantiation: <dbus::blocking::LocalConnection as dbus::blocking::BlockingSender>::send_with_reply_and_block
Unexecuted instantiation: <dbus::blocking::SyncConnection as dbus::blocking::BlockingSender>::send_with_reply_and_block
284
}
285
286
impl From<Channel> for $c {
287
0
    fn from(channel: Channel) -> $c { $c {
288
0
        channel,
289
0
        filters: Default::default(),
290
0
        all_signal_matches: AtomicBool::new(false),
291
0
    } }
Unexecuted instantiation: <dbus::blocking::Connection as core::convert::From<dbus::channel::ffichannel::Channel>>::from
Unexecuted instantiation: <dbus::blocking::LocalConnection as core::convert::From<dbus::channel::ffichannel::Channel>>::from
Unexecuted instantiation: <dbus::blocking::SyncConnection as core::convert::From<dbus::channel::ffichannel::Channel>>::from
292
}
293
294
impl channel::Sender for $c {
295
0
    fn send(&self, msg: Message) -> Result<u32, ()> { self.channel.send(msg) }
Unexecuted instantiation: <dbus::blocking::Connection as dbus::channel::Sender>::send
Unexecuted instantiation: <dbus::blocking::LocalConnection as dbus::channel::Sender>::send
Unexecuted instantiation: <dbus::blocking::SyncConnection as dbus::channel::Sender>::send
296
}
297
298
impl<S: ReadAll, F: FnMut(S, &$c, &Message) -> bool $(+ $ss)* + 'static> MakeSignal<$cb, S, $c> for F {
299
0
    fn make(mut self, mstr: String) -> $cb {
300
0
        Box::new(move |msg: Message, conn: &$c| {
301
0
            if let Ok(s) = S::read(&mut msg.iter_init()) {
302
0
                if self(s, conn, &msg) { return true };
303
0
                let proxy = stdintf::proxy(conn);
304
                use crate::blocking::stdintf::org_freedesktop::DBus;
305
0
                let _ = proxy.remove_match(&mstr);
306
0
                false
307
0
            } else { true }
308
0
        })
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::Connection), Output = bool> + core::marker::Send>, _, dbus::blocking::Connection>>::make::{closure#0}
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::LocalConnection), Output = bool>>, _, dbus::blocking::LocalConnection>>::make::{closure#0}
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::SyncConnection), Output = bool> + core::marker::Sync + core::marker::Send>, _, dbus::blocking::SyncConnection>>::make::{closure#0}
309
0
    }
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::Connection), Output = bool> + core::marker::Send>, _, dbus::blocking::Connection>>::make
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::LocalConnection), Output = bool>>, _, dbus::blocking::LocalConnection>>::make
Unexecuted instantiation: <_ as dbus::blocking::MakeSignal<alloc::boxed::Box<dyn for<'a> core::ops::function::FnMut<(dbus::message::Message, &'a dbus::blocking::SyncConnection), Output = bool> + core::marker::Sync + core::marker::Send>, _, dbus::blocking::SyncConnection>>::make
310
}
311
312
impl channel::MatchingReceiver for $c {
313
    type F = $cb;
314
0
    fn start_receive(&self, m: MatchRule<'static>, f: Self::F) -> Token {
315
0
        self.filters_mut().add(m, f)
316
0
    }
Unexecuted instantiation: <dbus::blocking::Connection as dbus::channel::MatchingReceiver>::start_receive
Unexecuted instantiation: <dbus::blocking::LocalConnection as dbus::channel::MatchingReceiver>::start_receive
Unexecuted instantiation: <dbus::blocking::SyncConnection as dbus::channel::MatchingReceiver>::start_receive
317
0
    fn stop_receive(&self, id: Token) -> Option<(MatchRule<'static>, Self::F)> {
318
0
        self.filters_mut().remove(id)
319
0
    }
Unexecuted instantiation: <dbus::blocking::Connection as dbus::channel::MatchingReceiver>::stop_receive
Unexecuted instantiation: <dbus::blocking::LocalConnection as dbus::channel::MatchingReceiver>::stop_receive
Unexecuted instantiation: <dbus::blocking::SyncConnection as dbus::channel::MatchingReceiver>::stop_receive
320
}
321
322
323
324
     }
325
}
326
327
connimpl!(Connection, FilterCb, Send);
328
connimpl!(LocalConnection, LocalFilterCb);
329
connimpl!(SyncConnection, SyncFilterCb, Send, Sync);
330
331
impl Connection {
332
0
    fn filters_mut(&self) -> std::cell::RefMut<Filters<FilterCb>> { self.filters.borrow_mut() }
333
}
334
335
impl LocalConnection {
336
0
    fn filters_mut(&self) -> std::cell::RefMut<Filters<LocalFilterCb>> { self.filters.borrow_mut() }
337
}
338
339
impl SyncConnection {
340
0
    fn filters_mut(&self) -> std::sync::MutexGuard<Filters<SyncFilterCb>> { self.filters.lock().unwrap() }
341
}
342
343
/// Abstraction over different connections
344
pub trait BlockingSender {
345
    /// Sends a message over the D-Bus and blocks, waiting for a reply or a timeout. This is used for method calls.
346
    ///
347
    /// Note: In case of an error reply, this is returned as an Err(), not as a Ok(Message) with the error type.
348
    fn send_with_reply_and_block(&self, msg: Message, timeout: Duration) -> Result<Message, Error>;
349
}
350
351
impl BlockingSender for Channel {
352
0
    fn send_with_reply_and_block(&self, msg: Message, timeout: Duration) -> Result<Message, Error> {
353
0
        Channel::send_with_reply_and_block(self, msg, timeout)
354
0
    }
355
}
356
357
/// A struct that wraps a connection, destination and path.
358
///
359
/// A D-Bus "Proxy" is a client-side object that corresponds to a remote object on the server side.
360
/// Calling methods on the proxy object calls methods on the remote object.
361
/// Read more in the [D-Bus tutorial](https://dbus.freedesktop.org/doc/dbus-tutorial.html#proxies)
362
#[derive(Clone, Debug)]
363
pub struct Proxy<'a, C> {
364
    /// Destination, i e what D-Bus service you're communicating with
365
    pub destination: BusName<'a>,
366
    /// Object path on the destination
367
    pub path: Path<'a>,
368
    /// Timeout for method calls
369
    pub timeout: Duration,
370
    /// Some way to send and/or receive messages, either blocking or non-blocking.
371
    pub connection: C,
372
}
373
374
impl<'a, C> Proxy<'a, C> {
375
    /// Creates a new proxy struct.
376
0
    pub fn new<D: Into<BusName<'a>>, P: Into<Path<'a>>>(dest: D, path: P, timeout: Duration, connection: C) -> Self {
377
0
        Proxy { destination: dest.into(), path: path.into(), timeout, connection }
378
0
    }
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::Connection>>::new::<&str, &str>
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::SyncConnection>>::new::<&str, &str>
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::LocalConnection>>::new::<&str, &str>
379
}
380
381
impl<'a, T: BlockingSender, C: std::ops::Deref<Target=T>> Proxy<'a, C> {
382
// impl<'a, S: std::convert::AsRef<channel::Sender>> Proxy<'a, S> {
383
    /// Make a method call using typed input and output arguments, then block waiting for a reply.
384
    ///
385
    /// # Example
386
    ///
387
    /// ```
388
    /// use dbus::blocking::{Connection, Proxy};
389
    ///
390
    /// let conn = Connection::new_session()?;
391
    /// let proxy = Proxy::new("org.freedesktop.DBus", "/", std::time::Duration::from_millis(5000), &conn);
392
    /// let (has_owner,): (bool,) = proxy.method_call("org.freedesktop.DBus", "NameHasOwner", ("dummy.name.without.owner",))?;
393
    /// assert_eq!(has_owner, false);
394
    /// # Ok::<(), Box<dyn std::error::Error>>(())
395
    /// ```
396
0
    pub fn method_call<'i, 'm, R: ReadAll, A: AppendAll, I: Into<Interface<'i>>, M: Into<Member<'m>>>(&self, i: I, m: M, args: A) -> Result<R, Error> {
397
0
        let mut msg = Message::method_call(&self.destination, &self.path, &i.into(), &m.into());
398
0
        args.append(&mut IterAppend::new(&mut msg));
399
0
        let r = self.connection.send_with_reply_and_block(msg, self.timeout)?;
400
0
        Ok(R::read(&mut r.iter_init())?)
401
0
    }
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::Connection>>::method_call::<(), (&str,), &str, &str>
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::SyncConnection>>::method_call::<(), (&str,), &str, &str>
Unexecuted instantiation: <dbus::blocking::Proxy<&dbus::blocking::LocalConnection>>::method_call::<(), (&str,), &str, &str>
402
403
    /// Starts matching incoming messages on this destination and path.
404
    ///
405
    /// For matching signals, match_signal might be more convenient.
406
    ///
407
    /// The match rule will be modified to include this path and destination only.
408
    ///
409
    /// If call_add_match is true, will notify the D-Bus server that matching should start.
410
0
    pub fn match_start(&self, mut mr: MatchRule<'static>, call_add_match: bool, f: <T as channel::MatchingReceiver>::F)
411
0
    -> Result<Token, Error>
412
0
    where T: channel::MatchingReceiver {
413
0
        mr.path = Some(self.path.clone().into_static());
414
0
        mr.sender = Some(self.destination.clone().into_static());
415
0
        if call_add_match {
416
            use crate::blocking::stdintf::org_freedesktop::DBus;
417
0
            let proxy = stdintf::proxy(&*self.connection);
418
0
            proxy.add_match(&mr.match_str())?;
419
0
        }
420
421
0
        Ok(self.connection.start_receive(mr, f))
422
0
    }
423
424
    /// Stops matching a signal added with match_start or match_signal.
425
    ///
426
    /// If call_remove_match is true, will notify the D-Bus server that matching should stop,
427
    /// this should be true in case match_signal was used.
428
0
    pub fn match_stop(&self, id: Token, call_remove_match: bool) -> Result<(), Error>
429
0
    where T: channel::MatchingReceiver {
430
0
        if let Some((mr, _)) = self.connection.stop_receive(id) {
431
0
            if call_remove_match {
432
                use crate::blocking::stdintf::org_freedesktop::DBus;
433
0
                let proxy = stdintf::proxy(&*self.connection);
434
0
                proxy.remove_match(&mr.match_str())?;
435
0
            }
436
0
        }
437
0
        Ok(())
438
0
    }
439
440
    /// Sets up an incoming signal match, that calls the supplied callback every time the signal is received.
441
    ///
442
    /// The returned value can be used to remove the match. The match is also removed if the callback
443
    /// returns "false".
444
0
    pub fn match_signal<S: SignalArgs + ReadAll, F>(&self, f: F) -> Result<Token, Error>
445
0
    where T: channel::MatchingReceiver,
446
0
          F: MakeSignal<<T as channel::MatchingReceiver>::F, S, T>
447
    {
448
0
        let mr = S::match_rule(Some(&self.destination), Some(&self.path)).static_clone();
449
0
        let ff = f.make(mr.match_str());
450
0
        self.match_start(mr, true, ff)
451
0
    }
452
}
453
454
/// Internal helper trait
455
pub trait MakeSignal<G, S, T> {
456
    /// Internal helper trait
457
    fn make(self, mstr: String) -> G;
458
}
459
460
#[test]
461
fn test_add_match() {
462
    use self::stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged as Ppc;
463
    let c = Connection::new_session().unwrap();
464
    let x = c.add_match(Ppc::match_rule(None, None), |_: Ppc, _, _| { true }).unwrap();
465
    c.remove_match(x).unwrap();
466
}
467
468
#[test]
469
fn test_conn_send_sync() {
470
    fn is_send<T: Send>(_: &T) {}
471
    fn is_sync<T: Sync>(_: &T) {}
472
473
    let c = SyncConnection::new_session().unwrap();
474
    is_send(&c);
475
    is_sync(&c);
476
477
    let c = Connection::new_session().unwrap();
478
    is_send(&c);
479
}
480
481
#[test]
482
fn test_peer() {
483
    let c = Connection::new_session().unwrap();
484
485
    let c_name = c.unique_name().into_static();
486
    use std::sync::Arc;
487
    let done = Arc::new(false);
488
    let d2 = done.clone();
489
    let j = std::thread::spawn(move || {
490
        let c2 = Connection::new_session().unwrap();
491
492
        let proxy = c2.with_proxy(c_name, "/", Duration::from_secs(5));
493
        let (s2,): (String,) = proxy.method_call("org.freedesktop.DBus.Peer", "GetMachineId", ()).unwrap();
494
        println!("{}", s2);
495
        assert_eq!(Arc::strong_count(&d2), 2);
496
        s2
497
    });
498
    assert_eq!(Arc::strong_count(&done), 2);
499
500
    for _ in 0..30 {
501
        c.process(Duration::from_millis(100)).unwrap();
502
        if Arc::strong_count(&done) < 2 { break; }
503
    }
504
505
    let s2 = j.join().unwrap();
506
507
    #[cfg(unix)]
508
    {
509
        let proxy = c.with_proxy("org.a11y.Bus", "/org/a11y/bus", Duration::from_secs(5));
510
        let (s1,): (String,) = proxy.method_call("org.freedesktop.DBus.Peer", "GetMachineId", ()).unwrap();
511
512
        assert_eq!(s1, s2);
513
    }
514
515
}