Skip to content

Commit 9f09c42

Browse files
authored
Merge pull request #1584 from sdroege/gdbus-method-call-nullability
gio: Fix nullability of various DBus method call related parameters
2 parents 478854c + b7be698 commit 9f09c42

File tree

5 files changed

+207
-19
lines changed

5 files changed

+207
-19
lines changed

examples/gio_dbus_register_object/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ enum HelloMethod {
4040
impl DBusMethodCall for HelloMethod {
4141
fn parse_call(
4242
_obj_path: &str,
43-
_interface: &str,
43+
_interface: Option<&str>,
4444
method: &str,
4545
params: glib::Variant,
4646
) -> Result<Self, glib::Error> {
@@ -65,7 +65,7 @@ fn on_startup(app: &gio::Application, tx: &Sender<gio::RegistrationId>) {
6565
.register_object("/com/github/gtk_rs/examples/HelloWorld", &example)
6666
.typed_method_call::<HelloMethod>()
6767
.invoke_and_return_future_local(|_, sender, call| {
68-
println!("Method call from {sender}");
68+
println!("Method call from {sender:?}");
6969
async {
7070
match call {
7171
HelloMethod::Hello(Hello { name }) => {

gio/Gir.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,16 @@ status = "generate"
644644
name = "return_error_literal"
645645
# glib::ErrorDomain
646646
manual = true
647-
647+
[[object.function]]
648+
name = "get_sender"
649+
[object.function.return]
650+
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4414
651+
nullable = true
652+
[[object.function]]
653+
name = "get_interface_name"
654+
[object.function.return]
655+
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4414
656+
nullable = true
648657

649658
[[object]]
650659
name = "Gio.DBusProxy"

gio/src/auto/dbus_method_invocation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl DBusMethodInvocation {
3333

3434
#[doc(alias = "g_dbus_method_invocation_get_interface_name")]
3535
#[doc(alias = "get_interface_name")]
36-
pub fn interface_name(&self) -> glib::GString {
36+
pub fn interface_name(&self) -> Option<glib::GString> {
3737
unsafe {
3838
from_glib_none(ffi::g_dbus_method_invocation_get_interface_name(
3939
self.to_glib_none().0,
@@ -103,7 +103,7 @@ impl DBusMethodInvocation {
103103

104104
#[doc(alias = "g_dbus_method_invocation_get_sender")]
105105
#[doc(alias = "get_sender")]
106-
pub fn sender(&self) -> glib::GString {
106+
pub fn sender(&self) -> Option<glib::GString> {
107107
unsafe {
108108
from_glib_none(ffi::g_dbus_method_invocation_get_sender(
109109
self.to_glib_none().0,

gio/src/dbus_connection.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use glib::{prelude::*, translate::*};
1111
pub trait DBusMethodCall: Sized {
1212
fn parse_call(
1313
obj_path: &str,
14-
interface: &str,
14+
interface: Option<&str>,
1515
method: &str,
1616
params: glib::Variant,
1717
) -> Result<Self, glib::Error>;
@@ -46,7 +46,7 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
4646
/// safer interface where the callback returns a result directly.
4747
pub fn invoke<F>(self, f: F) -> RegistrationBuilder<'a>
4848
where
49-
F: Fn(DBusConnection, &str, T, DBusMethodInvocation) + 'static,
49+
F: Fn(DBusConnection, Option<&str>, T, DBusMethodInvocation) + 'static,
5050
{
5151
self.registration.method_call(
5252
move |connection, sender, obj_path, interface, method, params, invocation| {
@@ -74,7 +74,8 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
7474
/// See [`DBusMethodInvocation::return_result`] for details.
7575
pub fn invoke_and_return<F>(self, f: F) -> RegistrationBuilder<'a>
7676
where
77-
F: Fn(DBusConnection, &str, T) -> Result<Option<glib::Variant>, glib::Error> + 'static,
77+
F: Fn(DBusConnection, Option<&str>, T) -> Result<Option<glib::Variant>, glib::Error>
78+
+ 'static,
7879
{
7980
self.invoke(move |connection, sender, call, invocation| {
8081
invocation.return_result(f(connection, sender, call))
@@ -97,7 +98,7 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
9798
/// See [`DBusMethodInvocation::return_future_local`] for details.
9899
pub fn invoke_and_return_future_local<F, Fut>(self, f: F) -> RegistrationBuilder<'a>
99100
where
100-
F: Fn(DBusConnection, &str, T) -> Fut + 'static,
101+
F: Fn(DBusConnection, Option<&str>, T) -> Fut + 'static,
101102
Fut: Future<Output = Result<Option<glib::Variant>, glib::Error>> + 'static,
102103
{
103104
self.invoke(move |connection, sender, call, invocation| {
@@ -128,18 +129,37 @@ pub struct RegistrationBuilder<'a> {
128129
interface_info: &'a DBusInterfaceInfo,
129130
#[allow(clippy::type_complexity)]
130131
method_call: Option<
131-
Box_<dyn Fn(DBusConnection, &str, &str, &str, &str, glib::Variant, DBusMethodInvocation)>,
132+
Box_<
133+
dyn Fn(
134+
DBusConnection,
135+
Option<&str>,
136+
&str,
137+
Option<&str>,
138+
&str,
139+
glib::Variant,
140+
DBusMethodInvocation,
141+
),
142+
>,
132143
>,
133144
#[allow(clippy::type_complexity)]
134-
get_property: Option<Box_<dyn Fn(DBusConnection, &str, &str, &str, &str) -> glib::Variant>>,
145+
get_property:
146+
Option<Box_<dyn Fn(DBusConnection, Option<&str>, &str, &str, &str) -> glib::Variant>>,
135147
#[allow(clippy::type_complexity)]
136148
set_property:
137-
Option<Box_<dyn Fn(DBusConnection, &str, &str, &str, &str, glib::Variant) -> bool>>,
149+
Option<Box_<dyn Fn(DBusConnection, Option<&str>, &str, &str, &str, glib::Variant) -> bool>>,
138150
}
139151

140152
impl<'a> RegistrationBuilder<'a> {
141153
pub fn method_call<
142-
F: Fn(DBusConnection, &str, &str, &str, &str, glib::Variant, DBusMethodInvocation) + 'static,
154+
F: Fn(
155+
DBusConnection,
156+
Option<&str>,
157+
&str,
158+
Option<&str>,
159+
&str,
160+
glib::Variant,
161+
DBusMethodInvocation,
162+
) + 'static,
143163
>(
144164
mut self,
145165
f: F,
@@ -162,7 +182,9 @@ impl<'a> RegistrationBuilder<'a> {
162182
}
163183

164184
#[doc(alias = "get_property")]
165-
pub fn property<F: Fn(DBusConnection, &str, &str, &str, &str) -> glib::Variant + 'static>(
185+
pub fn property<
186+
F: Fn(DBusConnection, Option<&str>, &str, &str, &str) -> glib::Variant + 'static,
187+
>(
166188
mut self,
167189
f: F,
168190
) -> Self {
@@ -171,7 +193,7 @@ impl<'a> RegistrationBuilder<'a> {
171193
}
172194

173195
pub fn set_property<
174-
F: Fn(DBusConnection, &str, &str, &str, &str, glib::Variant) -> bool + 'static,
196+
F: Fn(DBusConnection, Option<&str>, &str, &str, &str, glib::Variant) -> bool + 'static,
175197
>(
176198
mut self,
177199
f: F,
@@ -191,9 +213,9 @@ impl<'a> RegistrationBuilder<'a> {
191213
.map(|f| {
192214
glib::Closure::new_local(move |args| {
193215
let conn = args[0].get::<DBusConnection>().unwrap();
194-
let sender = args[1].get::<&str>().unwrap();
216+
let sender = args[1].get::<Option<&str>>().unwrap();
195217
let object_path = args[2].get::<&str>().unwrap();
196-
let interface_name = args[3].get::<&str>().unwrap();
218+
let interface_name = args[3].get::<Option<&str>>().unwrap();
197219
let method_name = args[4].get::<&str>().unwrap();
198220
let parameters = args[5].get::<glib::Variant>().unwrap();
199221
let invocation = args[6].get::<DBusMethodInvocation>().unwrap();
@@ -215,7 +237,7 @@ impl<'a> RegistrationBuilder<'a> {
215237
.map(|f| {
216238
glib::Closure::new_local(move |args| {
217239
let conn = args[0].get::<DBusConnection>().unwrap();
218-
let sender = args[1].get::<&str>().unwrap();
240+
let sender = args[1].get::<Option<&str>>().unwrap();
219241
let object_path = args[2].get::<&str>().unwrap();
220242
let interface_name = args[3].get::<&str>().unwrap();
221243
let property_name = args[4].get::<&str>().unwrap();
@@ -237,7 +259,7 @@ impl<'a> RegistrationBuilder<'a> {
237259
.map(|f| {
238260
glib::Closure::new_local(move |args| {
239261
let conn = args[0].get::<DBusConnection>().unwrap();
240-
let sender = args[1].get::<&str>().unwrap();
262+
let sender = args[1].get::<Option<&str>>().unwrap();
241263
let object_path = args[2].get::<&str>().unwrap();
242264
let interface_name = args[3].get::<&str>().unwrap();
243265
let property_name = args[4].get::<&str>().unwrap();

gio/tests/dbus_peer.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
#[cfg(unix)]
4+
#[test]
5+
fn test_gdbus_peer_connection() {
6+
use gio::{
7+
glib::{self, VariantTy},
8+
prelude::*,
9+
DBusConnection, DBusConnectionFlags, DBusNodeInfo, Socket,
10+
};
11+
use std::os::{fd::IntoRawFd, unix::net::UnixStream};
12+
13+
const EXAMPLE_XML: &str = r#"
14+
<node>
15+
<interface name='com.github.gtk_rs'>
16+
<method name='Hello'>
17+
<arg type='s' name='name' direction='in'/>
18+
<arg type='s' name='greet' direction='out'/>
19+
</method>
20+
</interface>
21+
</node>
22+
"#;
23+
24+
pub async fn spawn_server(fd: UnixStream) -> DBusConnection {
25+
let socket = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
26+
let socket_connection = socket.connection_factory_create_connection();
27+
28+
let guid = gio::dbus_generate_guid();
29+
30+
dbg!("server connecting");
31+
32+
let connection = DBusConnection::new_future(
33+
&socket_connection,
34+
Some(&guid),
35+
DBusConnectionFlags::AUTHENTICATION_SERVER
36+
.union(DBusConnectionFlags::DELAY_MESSAGE_PROCESSING),
37+
None,
38+
)
39+
.await
40+
.unwrap();
41+
42+
dbg!("server connected");
43+
44+
let interface_info = DBusNodeInfo::for_xml(EXAMPLE_XML)
45+
.unwrap()
46+
.lookup_interface("com.github.gtk_rs")
47+
.unwrap();
48+
49+
let _id = connection
50+
.register_object("/com/github/gtk_rs", &interface_info)
51+
.method_call(
52+
|_connection,
53+
_sender,
54+
_object_path,
55+
_interface_name,
56+
_method_name,
57+
parameters,
58+
invocation| {
59+
dbg!(
60+
_sender,
61+
_object_path,
62+
_interface_name,
63+
_method_name,
64+
&parameters,
65+
&invocation
66+
);
67+
68+
let name = parameters.child_get::<String>(0);
69+
invocation.return_value(Some(&(format!("Hello {name}!"),).to_variant()));
70+
},
71+
)
72+
.build()
73+
.unwrap();
74+
75+
dbg!("server starts message processing");
76+
77+
connection.start_message_processing();
78+
79+
dbg!("server awaiting calls");
80+
81+
connection
82+
}
83+
84+
pub async fn spawn_client(fd: UnixStream) -> DBusConnection {
85+
let socket_client = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
86+
let socket_connection_client = socket_client.connection_factory_create_connection();
87+
88+
dbg!("client connecting");
89+
90+
let connection = DBusConnection::new_future(
91+
&socket_connection_client,
92+
None,
93+
DBusConnectionFlags::AUTHENTICATION_CLIENT,
94+
None,
95+
)
96+
.await
97+
.unwrap();
98+
99+
dbg!("client connected");
100+
101+
connection
102+
}
103+
104+
let ctx = glib::MainContext::default();
105+
106+
let (x, y) = std::os::unix::net::UnixStream::pair().unwrap();
107+
108+
x.set_nonblocking(true).unwrap();
109+
y.set_nonblocking(true).unwrap();
110+
111+
ctx.block_on(async move {
112+
let ctx = glib::MainContext::default();
113+
114+
let server = ctx.spawn_local(spawn_server(x));
115+
let client = ctx.spawn_local(spawn_client(y));
116+
117+
let server = server.await.unwrap();
118+
let client = client.await.unwrap();
119+
120+
dbg!("calling method");
121+
122+
let result = client
123+
.call_future(
124+
None,
125+
"/com/github/gtk_rs",
126+
"com.github.gtk_rs",
127+
"Hello",
128+
Some(&("World",).into()),
129+
Some(VariantTy::new("(s)").unwrap()),
130+
gio::DBusCallFlags::NONE,
131+
10000,
132+
)
133+
.await
134+
.unwrap();
135+
136+
dbg!("method called");
137+
138+
dbg!(&result);
139+
140+
dbg!("closing client");
141+
client.close_future().await.unwrap();
142+
dbg!("closed client, closing server");
143+
server.close_future().await.unwrap();
144+
dbg!("closed server");
145+
146+
drop(client);
147+
drop(server);
148+
149+
assert_eq!(result.child_get::<String>(0), "Hello World!");
150+
151+
glib::timeout_future_with_priority(
152+
glib::Priority::LOW,
153+
std::time::Duration::from_millis(50),
154+
)
155+
.await;
156+
});
157+
}

0 commit comments

Comments
 (0)