Skip to content

Commit 5792bef

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 5792bef

File tree

2 files changed

+107
-2
lines changed

2 files changed

+107
-2
lines changed

gio/src/dbus_connection.rs

Lines changed: 106 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,76 @@ 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+
#[must_use]
140+
pub fn downgrade(mut self) -> WeakSignalSubscription {
141+
WeakSignalSubscription(self.0.downgrade(), self.1.take())
142+
}
143+
}
144+
145+
impl Drop for SignalSubscription {
146+
fn drop(&mut self) {
147+
if let Some(id) = self.1.take() {
148+
#[allow(deprecated)]
149+
self.0.signal_unsubscribe(id);
150+
}
151+
}
152+
}
153+
154+
// rustdoc-stripper-ignore-next
155+
/// A weak subscription to a D-Bus signal.
156+
///
157+
/// Like [`SignalSubscription`] but hold only a weak reference to the D-Bus
158+
/// connection the siganl is subscribed on, i.e. maintain the subscription on
159+
/// the D-Bus signal only as long as some strong reference exists on the
160+
/// corresponding D-Bus connection.
161+
///
162+
/// When dropped, unsubscribes from signal on the connection if it still exists,
163+
/// and then drop the reference on the connection. If no other strong reference
164+
/// on the connection exists the connection is closed and destroyed.
165+
#[derive(Debug)]
166+
pub struct WeakSignalSubscription(WeakRef<DBusConnection>, Option<SignalSubscriptionId>);
167+
168+
impl WeakSignalSubscription {
169+
// rustdoc-stripper-ignore-next
170+
/// Upgrade this signal subscription to a strong one.
171+
#[must_use]
172+
pub fn upgrade(mut self) -> Option<SignalSubscription> {
173+
self.0
174+
.upgrade()
175+
.map(|c| SignalSubscription(c, self.1.take()))
176+
}
177+
}
178+
179+
impl Drop for WeakSignalSubscription {
180+
fn drop(&mut self) {
181+
if let Some(id) = self.1.take() {
182+
if let Some(connection) = self.0.upgrade() {
183+
#[allow(deprecated)]
184+
connection.signal_unsubscribe(id);
185+
}
186+
}
187+
}
188+
}
189+
123190
// rustdoc-stripper-ignore-next
124191
/// Build a registered DBus object, by handling different parts of DBus.
125192
#[must_use = "The builder must be built to be used"]
@@ -437,8 +504,45 @@ impl DBusConnection {
437504
}
438505
}
439506

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

509613
#[doc(alias = "g_dbus_connection_signal_unsubscribe")]
614+
#[deprecated(note = "Prefer subscribe_to_signal")]
510615
pub fn signal_unsubscribe(&self, subscription_id: SignalSubscriptionId) {
511616
unsafe {
512617
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)