You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/using-sdbus-c++.md
+63-10Lines changed: 63 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -759,7 +759,7 @@ private:
759
759
760
760
Analogously to the adaptor classes described above, there is one proxy class generated for one interface in the XML IDL file. The class is de facto a proxy to the concrete single interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child class. For each method, there is a public function member that calls the method remotely.
761
761
762
-
Generated proxy classes are not copyable and not moveable by design. One can create them on the heap and manage them in e.g. a `std::unique_ptr` if move semantics is needed (for example, when they are stored in a container).
762
+
Generated proxy classes are not copyable and not moveable by design. One can create them on the heap and manage them in e.g. a `std::unique_ptr` if move semantics is needed (for example, when they are stored in a container).
763
763
764
764
```cpp
765
765
/*
@@ -1130,11 +1130,11 @@ For a real example of a server-side asynchronous D-Bus method, please look at sd
1130
1130
Asynchronous client-side methods
1131
1131
--------------------------------
1132
1132
1133
-
sdbus-c++ also supports asynchronous approach at the client (the proxy) side. With this approach, we can issue a D-Bus method call without blocking current thread's execution while waiting for the reply. We go on doing other things, and when the reply comes, either a given callback handler will be invoked within the context of the event loop thread, or a future object returned by the async call will be set the returned value.6
1133
+
sdbus-c++ also supports asynchronous approach at the client (the proxy) side. With this approach, we can issue a D-Bus method call without blocking current thread's execution while waiting for the reply. We go on doing other things, and when the reply comes, either a given callback handler will be invoked within the context of the event loop thread, a future object returned by the async call will be set the returned value, or (with C++20) an awaitable can be `co_await`ed in a coroutine.
1134
1134
1135
1135
### Lower-level API
1136
1136
1137
-
Considering the Concatenator example based on lower-level API, if we wanted to call `concatenate` in an async way, we have two options: We either pass a callback to the proxy when issuing the call, and that callback gets invoked when the reply arrives:
1137
+
Considering the Concatenator example based on lower-level API, if we wanted to call `concatenate` in an async way, we have several options. We can pass a callback to the proxy when issuing the call, and that callback gets invoked when the reply arrives:
1138
1138
1139
1139
```c++
1140
1140
intmain(int argc, char *argv[])
@@ -1204,6 +1204,18 @@ Another option is to use `std::future`-based overload of the `IProxy::callMethod
1204
1204
}
1205
1205
```
1206
1206
1207
+
A third option, available with C++20, is to use `sdbus::with_awaitable` to get an `Awaitable<MethodReply>` that can be `co_await`ed in a coroutine:
1208
+
1209
+
```c++
1210
+
// In a coroutine context:
1211
+
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
1212
+
method << numbers << separator;
1213
+
auto reply = co_await concatenatorProxy->callMethod(method, sdbus::with_awaitable);
1214
+
std::string result;
1215
+
reply >> result;
1216
+
// If an error occurs, sdbus::Error is thrown when co_await completes
1217
+
```
1218
+
1207
1219
### Convenience API
1208
1220
1209
1221
On the convenience API level, the call statement starts with `callMethodAsync()`, and one option is to finish the statement with `uponReplyInvoke()` that takes a callback handler. The callback is a void-returning function that takes at least one argument: `std::optional<sdbus::Error>`. All subsequent arguments shall exactly reflect the D-Bus method output arguments. A concatenator example:
@@ -1264,6 +1276,18 @@ The future object will contain void for a void-returning D-Bus method, a single
1264
1276
...
1265
1277
```
1266
1278
1279
+
A third option, available with C++20, is to finish the async call statement with `getResultAsAwaitable<ReturnTypes...>()`, which returns an `Awaitable<T>` that can be `co_await`ed in a coroutine. The template arguments are the D-Bus method return types (empty for void-returning methods). The awaitable returns `void`, a single value, or a `std::tuple` for multiple return values:
1280
+
1281
+
```c++
1282
+
// In a coroutine context:
1283
+
auto result = co_await concatenatorProxy->callMethodAsync("concatenate")
1284
+
.onInterface(interfaceName)
1285
+
.withArguments(numbers, separator)
1286
+
.getResultAsAwaitable<std::string>();
1287
+
std::cout << "Got concatenate result: " << result << std::endl;
1288
+
// If an error occurs, sdbus::Error is thrown when co_await completes
1289
+
```
1290
+
1267
1291
### Marking client-side async methods in the IDL
1268
1292
1269
1293
sdbus-c++-xml2cpp can generate C++ code for client-side async methods. We just need to annotate the method with `org.freedesktop.DBus.Method.Async`. The annotation element value must be either `client` (async on the client-side only) or `client-server` (async method on both client- and server-side):
@@ -1286,19 +1310,39 @@ sdbus-c++-xml2cpp can generate C++ code for client-side async methods. We just n
1286
1310
</node>
1287
1311
```
1288
1312
1289
-
An asynchronous method can be generated as a callback-based method or `std::future`-based method. This can optionally be customized through an additional `org.freedesktop.DBus.Method.Async.ClientImpl` annotation. Its supported values are `callback`and `std::future`. The default behavior is callback-based method.
1313
+
An asynchronous method can be generated as a callback-based method, `std::future`-based method, or C++20 awaitable-based method. This can optionally be customized through an additional `org.freedesktop.DBus.Method.Async.ClientImpl` annotation. Its supported values are `callback`, `future`and `awaitable`. The default behavior is callback-based method.
1290
1314
1291
1315
#### Generating callback-based async methods
1292
1316
1293
1317
For each client-side async method, a corresponding `on<MethodName>Reply` pure virtual function, where `<MethodName>` is the capitalized D-Bus method name, is generated in the generated proxy class. This function is the callback invoked when the D-Bus method reply arrives, and must be provided a body by overriding it in the implementation class.
1294
1318
1295
1319
So in the specific example above, the tool will generate a `Concatenator_proxy` class similar to one shown in a [dedicated section above](#concatenator-client-glueh), with the difference that it will also generate an additional `virtual void onConcatenateReply(std::optional<sdbus::Error> error, const std::string& concatenatedString);` method, which we shall override in the derived `ConcatenatorProxy`.
1296
1320
1297
-
#### Generating std:future-based async methods
1321
+
#### Generating std::future-based async methods
1298
1322
1299
1323
In this case, a `std::future` is returned by the method, which will later, when the reply arrives, get set to contain the return value. Or if the call returns an error, `sdbus::Error` will be thrown by `std::future::get()`.
1300
1324
1301
-
For a real example of a client-side asynchronous D-Bus methods, please look at sdbus-c++ [stress tests](/tests/stresstests).
1325
+
#### Generating awaitable-based async methods
1326
+
1327
+
> **_Note_:** This requires C++20 support. The generated code uses `sdbus::Awaitable<T>` which requires compiling with C++20 or newer.
1328
+
1329
+
When using `awaitable` as the `ClientImpl` annotation value, the generated method returns an `sdbus::Awaitable<T>` that can be used with C++20 coroutines. The return type `T` is `void` for void-returning D-Bus methods, a single type for single-value methods, or `std::tuple<Types...>` for multi-value methods.
This generates a method that can be `co_await`ed: `std::string result = co_await proxy.concatenate({1, 2, 3}, ":");`
1344
+
1345
+
For a real example of a client-side asynchronous D-Bus methods, please look at sdbus-c++ [stress tests](/tests/stresstests) and [integration tests](/tests/integrationtests).
1302
1346
1303
1347
## Method call timeout
1304
1348
@@ -1338,7 +1382,7 @@ We read property value easily through `IProxy::getProperty()` method:
1338
1382
uint32_t status = proxy->getProperty("status").onInterface("org.sdbuscpp.Concatenator");
1339
1383
```
1340
1384
1341
-
Getting a property in asynchronous manner is also possible, in both callback-based and future-based way, by calling `IProxy::getPropertyAsync()` method:
1385
+
Getting a property in asynchronous manner is also possible, in callback-based, future-based, or (with C++20) awaitable way, by calling `IProxy::getPropertyAsync()` method:
More information on an `error` callback handler parameter, on behavior of `future` in erroneous situations, can be found in section [Asynchronous client-side methods](#asynchronous-client-side-methods).
Setting a property in asynchronous manner is also possible, in both callback-based and future-based way, by calling `IProxy::setPropertyAsync()` method:
1416
+
Setting a property in asynchronous manner is also possible, in callback-based, future-based, or awaitable way, by calling `IProxy::setPropertyAsync()` method:
1368
1417
1369
1418
```c++
1370
1419
// Callback-based method:
1371
1420
auto callback = [](std::optional<sdbus::Error> error { /*... Error handling in case error contains a value...*/ };
1372
1421
uint32_t status = proxy->setPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").toValue(status).uponReplyInvoke(std::move(callback));
More information on `error` callback handler parameter, on behavior of `future` in erroneous situations, can be found in section [Asynchronous client-side methods](#asynchronous-client-side-methods).
@@ -1468,7 +1521,7 @@ When implementing the adaptor, we simply need to provide the body for the `statu
1468
1521
1469
1522
We can mark the property so that the generator generates either asynchronous variant of getter method, or asynchronous variant of setter method, or both. Annotations names are `org.freedesktop.DBus.Property.Get.Async`, or `org.freedesktop.DBus.Property.Set.Async`, respectively. Their values must be set to `client`.
1470
1523
1471
-
In addition, we can choose through annotations `org.freedesktop.DBus.Property.Get.Async.ClientImpl`, or `org.freedesktop.DBus.Property.Set.Async.ClientImpl`, respectively, whether a callback-based or future-basedvariant will be generated. The concept is analogous to the one for asynchronous D-Bus methods described above in this document.
1524
+
In addition, we can choose through annotations `org.freedesktop.DBus.Property.Get.Async.ClientImpl`, or `org.freedesktop.DBus.Property.Set.Async.ClientImpl`, respectively, whether a callback-based, future-based, or awaitable variant will be generated. Supported values are `callback`, `future`, and `awaitable`. The concept is analogous to the one for asynchronous D-Bus methods described above in this document.
1472
1525
1473
1526
The callback-based method will generate a pure virtual function `On<PropertyName>Property[Get|Set]Reply()`, which must be overridden by the derived class.
1474
1527
@@ -1679,7 +1732,7 @@ The macro must be placed in the global namespace. The first argument is the stru
1679
1732
1680
1733
This is described in detail in the following sections.
1681
1734
1682
-
> **_Note_:** The macro supports **max 16structmembers**. If you need more, feel free to open an issue, or implement the teaching code yourself :o)
1735
+
> **_Note_:** The macro supports **max 16structmembers**. If you need more, feel free to open an issue, or implement the teaching code yourself :o)
1683
1736
1684
1737
> **_Another note_:** You may have noticed one of `my::Struct` members is `std::list`. Thanks to the custom support for `std::list` implemented higher above, it's now automatically accepted by sdbus-c++ as a D-Bus array representation.
0 commit comments