Skip to content

Commit e5a7250

Browse files
committed
Add subscribe_to_signal
Add a new method subscribe_to_signal which returns a managed signal subscription which unsubscribes from the signal when dropped. Also add a weak ref counterpart to this signal subscription to allow breaking reference cycles. This fits better into Rust's ownership model and makes it much easier to handle the lifetime of a signal subscription in async code. Mark the old signal_subscribe and signal_unsubscribe as deprecated in favour of this new subscribe_to_signal method.
1 parent 93fefd4 commit e5a7250

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

gio/src/dbus_connection.rs

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
ffi, ActionGroup, DBusConnection, DBusInterfaceInfo, DBusMessage, DBusMethodInvocation,
77
DBusSignalFlags, MenuModel,
88
};
9-
use glib::{prelude::*, translate::*};
9+
use glib::{prelude::*, translate::*, WeakRef};
1010

1111
pub trait DBusMethodCall: Sized {
1212
fn parse_call(
@@ -117,9 +117,74 @@ pub struct ActionGroupExportId(NonZeroU32);
117117
pub struct MenuModelExportId(NonZeroU32);
118118
#[derive(Debug, Eq, PartialEq)]
119119
pub struct FilterId(NonZeroU32);
120+
120121
#[derive(Debug, Eq, PartialEq)]
121122
pub struct SignalSubscriptionId(NonZeroU32);
122123

124+
// rustdoc-stripper-ignore-next
125+
/// A strong subscription to a D-Bus signal.
126+
///
127+
/// Keep a reference to a D-Bus connection to maintain a subscription on a
128+
/// D-Bus signal even if the connection has no other strong reference.
129+
///
130+
/// When dropped, unsubscribes from signal on the connection, and then drop the
131+
/// reference on the connection. If no other strong reference on the connection
132+
/// exists the connection is closed and destroyed.
133+
#[derive(Debug)]
134+
pub struct SignalSubscription(DBusConnection, Option<SignalSubscriptionId>);
135+
136+
impl SignalSubscription {
137+
// rustdoc-stripper-ignore-next
138+
/// Downgrade this signal subscription to a weak one.
139+
pub fn downgrade(mut self) -> WeakSignalSubscription {
140+
WeakSignalSubscription(self.0.downgrade(), self.1.take())
141+
}
142+
}
143+
144+
impl Drop for SignalSubscription {
145+
fn drop(&mut self) {
146+
if let Some(id) = self.1.take() {
147+
#[allow(deprecated)]
148+
self.0.signal_unsubscribe(id);
149+
}
150+
}
151+
}
152+
153+
// rustdoc-stripper-ignore-next
154+
/// A weak subscription to a D-Bus signal.
155+
///
156+
/// Like [`SignalSubscription`] but hold only a weak reference to the D-Bus
157+
/// connection the siganl is subscribed on, i.e. maintain the subscription on
158+
/// the D-Bus signal only as long as some strong reference exists on the
159+
/// corresponding D-Bus connection.
160+
///
161+
/// When dropped, unsubscribes from signal on the connection if it still exists,
162+
/// and then drop the reference on the connection. If no other strong reference
163+
/// on the connection exists the connection is closed and destroyed.
164+
#[derive(Debug)]
165+
pub struct WeakSignalSubscription(WeakRef<DBusConnection>, Option<SignalSubscriptionId>);
166+
167+
impl WeakSignalSubscription {
168+
// rustdoc-stripper-ignore-next
169+
/// Upgrade this signal subscription to a strong one.
170+
pub fn upgrade(mut self) -> Option<SignalSubscription> {
171+
self.0
172+
.upgrade()
173+
.map(|c| SignalSubscription(c, self.1.take()))
174+
}
175+
}
176+
177+
impl Drop for WeakSignalSubscription {
178+
fn drop(&mut self) {
179+
if let Some(id) = self.1.take() {
180+
if let Some(connection) = self.0.upgrade() {
181+
#[allow(deprecated)]
182+
connection.signal_unsubscribe(id);
183+
}
184+
}
185+
}
186+
}
187+
123188
// rustdoc-stripper-ignore-next
124189
/// Build a registered DBus object, by handling different parts of DBus.
125190
#[must_use = "The builder must be built to be used"]
@@ -437,8 +502,45 @@ impl DBusConnection {
437502
}
438503
}
439504

505+
// rustdoc-stripper-ignore-next
506+
/// Subscribe to a D-Bus signal.
507+
///
508+
/// See [`Self::signal_subscribe`] for arguments.
509+
///
510+
/// Return a signal subscription which keeps a reference to this D-Bus
511+
/// connection and unsubscribes from the signal when dropped.
512+
///
513+
/// To avoid reference cycles you may wish to downgrade the returned
514+
/// subscription to a weak one with [`SignalSubscription::downgrade`].
515+
#[must_use]
516+
pub fn subscribe_to_signal<
517+
P: Fn(&DBusConnection, &str, &str, &str, &str, &glib::Variant) + 'static,
518+
>(
519+
&self,
520+
sender: Option<&str>,
521+
interface_name: Option<&str>,
522+
member: Option<&str>,
523+
object_path: Option<&str>,
524+
arg0: Option<&str>,
525+
flags: DBusSignalFlags,
526+
callback: P,
527+
) -> SignalSubscription {
528+
#[allow(deprecated)]
529+
let id = self.signal_subscribe(
530+
sender,
531+
interface_name,
532+
member,
533+
object_path,
534+
arg0,
535+
flags,
536+
callback,
537+
);
538+
SignalSubscription(self.clone(), Some(id))
539+
}
540+
440541
#[doc(alias = "g_dbus_connection_signal_subscribe")]
441542
#[allow(clippy::too_many_arguments)]
543+
#[deprecated(note = "Prefer subscribe_to_signal")]
442544
pub fn signal_subscribe<
443545
P: Fn(&DBusConnection, &str, &str, &str, &str, &glib::Variant) + 'static,
444546
>(
@@ -507,6 +609,7 @@ impl DBusConnection {
507609
}
508610

509611
#[doc(alias = "g_dbus_connection_signal_unsubscribe")]
612+
#[deprecated(note = "Prefer subscribe_to_signal")]
510613
pub fn signal_unsubscribe(&self, subscription_id: SignalSubscriptionId) {
511614
unsafe {
512615
ffi::g_dbus_connection_signal_unsubscribe(

gio/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub use self::dbus::*;
3333
mod dbus_connection;
3434
pub use self::dbus_connection::{
3535
ActionGroupExportId, FilterId, MenuModelExportId, RegistrationBuilder, RegistrationId,
36-
SignalSubscriptionId, WatcherId,
36+
SignalSubscription, SignalSubscriptionId, WatcherId, WeakSignalSubscription,
3737
};
3838
mod dbus_message;
3939
mod dbus_method_invocation;

0 commit comments

Comments
 (0)