Compare commits

...
13 Commits
Author SHA1 Message Date
Oliver FacklamandStanislav Angelovič 0b9b15cbac fix: prevent ambiguous call by calling signal handler with std::nullopt (#541)
Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
2026-06-08 20:21:54 +02:00
b5c352700f feat: allow custom direct callbacks in proxy generator (#540)
Co-authored-by: Pavel Pletnev <pletnev_pg@nectech.pro>
Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
2026-06-08 13:13:22 +02:00
Stanislav Angelovič ca073434d2 chore: release version v2.3.1 2026-05-20 14:36:18 +02:00
Stanislav Angelovič ca69493b20 fix: move new virtual functions to the end of the class (#539)
This fixes ABI compatibility issue of the recent version.
2026-05-20 14:34:10 +02:00
Stanislav Angelovič fbe77629bc chore: release version v2.3.0 2026-05-17 14:25:54 +02:00
Stanislav Angelovič b042f4e13d ci: fix ctest run (#533)
There was a bug which caused no tests to be run in the CI jobs.
2026-04-20 14:54:54 +02:00
Alex CaniandStanislav Angelovič eb05ed5d18 feat: add coroutine support for client-side async calls (#527)
C++ 20 introduced coroutine support to the language, enabling writing
asynchronous code using the co_await, co_return and co_yield operators.
Similar to other languages, coroutines allow functions to suspend
execution at certain points and later resume from where they left off,
without blocking the calling thread.

Coroutines are a natural fit for any sort of IO-bound asynchronous
operations, such as D-Bus communication.

This PR introduces native coroutine support in sdbus-c++ by the means of
the Awaitable<T> class, a type that implements the C++20 awaitable
protocol, allowing D-Bus method calls to be awaited in coroutines.

Summary of the changes:

Core library:

* New Awaitable<T> type that can be co_awaited, which suspends a running
  coroutine. When the result or error of a method call arrives, the
  coroutine is resumed and the result/error is returned.
  Implementation is done in a thread-safe way, meaning there are no race
  conditions between the awaitable object returned by asynchronous calls
  and the callback invoked by the event loop upon arrival of a message.
  Naturally, it works in the single-threaded scenario as well, where the
  connection event loop may be driven externally and/or integrated in a
  full fledged coroutine runtime.
* Low-level API: new callMethodAsync() overloads accepting
  with_awaitable_t tag and returning Awaitable<MethodReply>.
* High-level API: new getResultAsAwaitable methods in the relevant
  high-level API helpers, covering methods and properties.
  StandardInterfaces.h classes have also been updated to expose
  awaitable-based methods.
* Integration tests for both low-level and high-level APIs.

Codegen:

* Added support for generating awaitable-based async methods in the
  xml2cpp tool through new values for the
  org.freedesktop.DBus.Method.Async.ClientImpl and
  org.freedesktop.DBus.Property.[Get/Set].Async.ClientImpl annotations.

---------

Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
2026-04-20 10:41:04 +02:00
DespinaRizkanddespinarizk 7363944751 fix: replace incorrect variable 's' with 'source' in deleteSdEventSource (#528)
Co-authored-by: despinarizk <despina.rizk@inmind.ai>
2026-03-04 23:44:02 +01:00
Stanislav Angelovič c2bb343f8a feat: add support for dumping variant to string (#526)
This allows Message and Variant contents serialization to a string -- based on `sd_bus_message_dump` sd-bus API function.
2026-01-15 23:24:54 +01:00
Stanislav Angelovič 9f3e89eb6a feat: use clang-tidy for static analysis (#495) 2026-01-15 14:38:33 +01:00
Michael NosthoffandStanislav Angelovič 6f694e3fd3 fix: add deduction guides for Struct from std::tuple (#525)
* Types.h: add deduction guides for Struct from std::tuple

C++23 changed the generation of implicit deduction guides. This causes
the compiler to also see deduction guides for std::tuple as candidates
for sdbus::Struct.
Because of the competing guides the compiler doesn't know which one to pick.

This seems to be implemented from gcc 15 on and is thus causing breakage there.

To fix this we need to add explicit deduction guides when std::tuple is passed
to sdbus::Struct.

fixes https://github.com/Kistler-Group/sdbus-cpp/issues/524

* refactor: remove std::decay_t wrapper

We need to be able to create sdbus::Structs
with element types being references.

---------

Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
2026-01-15 12:39:22 +01:00
Robert AdamandStanislav Angelovič 44aa4f080f feat(cmake): add export support (#523)
* feat: add export support

This makes sdbus-c++ consumable from the build tree without the need for
an explicit installation. This can be very handy for e.g. testing
purposes. Crucially, downstream projects will depend on upstream to
properly export everything. Otherwise, they can't be built as static
libraries, even if sdbus-c++ is only a private dependency.

See also https://runebook.dev/en/docs/cmake/command/export

* fix(cmake): avoid possibly empty EXPORT_SET

EXPORT_SET is empty when SDBUSCPP_INSTALL is OFF,
which leads to targets file with no targets.

---------

Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
2026-01-06 20:11:05 +01:00
Robert Adam 6715ef1fc3 feat: create cmake alias for consistent downstream usage (#522)
At the moment, downstream projects will have to differentiate based off the way the obtained sdbus-c++ in CMake. If they use `find_package`, the target they have to use is `SDBusCpp::sdbus-c++`, whereas the target is merely `sdbus-c++` if they use `FetchContent` (i.e. use without installation).

By creating an alias target, it is now always possible to use the `DBusCpp::sdbus-c++` target regardless of how the library was obtained.
2025-12-31 12:48:26 +01:00
100 changed files with 3450 additions and 2110 deletions
+66
View File
@@ -0,0 +1,66 @@
---
# TODO: enable -llvm-include-order in the end, after clang-format
Checks: "*,\
-llvmlibc-*,\
-altera-*,\
-fuchsia-*,
-cert-err58-cpp,\
-modernize-use-trailing-return-type,\
-cppcoreguidelines-avoid-magic-numbers,\
-readability-magic-numbers,\
-readability-braces-around-statements,\
-google-readability-braces-around-statements,\
-hicpp-braces-around-statements,\
-hicpp-signed-bitwise,\
-llvm-include-order,\
-llvm-header-guard,\
-google-runtime-int,\
-google-default-arguments,\
-hicpp-named-parameter,\
-readability-named-parameter,\
-bugprone-macro-parentheses,\
-google-readability-todo,\
-google-build-using-namespace,\
-cppcoreguidelines-pro-type-reinterpret-cast,\
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,\
-hicpp-no-array-decay,\
-cppcoreguidelines-avoid-c-arrays,\
-hicpp-avoid-c-arrays,\
-cppcoreguidelines-non-private-member-variables-in-classes,\
-misc-non-private-member-variables-in-classes,\
-modernize-avoid-c-arrays"
HeaderFilterRegex: '.*'
FormatStyle: file
WarningsAsErrors: "*"
CheckOptions:
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '1'
- key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '1'
- key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
value: '1'
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: '1'
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: '1'
- key: readability-identifier-length.IgnoredVariableNames
value: 'r|t|fd|id|ok|it|ts'
- key: readability-identifier-length.IgnoredParameterNames
value: 'fd|id|b'
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: '0'
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove
value: '0'
- key: misc-include-cleaner.IgnoreHeaders
value: 'systemd/.*|sdbus-c\+\+/.*|gtest/.*|gmock/.*|bits/chrono.h|bits/basic_string.h|time.h|poll.h|stdlib.h|stdio.h'
- key: readability-simplify-boolean-expr.IgnoreMacros
value: '1'
- key: cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams
value: '1'
# - key: bugprone-easily-swappable-parameters.MinimumLength
# value: '3'
# - key: readability-braces-around-statements.ShortStatementLines
# value: '3'
+30 -17
View File
@@ -46,34 +46,26 @@ jobs:
- name: configure-debug-gcc11 # For gcc 11, turn off the annoying deprecated-copy warning
if: matrix.build == 'shared-libsystemd' && matrix.compiler == 'g++' && matrix.os == 'ubuntu-22.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Wno-deprecated-copy -Werror $SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0 ..
cmake -B _build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Wno-deprecated-copy -Werror $SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0
- name: configure-debug
if: matrix.build == 'shared-libsystemd' && (matrix.compiler != 'g++' || matrix.os != 'ubuntu-22.04')
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror $SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0 ..
cmake -B _build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror $SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0
- name: configure-release-with-embedded-libsystemd
if: matrix.build == 'embedded-static-libsystemd'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="$SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_BUILD_LIBSYSTEMD=ON -DSDBUSCPP_LIBSYSTEMD_VERSION=252 -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0 ..
cmake -B _build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="$SDBUSCPP_EXTRA_CXX_FLAGS" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_BUILD_LIBSYSTEMD=ON -DSDBUSCPP_LIBSYSTEMD_VERSION=252 -DSDBUSCPP_GOOGLETEST_VERSION=1.14.0
- name: make
run: |
cd build
cmake --build . -j4
cmake --build _build -j4
- name: verify
run: |
cd build
sudo cmake --build . --target install
ctest --output-on-failure
sudo cmake --build _build --target install
ctest --output-on-failure --test-dir _build
- name: pack
if: matrix.build == 'shared-libsystemd'
run: |
cd build
cd _build
cpack -G DEB
- name: 'Upload Artifact'
if: matrix.build == 'shared-libsystemd' && matrix.compiler == 'g++'
@@ -81,9 +73,30 @@ jobs:
with:
name: "debian-packages-${{ matrix.os }}-${{ matrix.compiler }}"
path: |
build/sdbus-c++*.deb
build/sdbus-c++*.ddeb
_build/sdbus-c++*.deb
_build/sdbus-c++*.ddeb
retention-days: 10
static-analysis:
name: static-analysis (ubuntu-24.04, clang-tidy, shared-libsystemd)
runs-on: ubuntu-24.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: install-deps
run: |
sudo apt-get update -y
sudo apt-get install -y libsystemd-dev libgmock-dev clang
sudo update-alternatives --remove-all cc
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 10
sudo update-alternatives --remove-all c++
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 10
- name: configure
run: |
cmake -B _build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_CLANG_TIDY=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DSDBUSCPP_BUILD_EXAMPLES=ON
- name: make
run: |
cmake --build _build -j4
freebsd-build:
name: build (freebsd, clang/libc++, basu)
runs-on: ubuntu-22.04 # until https://github.com/actions/runner/issues/385
+3
View File
@@ -16,6 +16,9 @@ tests/run-test-on-device.sh
.settings
*.log
# vscode
.vscode/
#autotools
sdbus-cpp.pc
*Makefile
+22 -7
View File
@@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.14)
project(sdbus-c++ VERSION 2.2.1 LANGUAGES CXX C)
project(sdbus-c++ VERSION 2.3.1 LANGUAGES CXX C)
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
@@ -35,7 +35,7 @@ option(SDBUSCPP_BUILD_DOCS "Build documentation for sdbus-c++" ON)
if(SDBUSCPP_BUILD_DOCS)
option(SDBUSCPP_BUILD_DOXYGEN_DOCS "Build doxygen documentation for sdbus-c++ API" OFF)
endif()
#option(SDBUSCPP_CLANG_TIDY "Co-compile with clang-tidy static analyzer" OFF)
option(SDBUSCPP_CLANG_TIDY "Co-compile with clang-tidy static analyzer" OFF)
#option(SDBUSCPP_COVERAGE "Build sdbus-c++ with code coverage instrumentation" OFF)
# We promote the BUILD_SHARED_LIBS flag to a (global) option only if we are the main project
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
@@ -130,6 +130,8 @@ endif()
find_package(Threads REQUIRED)
include(cmake/clang-tidy.cmake) # Static analysis with clang-tidy
#-------------------------------
# SOURCE FILES CONFIGURATION
#-------------------------------
@@ -162,6 +164,7 @@ set(SDBUSCPP_HDR_SRCS
${SDBUSCPP_SOURCE_DIR}/ISdBus.h)
set(SDBUSCPP_PUBLIC_HDRS
${SDBUSCPP_INCLUDE_DIR}/Awaitable.h
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.h
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.inl
${SDBUSCPP_INCLUDE_DIR}/VTableItems.h
@@ -216,6 +219,9 @@ target_link_libraries(sdbus-c++-objlib
Threads::Threads)
add_library(sdbus-c++)
# Create alias to allow consistent target use regardless whether used in-source or found via find_package
add_library(SDBusCpp::sdbus-c++ ALIAS sdbus-c++)
target_include_directories(sdbus-c++ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
set_target_properties(sdbus-c++
@@ -281,14 +287,23 @@ set(PKGCONFIG_DEPS ${SDBUS_LIB})
configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY)
#----------------------------------
# INSTALLATION
# EXPORTING BUILD-TREE TARGETS
#----------------------------------
set(EXPORT_SET sdbus-c++)
if(NOT BUILD_SHARED_LIBS)
list(APPEND EXPORT_SET "sdbus-c++-objlib")
endif()
export(TARGETS ${EXPORT_SET}
NAMESPACE SDBusCpp::
FILE sdbus-c++-targets.cmake)
#----------------------------------
# INSTALLATION & EXPORTING INSTALL-TREE TARGETS
#----------------------------------
if(SDBUSCPP_INSTALL)
set(EXPORT_SET sdbus-c++)
if(NOT BUILD_SHARED_LIBS)
list(APPEND EXPORT_SET "sdbus-c++-objlib")
endif()
install(TARGETS ${EXPORT_SET}
EXPORT sdbus-c++-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT sdbus-c++-runtime
+10
View File
@@ -315,3 +315,13 @@ v2.2.0
v2.2.1
- Fix component names in CPack configuration
- Generate correct, expected DEB package names
v2.3.0
- Add coroutine support for client-side async calls
- Add support for dumping variant to string
- Introduce clang-tidy for static analysis and fix issues
- Add deduction guides for Struct from std::tuple
- Other fixes and improvements
v2.3.1
- Fix ABI compat issue by moving new virtual functions to the end of the class
+16
View File
@@ -0,0 +1,16 @@
#----------------------------------
# STATIC ANALYSIS
#----------------------------------
if(SDBUSCPP_CLANG_TIDY)
message(STATUS "Building with static analysis")
find_program(CLANG_TIDY NAMES clang-tidy)
if(NOT CLANG_TIDY)
message(WARNING "clang-tidy not found")
else()
message(STATUS "clang-tidy found: ${CLANG_TIDY}")
set(DO_CLANG_TIDY "${CLANG_TIDY}")
#set(DO_CLANG_TIDY "${CLANG_TIDY}" "-fix")
set(CMAKE_CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif()
endif()
+71 -14
View File
@@ -611,10 +611,10 @@ We recommend that sdbus-c++ users prefer the convenience API to the lower level,
> **_Note_:** By default, signal callback handlers are not invoked (i.e., the signal is silently dropped) if there is a signal signature mismatch. If you want to be informed of such situations, you can add `std::optional<sdbus::Error>` parameter to the beginning of your signal callback handler's parameter list. When sdbus-c++ invokes the handler, it will set this argument either to be empty (in normal cases), or to carry a corresponding `sdbus::Error` object (in case of deserialization failures, like type mismatches). An example of a handler with the signature (`int`) different from the real signal contents (`string`):
> ```c++
> void onConcatenated(std::optional<sdbus::Error> e, int wrongParameter)
> void onConcatenated(std::optional<sdbus::Error> err, int wrongParameter)
> {
> assert(e.has_value());
> assert(e->getMessage() == "Failed to deserialize a int32 value");
> assert(err.has_value());
> assert(err->getMessage() == "Failed to deserialize a int32 value");
> }
> ```
> Signature mismatch in signal handlers is probably the most common reason why signals are not received in the client, while we can see them on the bus with `dbus-monitor`. Use `std::optional<sdbus::Error>`-based callback variant and inspect the error to check if that's the cause of your problems.
@@ -759,7 +759,7 @@ private:
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.
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).
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).
```cpp
/*
@@ -1130,11 +1130,11 @@ For a real example of a server-side asynchronous D-Bus method, please look at sd
Asynchronous client-side methods
--------------------------------
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
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.
### Lower-level API
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:
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:
```c++
int main(int argc, char *argv[])
@@ -1204,6 +1204,18 @@ Another option is to use `std::future`-based overload of the `IProxy::callMethod
}
```
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:
```c++
// In a coroutine context:
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
method << numbers << separator;
auto reply = co_await concatenatorProxy->callMethod(method, sdbus::with_awaitable);
std::string result;
reply >> result;
// If an error occurs, sdbus::Error is thrown when co_await completes
```
### Convenience API
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
...
```
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:
```c++
// In a coroutine context:
auto result = co_await concatenatorProxy->callMethodAsync("concatenate")
.onInterface(interfaceName)
.withArguments(numbers, separator)
.getResultAsAwaitable<std::string>();
std::cout << "Got concatenate result: " << result << std::endl;
// If an error occurs, sdbus::Error is thrown when co_await completes
```
### Marking client-side async methods in the IDL
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,43 @@ sdbus-c++-xml2cpp can generate C++ code for client-side async methods. We just n
</node>
```
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.
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`, `direct-callback`, `future` and `awaitable`. The default behavior is callback-based method.
#### Generating callback-based async methods
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.
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`.
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(const std::string& concatenatedString, std::optional<sdbus::Error> error);` method, which we shall override in the derived `ConcatenatorProxy`.
#### Generating std:future-based async methods
#### Generating direct callback-based async methods
An additional callback parameter is added to the function signature. The callback is called when the D-Bus method reply arrives. The callback can be any generic callable that takes the method output arguments (`const std::string&` in this example), followed by the parameter of type `std::optional<sdbus::Error> error`.
#### Generating std::future-based async methods
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()`.
For a real example of a client-side asynchronous D-Bus methods, please look at sdbus-c++ [stress tests](/tests/stresstests).
#### Generating awaitable-based async methods
> **_Note_:** This requires C++20 support. The generated code uses `sdbus::Awaitable<T>` which requires compiling with C++20 or newer.
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.
Example annotation:
```xml
<method name="concatenate">
<annotation name="org.freedesktop.DBus.Method.Async" value="client" />
<annotation name="org.freedesktop.DBus.Method.Async.ClientImpl" value="awaitable" />
<arg type="ai" name="numbers" direction="in" />
<arg type="s" name="separator" direction="in" />
<arg type="s" name="concatenatedString" direction="out" />
</method>
```
This generates a method that can be `co_await`ed: `std::string result = co_await proxy.concatenate({1, 2, 3}, ":");`
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).
## Method call timeout
@@ -1338,7 +1386,7 @@ We read property value easily through `IProxy::getProperty()` method:
uint32_t status = proxy->getProperty("status").onInterface("org.sdbuscpp.Concatenator");
```
Getting a property in asynchronous manner is also possible, in both callback-based and future-based way, by calling `IProxy::getPropertyAsync()` method:
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:
```c++
// Callback-based method:
@@ -1347,10 +1395,15 @@ auto callback = [](std::optional<sdbus::Error> /*error*/, sdbus::Variant value)
std::cout << "Got property value: " << value.get<uint32_t>() << std::endl;
};
uint32_t status = proxy->getPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").uponReplyInvoke(std::move(callback));
// Future-based method:
std::future<sdbus::Variant> statusFuture = object.getPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").getResultAsFuture();
...
std::cout << "Got property value: " << statusFuture.get().get<uint32_t>() << std::endl;
// Awaitable method (C++20):
auto value = co_await proxy->getPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").getResultAsAwaitable();
std::cout << "Got property value: " << value.get<uint32_t>() << std::endl;
```
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).
@@ -1364,14 +1417,18 @@ uint32_t status = ...;
proxy->setProperty("status").onInterface("org.sdbuscpp.Concatenator").toValue(status);
```
Setting a property in asynchronous manner is also possible, in both callback-based and future-based way, by calling `IProxy::setPropertyAsync()` method:
Setting a property in asynchronous manner is also possible, in callback-based, future-based, or awaitable way, by calling `IProxy::setPropertyAsync()` method:
```c++
// Callback-based method:
auto callback = [](std::optional<sdbus::Error> error { /*... Error handling in case error contains a value...*/ };
uint32_t status = proxy->setPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").toValue(status).uponReplyInvoke(std::move(callback));
// Future-based method:
std::future<void> statusFuture = object.setPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").getResultAsFuture();
// Awaitable method (C++20):
co_await proxy->setPropertyAsync("status").onInterface("org.sdbuscpp.Concatenator").toValue(status).getResultAsAwaitable();
```
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 +1525,7 @@ When implementing the adaptor, we simply need to provide the body for the `statu
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`.
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-based variant will be generated. The concept is analogous to the one for asynchronous D-Bus methods described above in this document.
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.
The callback-based method will generate a pure virtual function `On<PropertyName>Property[Get|Set]Reply()`, which must be overridden by the derived class.
@@ -1679,7 +1736,7 @@ The macro must be placed in the global namespace. The first argument is the stru
This is described in detail in the following sections.
> **_Note_:** The macro supports **max 16 struct members**. If you need more, feel free to open an issue, or implement the teaching code yourself :o)
> **_Note_:** The macro supports **max 16 struct members**. If you need more, feel free to open an issue, or implement the teaching code yourself :o)
> **_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.
+14 -2
View File
@@ -1,9 +1,21 @@
# Building examples
add_executable(obj-manager-server org.freedesktop.DBus.ObjectManager/obj-manager-server.cpp)
set(OBJECTMANAGER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.DBus.ObjectManager)
set(OBJECTMANAGER_GENERATED_DIR ${OBJECTMANAGER_SOURCE_DIR}/dbus-api/gen-cpp)
set(OBJECTMANAGER_SERVER_SRCS
${OBJECTMANAGER_SOURCE_DIR}/obj-manager-server.cpp
${OBJECTMANAGER_GENERATED_DIR}/examplemanager-planet1-server-glue.h)
add_executable(obj-manager-server ${OBJECTMANAGER_SERVER_SRCS})
target_include_directories(obj-manager-server SYSTEM PRIVATE ${OBJECTMANAGER_GENERATED_DIR})
target_link_libraries(obj-manager-server sdbus-c++)
add_executable(obj-manager-client org.freedesktop.DBus.ObjectManager/obj-manager-client.cpp)
set(OBJECTMANAGER_CLIENT_SRCS
${OBJECTMANAGER_SOURCE_DIR}/obj-manager-client.cpp
${OBJECTMANAGER_GENERATED_DIR}/examplemanager-planet1-client-glue.h)
add_executable(obj-manager-client ${OBJECTMANAGER_CLIENT_SRCS})
target_include_directories(obj-manager-client SYSTEM PRIVATE ${OBJECTMANAGER_GENERATED_DIR})
target_link_libraries(obj-manager-client sdbus-c++)
if(SDBUSCPP_INSTALL)
@@ -12,17 +12,26 @@
#include "examplemanager-planet1-client-glue.h"
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <thread>
#include <utility>
#include <map>
#include <string>
#include <vector>
#include <memory>
class PlanetProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::ExampleManager::Planet1_proxy >
{
public:
PlanetProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath path)
: ProxyInterfaces(connection, std::move(destination), std::move(path))
: ProxyInterfaces(connection, std::move(destination), std::move(path))
{
registerProxy();
}
PlanetProxy(const PlanetProxy&) = delete;
PlanetProxy& operator=(const PlanetProxy&) = delete;
PlanetProxy(PlanetProxy&&) = delete;
PlanetProxy& operator=(PlanetProxy&&) = delete;
~PlanetProxy()
{
unregisterProxy();
@@ -35,11 +44,16 @@ public:
ManagerProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath path)
: ProxyInterfaces(connection, destination, std::move(path))
, m_connection(connection)
, m_destination(destination)
, m_destination(std::move(destination))
{
registerProxy();
}
ManagerProxy(const ManagerProxy&) = delete;
ManagerProxy& operator=(const ManagerProxy&) = delete;
ManagerProxy(ManagerProxy&&) = delete;
ManagerProxy& operator=(ManagerProxy&&) = delete;
~ManagerProxy()
{
unregisterProxy();
@@ -61,7 +75,7 @@ private:
for (const auto& [interface, _] : interfacesAndProperties) {
std::cout << interface << " ";
}
std::cout << std::endl;
std::cout << '\n';
// Parse and print some more info
auto planetInterface = interfacesAndProperties.find(sdbus::InterfaceName{org::sdbuscpp::ExampleManager::Planet1_proxy::INTERFACE_NAME});
@@ -73,7 +87,7 @@ private:
const auto& name = properties.at(sdbus::PropertyName{"Name"}).get<std::string>();
// or create a proxy instance to the newly added object.
PlanetProxy planet(m_connection, m_destination, objectPath);
std::cout << name << " has a population of " << planet.GetPopulation() << ".\n" << std::endl;
std::cout << name << " has a population of " << planet.GetPopulation() << ".\n" << '\n';
}
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
@@ -83,7 +97,7 @@ private:
for (const auto& interface : interfaces) {
std::cout << interface << " ";
}
std::cout << std::endl;
std::cout << '\n';
}
sdbus::IConnection& m_connection;
@@ -102,7 +116,7 @@ int main()
}
catch (const sdbus::Error& e) {
if (e.getName() == "org.freedesktop.DBus.Error.ServiceUnknown") {
std::cout << "Waiting for server to start ..." << std::endl;
std::cout << "Waiting for server to start ..." << '\n';
}
}
@@ -18,8 +18,9 @@
#include <memory>
#include <thread>
#include <chrono>
using sdbus::ObjectPath;
#include <utility>
#include <string>
#include <cstdint>
class ManagerAdaptor : public sdbus::AdaptorInterfaces<sdbus::ObjectManager_adaptor>
{
@@ -30,6 +31,11 @@ public:
registerAdaptor();
}
ManagerAdaptor(const ManagerAdaptor&) = delete;
ManagerAdaptor& operator=(const ManagerAdaptor&) = delete;
ManagerAdaptor(ManagerAdaptor&&) = delete;
ManagerAdaptor& operator=(ManagerAdaptor&&) = delete;
~ManagerAdaptor()
{
unregisterAdaptor();
@@ -47,12 +53,17 @@ public:
, m_population(population)
{
registerAdaptor();
emitInterfacesAddedSignal({sdbus::InterfaceName{org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME}});
emitInterfacesAddedSignal({sdbus::InterfaceName{Planet1_adaptor::INTERFACE_NAME}});
}
PlanetAdaptor(const PlanetAdaptor&) = delete;
PlanetAdaptor& operator=(const PlanetAdaptor&) = delete;
PlanetAdaptor(PlanetAdaptor&&) = delete;
PlanetAdaptor& operator=(PlanetAdaptor&&) = delete;
~PlanetAdaptor()
{
emitInterfacesRemovedSignal({sdbus::InterfaceName{org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME}});
emitInterfacesRemovedSignal({sdbus::InterfaceName{Planet1_adaptor::INTERFACE_NAME}});
unregisterAdaptor();
}
@@ -78,25 +89,26 @@ void printCountDown(const std::string& message, int seconds)
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << i << " " << std::flush;
}
std::cout << std::endl;
std::cout << '\n';
}
int main()
{
auto connection = sdbus::createSessionBusConnection();
sdbus::ServiceName serviceName{"org.sdbuscpp.examplemanager"};
const sdbus::ServiceName serviceName{"org.sdbuscpp.examplemanager"};
connection->requestName(serviceName);
connection->enterEventLoopAsync();
auto manager = std::make_unique<ManagerAdaptor>(*connection, ObjectPath{"/org/sdbuscpp/examplemanager"});
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
auto manager = std::make_unique<ManagerAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager"});
while (true)
{
printCountDown("Creating PlanetAdaptor in ", 5);
auto earth = std::make_unique<PlanetAdaptor>(*connection, ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Earth"}, "Earth", 7'874'965'825);
auto earth = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Earth"}, "Earth", 7'874'965'825);
printCountDown("Creating PlanetAdaptor in ", 5);
auto trantor = std::make_unique<PlanetAdaptor>(*connection, ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Trantor"}, "Trantor", 40'000'000'000);
auto trantor = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Trantor"}, "Trantor", 40'000'000'000);
printCountDown("Creating PlanetAdaptor in ", 5);
auto laconia = std::make_unique<PlanetAdaptor>(*connection, ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Laconia"}, "Laconia", 231'721);
auto laconia = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Laconia"}, "Laconia", 231'721);
printCountDown("Removing PlanetAdaptor in ", 5);
earth.reset();
printCountDown("Removing PlanetAdaptor in ", 5);
+16 -15
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file AdaptorInterfaces.h
*
@@ -35,7 +35,7 @@
// Forward declarations
namespace sdbus {
class IConnection;
}
} // namespace sdbus
namespace sdbus {
@@ -50,18 +50,18 @@ namespace sdbus {
class ObjectHolder
{
protected:
ObjectHolder(std::unique_ptr<IObject>&& object)
explicit ObjectHolder(std::unique_ptr<IObject>&& object)
: object_(std::move(object))
{
}
const IObject& getObject() const
[[nodiscard]] const IObject& getObject() const
{
assert(object_ != nullptr);
return *object_;
}
IObject& getObject()
[[nodiscard]] IObject& getObject()
{
assert(object_ != nullptr);
return *object_;
@@ -88,12 +88,17 @@ namespace sdbus {
* so that the object API vtable is registered and unregistered at the proper time.
*
***********************************************/
template <typename... _Interfaces>
template <typename... Interfaces>
class AdaptorInterfaces
: protected ObjectHolder
, public _Interfaces...
, public Interfaces...
{
public:
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
AdaptorInterfaces(AdaptorInterfaces&&) = delete;
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = delete;
/*!
* @brief Creates object instance
*
@@ -104,7 +109,7 @@ namespace sdbus {
*/
AdaptorInterfaces(IConnection& connection, ObjectPath objectPath)
: ObjectHolder(createObject(connection, std::move(objectPath)))
, _Interfaces(getObject())...
, Interfaces(getObject())...
{
}
@@ -117,11 +122,11 @@ namespace sdbus {
*/
void registerAdaptor()
{
(_Interfaces::registerAdaptor(), ...);
(Interfaces::registerAdaptor(), ...);
}
/*!
* @brief Unregisters adaptors's API and removes it from the bus
* @brief Unregisters adaptor's API and removes it from the bus
*
* This function must be called in the destructor of the final adaptor class that implements AdaptorInterfaces.
*
@@ -140,13 +145,9 @@ namespace sdbus {
protected:
using base_type = AdaptorInterfaces;
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
AdaptorInterfaces(AdaptorInterfaces&&) = delete;
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = delete;
~AdaptorInterfaces() = default;
};
}
} // namespace sdbus
#endif /* SDBUS_CXX_ADAPTORINTERFACES_H_ */
+158
View File
@@ -0,0 +1,158 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2026 - Alex Cani <alexcani109@gmail.com>
*
* @file Awaitable.h
*
* Created on: Feb 28, 2026
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CXX_AWAITABLE_H_
#define SDBUS_CXX_AWAITABLE_H_
#include <atomic>
#include <cassert>
#if __has_include(<coroutine>)
#include <coroutine>
#endif
#include <cstdint>
#include <exception>
#include <memory>
#include <type_traits>
#include <variant>
namespace sdbus {
// Forward declarations
class AsyncMethodInvoker;
namespace internal {
class Proxy;
} // namespace internal
/********************************************//**
* @enum AwaitableState
*
* Represents the lifecycle state of an asynchronous
* operation in the coroutine awaitable protocol.
* Used for atomic coordination between the coroutine
* and the D-Bus callback thread.
*
***********************************************/
enum class AwaitableState : uint8_t
{
NotReady, // Initial state: callback hasn't fired yet
Waiting, // Coroutine is suspended and waiting for callback
Completed // Callback completed, result is ready
};
// Shared data
template <typename T>
struct AwaitableData
{
using result_type = std::conditional_t<std::is_void_v<T>, std::monostate, T>;
std::variant<result_type, std::exception_ptr> result;
std::atomic<AwaitableState> status{AwaitableState::NotReady};
#ifdef __cpp_lib_coroutine
// Keep the handle as the last member to mainting ABI compatibility
// with clients without coroutine support.
std::coroutine_handle<> handle;
#endif // __cpp_lib_coroutine
void resumeCoroutine()
{
#ifdef __cpp_lib_coroutine
handle.resume();
#endif // __cpp_lib_coroutine
}
};
/********************************************//**
* @class Awaitable
*
* A C++20 coroutine awaitable that represents an asynchronous
* operation. Allows suspending a coroutine until a D-Bus method
* call completes, then resuming with the result or exception.
*
* This is not a full-fledged coroutine type, but a simple awaitable
* that can be used with `co_await` to retrieve results of async D-Bus calls.
* This is independent of any specific coroutine framework or scheduler,
* as it relies on the D-Bus callback mechanism to resume the coroutine.
*
* You most likely don't need to use this class directly. Instead, use the
* respective low-level or high-level API functions that return an Awaitable
* instance, such as IProxy::callMethodAsync with with_awaitable_t tag,
* or the .getResultAsAwaitable() methods of the high-level API.
*
* The class represents nothing, i.e. is a simple placeholder class, if the API
* is used as C++17 or with a standard library not supporting coroutines.
*
***********************************************/
template <typename T>
class Awaitable
{
#ifdef __cpp_lib_coroutine
public:
// Called when the coroutine is co_await'ed. Returns true if the coroutine should be suspended.
[[nodiscard]] bool await_ready() const noexcept
{
return data_->status.load(std::memory_order_acquire) == AwaitableState::Completed;
}
// Called when the coroutine is suspended, returning false here will immediately
// resume the coroutine.
bool await_suspend(std::coroutine_handle<> handle) noexcept
{
data_->handle = handle;
// Attempt transition from NotReady to Waiting.
AwaitableState expected = AwaitableState::NotReady;
return data_->status.compare_exchange_strong(expected, AwaitableState::Waiting, std::memory_order_acq_rel);
}
// Called when the coroutine is resumed. Returns the result or throws the exception.
[[nodiscard]] T await_resume() const
{
if (auto* exception = std::get_if<std::exception_ptr>(&data_->result); exception != nullptr)
std::rethrow_exception(*exception);
if constexpr (std::is_void_v<T>)
return;
else
return std::get<T>(std::move(data_->result));
}
#endif // __cpp_lib_coroutine
private:
friend internal::Proxy;
friend AsyncMethodInvoker;
explicit Awaitable(std::shared_ptr<AwaitableData<T>> data)
: data_(std::move(data))
{
assert(data_ != nullptr);
}
std::shared_ptr<AwaitableData<T>> data_;
};
} // namespace sdbus
#endif // SDBUS_CXX_AWAITABLE_H_
+50 -50
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ConvenienceApiClasses.h
*
@@ -27,6 +27,7 @@
#ifndef SDBUS_CXX_CONVENIENCEAPICLASSES_H_
#define SDBUS_CXX_CONVENIENCEAPICLASSES_H_
#include <sdbus-c++/Awaitable.h>
#include <sdbus-c++/Message.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Types.h>
@@ -46,7 +47,7 @@ namespace sdbus {
class IProxy;
class Error;
class PendingAsyncCall;
}
} // namespace sdbus
namespace sdbus {
@@ -62,8 +63,7 @@ namespace sdbus {
friend IObject;
VTableAdder(IObject& object, std::vector<VTableItem> vtable);
private:
IObject& object_;
IObject& object_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::vector<VTableItem> vtable_;
};
@@ -73,9 +73,12 @@ namespace sdbus {
SignalEmitter& onInterface(const InterfaceName& interfaceName);
SignalEmitter& onInterface(const std::string& interfaceName);
SignalEmitter& onInterface(const char* interfaceName);
template <typename... _Args> void withArguments(_Args&&... args);
template <typename... Args> void withArguments(Args&&... args);
SignalEmitter(const SignalEmitter&) = delete;
SignalEmitter& operator=(const SignalEmitter&) = delete;
SignalEmitter(SignalEmitter&& other) = default;
SignalEmitter& operator=(SignalEmitter&&) = delete;
~SignalEmitter() noexcept(false);
private:
@@ -83,8 +86,7 @@ namespace sdbus {
SignalEmitter(IObject& object, const SignalName& signalName);
SignalEmitter(IObject& object, const char* signalName);
private:
IObject& object_;
IObject& object_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
const char* signalName_;
Signal signal_;
int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed
@@ -97,13 +99,16 @@ namespace sdbus {
MethodInvoker& onInterface(const std::string& interfaceName);
MethodInvoker& onInterface(const char* interfaceName);
MethodInvoker& withTimeout(uint64_t usec);
template <typename _Rep, typename _Period>
MethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
template <typename... _Args> MethodInvoker& withArguments(_Args&&... args);
template <typename... _Args> void storeResultsTo(_Args&... args);
template <typename Rep, typename Period>
MethodInvoker& withTimeout(const std::chrono::duration<Rep, Period>& timeout);
template <typename... Args> MethodInvoker& withArguments(Args&&... args);
template <typename... Args> void storeResultsTo(Args&... args);
void dontExpectReply();
MethodInvoker(const MethodInvoker&) = delete;
MethodInvoker& operator=(const MethodInvoker&) = delete;
MethodInvoker(MethodInvoker&& other) = default;
MethodInvoker& operator=(MethodInvoker&&) = delete;
~MethodInvoker() noexcept(false);
private:
@@ -111,8 +116,7 @@ namespace sdbus {
MethodInvoker(IProxy& proxy, const MethodName& methodName);
MethodInvoker(IProxy& proxy, const char* methodName);
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
const char* methodName_;
uint64_t timeout_{};
MethodCall method_;
@@ -127,24 +131,24 @@ namespace sdbus {
AsyncMethodInvoker& onInterface(const std::string& interfaceName);
AsyncMethodInvoker& onInterface(const char* interfaceName);
AsyncMethodInvoker& withTimeout(uint64_t usec);
template <typename _Rep, typename _Period>
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
template <typename _Function> [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t);
template <typename Rep, typename Period>
AsyncMethodInvoker& withTimeout(const std::chrono::duration<Rep, Period>& timeout);
template <typename... Args> AsyncMethodInvoker& withArguments(Args&&... args);
template <typename Function> PendingAsyncCall uponReplyInvoke(Function&& callback);
template <typename Function> [[nodiscard]] Slot uponReplyInvoke(Function&& callback, return_slot_t);
// Returned future will be std::future<void> for no (void) D-Bus method return value
// or std::future<T> for single D-Bus method return value
// or std::future<std::tuple<...>> for multiple method return values
template <typename... _Args> std::future<future_return_t<_Args...>> getResultAsFuture();
template <typename... Args> std::future<future_return_t<Args...>> getResultAsFuture();
template <typename... Args> Awaitable<awaitable_return_t<Args...>> getResultAsAwaitable();
private:
friend IProxy;
AsyncMethodInvoker(IProxy& proxy, const MethodName& methodName);
AsyncMethodInvoker(IProxy& proxy, const char* methodName);
template <typename _Function> async_reply_handler makeAsyncReplyHandler(_Function&& callback);
template <typename Function> async_reply_handler makeAsyncReplyHandler(Function&& callback);
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
const char* methodName_;
uint64_t timeout_{};
MethodCall method_;
@@ -156,17 +160,16 @@ namespace sdbus {
SignalSubscriber& onInterface(const InterfaceName& interfaceName);
SignalSubscriber& onInterface(const std::string& interfaceName);
SignalSubscriber& onInterface(const char* interfaceName);
template <typename _Function> void call(_Function&& callback);
template <typename _Function> [[nodiscard]] Slot call(_Function&& callback, return_slot_t);
template <typename Function> void call(Function&& callback);
template <typename Function> [[nodiscard]] Slot call(Function&& callback, return_slot_t);
private:
friend IProxy;
SignalSubscriber(IProxy& proxy, const SignalName& signalName);
SignalSubscriber(IProxy& proxy, const char* signalName);
template <typename _Function> signal_handler makeSignalHandler(_Function&& callback);
template <typename Function> signal_handler makeSignalHandler(Function&& callback);
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
const char* signalName_;
const char* interfaceName_{};
};
@@ -182,8 +185,7 @@ namespace sdbus {
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::string_view propertyName_;
};
@@ -191,9 +193,10 @@ namespace sdbus {
{
public:
AsyncPropertyGetter& onInterface(std::string_view interfaceName);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
template <typename _Function> [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t);
template <typename Function> PendingAsyncCall uponReplyInvoke(Function&& callback);
template <typename Function> [[nodiscard]] Slot uponReplyInvoke(Function&& callback, return_slot_t);
std::future<Variant> getResultAsFuture();
Awaitable<Variant> getResultAsAwaitable();
private:
friend IProxy;
@@ -201,8 +204,7 @@ namespace sdbus {
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::string_view propertyName_;
std::string_view interfaceName_;
};
@@ -211,8 +213,8 @@ namespace sdbus {
{
public:
PropertySetter& onInterface(std::string_view interfaceName);
template <typename _Value> void toValue(const _Value& value);
template <typename _Value> void toValue(const _Value& value, dont_expect_reply_t);
template <typename Value> void toValue(const Value& value);
template <typename Value> void toValue(const Value& value, dont_expect_reply_t);
void toValue(const Variant& value);
void toValue(const Variant& value, dont_expect_reply_t);
@@ -222,8 +224,7 @@ namespace sdbus {
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::string_view propertyName_;
std::string_view interfaceName_;
};
@@ -232,11 +233,12 @@ namespace sdbus {
{
public:
AsyncPropertySetter& onInterface(std::string_view interfaceName);
template <typename _Value> AsyncPropertySetter& toValue(_Value&& value);
template <typename Value> AsyncPropertySetter& toValue(Value&& value);
AsyncPropertySetter& toValue(Variant value);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
template <typename _Function> [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t);
template <typename Function> PendingAsyncCall uponReplyInvoke(Function&& callback);
template <typename Function> [[nodiscard]] Slot uponReplyInvoke(Function&& callback, return_slot_t);
std::future<void> getResultAsFuture();
Awaitable<void> getResultAsAwaitable();
private:
friend IProxy;
@@ -244,8 +246,7 @@ namespace sdbus {
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::string_view propertyName_;
std::string_view interfaceName_;
Variant value_;
@@ -258,30 +259,29 @@ namespace sdbus {
private:
friend IProxy;
AllPropertiesGetter(IProxy& proxy);
explicit AllPropertiesGetter(IProxy& proxy);
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
};
class AsyncAllPropertiesGetter
{
public:
AsyncAllPropertiesGetter& onInterface(std::string_view interfaceName);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
template <typename _Function> [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t);
template <typename Function> PendingAsyncCall uponReplyInvoke(Function&& callback);
template <typename Function> [[nodiscard]] Slot uponReplyInvoke(Function&& callback, return_slot_t);
std::future<std::map<PropertyName, Variant>> getResultAsFuture();
Awaitable<std::map<PropertyName, Variant>> getResultAsAwaitable();
private:
friend IProxy;
AsyncAllPropertiesGetter(IProxy& proxy);
explicit AsyncAllPropertiesGetter(IProxy& proxy);
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
private:
IProxy& proxy_;
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
std::string_view interfaceName_;
};
+136 -80
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ConvenienceApiClasses.inl
*
@@ -28,8 +28,8 @@
#define SDBUS_CPP_CONVENIENCEAPICLASSES_INL_
#include <sdbus-c++/Error.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/IObject.h> // NOLINT(misc-header-include-cycle)
#include <sdbus-c++/IProxy.h> // NOLINT(misc-header-include-cycle)
#include <sdbus-c++/Message.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/TypeTraits.h>
@@ -124,12 +124,12 @@ namespace sdbus {
return *this;
}
template <typename... _Args>
inline void SignalEmitter::withArguments(_Args&&... args)
template <typename... Args>
inline void SignalEmitter::withArguments(Args&&... args)
{
assert(signal_.isValid()); // onInterface() must be placed/called prior to withArguments()
detail::serialize_pack(signal_, std::forward<_Args>(args)...);
detail::serialize_pack(signal_, std::forward<Args>(args)...);
}
/*** ------------- ***/
@@ -191,25 +191,25 @@ namespace sdbus {
return *this;
}
template <typename _Rep, typename _Period>
inline MethodInvoker& MethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
template <typename Rep, typename Period>
inline MethodInvoker& MethodInvoker::withTimeout(const std::chrono::duration<Rep, Period>& timeout)
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return withTimeout(microsecs.count());
}
template <typename... _Args>
inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args)
template <typename... Args>
inline MethodInvoker& MethodInvoker::withArguments(Args&&... args)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
detail::serialize_pack(method_, std::forward<_Args>(args)...);
detail::serialize_pack(method_, std::forward<Args>(args)...);
return *this;
}
template <typename... _Args>
inline void MethodInvoker::storeResultsTo(_Args&... args)
template <typename... Args>
inline void MethodInvoker::storeResultsTo(Args&... args)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
@@ -265,50 +265,50 @@ namespace sdbus {
return *this;
}
template <typename _Rep, typename _Period>
inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
template <typename Rep, typename Period>
inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(const std::chrono::duration<Rep, Period>& timeout)
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return withTimeout(microsecs.count());
}
template <typename... _Args>
inline AsyncMethodInvoker& AsyncMethodInvoker::withArguments(_Args&&... args)
template <typename... Args>
inline AsyncMethodInvoker& AsyncMethodInvoker::withArguments(Args&&... args)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
detail::serialize_pack(method_, std::forward<_Args>(args)...);
detail::serialize_pack(method_, std::forward<Args>(args)...);
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncMethodInvoker::uponReplyInvoke(_Function&& callback)
template <typename Function>
PendingAsyncCall AsyncMethodInvoker::uponReplyInvoke(Function&& callback)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync(method_, makeAsyncReplyHandler(std::forward<_Function>(callback)), timeout_);
return proxy_.callMethodAsync(method_, makeAsyncReplyHandler(std::forward<Function>(callback)), timeout_);
}
template <typename _Function>
[[nodiscard]] Slot AsyncMethodInvoker::uponReplyInvoke(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot AsyncMethodInvoker::uponReplyInvoke(Function&& callback, return_slot_t)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync( method_
, makeAsyncReplyHandler(std::forward<_Function>(callback))
, makeAsyncReplyHandler(std::forward<Function>(callback))
, timeout_
, return_slot );
}
template <typename _Function>
inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(_Function&& callback)
template <typename Function>
inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(Function&& callback)
{
return [callback = std::forward<_Function>(callback)](MethodReply reply, std::optional<Error> error)
return [callback = std::forward<Function>(callback)](MethodReply reply, std::optional<Error> error)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the message.
tuple_of_function_input_arg_types_t<_Function> args;
tuple_of_function_input_arg_types_t<Function> args;
// Deserialize input arguments from the message into the tuple (if no error occurred).
if (!error)
@@ -317,11 +317,11 @@ namespace sdbus {
{
reply >> args;
}
catch (const Error& e)
catch (const Error& err)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, e, args);
sdbus::apply(callback, err, args);
return;
}
}
@@ -331,16 +331,16 @@ namespace sdbus {
};
}
template <typename... _Args>
std::future<future_return_t<_Args...>> AsyncMethodInvoker::getResultAsFuture()
template <typename... Args>
std::future<future_return_t<Args...>> AsyncMethodInvoker::getResultAsFuture()
{
auto promise = std::make_shared<std::promise<future_return_t<_Args...>>>();
auto promise = std::make_shared<std::promise<future_return_t<Args...>>>();
auto future = promise->get_future();
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, _Args... args)
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, Args... args)
{
if (!error)
if constexpr (!std::is_void_v<future_return_t<_Args...>>)
if constexpr (!std::is_void_v<future_return_t<Args...>>)
promise->set_value({std::move(args)...});
else
promise->set_value();
@@ -354,6 +354,32 @@ namespace sdbus {
return future;
}
template <typename... Args>
Awaitable<awaitable_return_t<Args...>> AsyncMethodInvoker::getResultAsAwaitable()
{
// awaitable_return_t<Args...> will be void for no D-Bus method return value
// or T for single D-Bus method return value
// or std::tuple<...> for multiple method return values
auto data = std::make_shared<AwaitableData<awaitable_return_t<Args...>>>();
uponReplyInvoke([data](std::optional<Error> error, Args... args)
{
if (!error)
if constexpr (!std::is_void_v<awaitable_return_t<Args...>>)
data->result = {std::move(args)...};
else
data->result = std::monostate{};
else
data->result = std::make_exception_ptr(*std::move(error));
auto previous = data->status.exchange(AwaitableState::Completed, std::memory_order_acq_rel);
if (previous == AwaitableState::Waiting)
data->resumeCoroutine();
});
return Awaitable(data);
}
/*** ---------------- ***/
/*** SignalSubscriber ***/
/*** ---------------- ***/
@@ -386,57 +412,57 @@ namespace sdbus {
return *this;
}
template <typename _Function>
inline void SignalSubscriber::call(_Function&& callback)
template <typename Function>
inline void SignalSubscriber::call(Function&& callback)
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
proxy_.registerSignalHandler( interfaceName_
, signalName_
, makeSignalHandler(std::forward<_Function>(callback)) );
, makeSignalHandler(std::forward<Function>(callback)) );
}
template <typename _Function>
[[nodiscard]] inline Slot SignalSubscriber::call(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] inline Slot SignalSubscriber::call(Function&& callback, return_slot_t)
{
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
return proxy_.registerSignalHandler( interfaceName_
, signalName_
, makeSignalHandler(std::forward<_Function>(callback))
, makeSignalHandler(std::forward<Function>(callback))
, return_slot );
}
template <typename _Function>
inline signal_handler SignalSubscriber::makeSignalHandler(_Function&& callback)
template <typename Function>
inline signal_handler SignalSubscriber::makeSignalHandler(Function&& callback)
{
return [callback = std::forward<_Function>(callback)](Signal signal)
return [callback = std::forward<Function>(callback)](Signal signal)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the signal message.
tuple_of_function_input_arg_types_t<_Function> signalArgs;
tuple_of_function_input_arg_types_t<Function> signalArgs;
// The signal handler can take pure signal parameters only, or an additional `std::optional<Error>` as its first
// parameter. In the former case, if the deserialization fails (e.g. due to signature mismatch),
// the failure is ignored (and signal simply dropped). In the latter case, the deserialization failure
// will be communicated to the client's signal handler as a valid Error object inside the std::optional parameter.
if constexpr (has_error_param_v<_Function>)
if constexpr (has_error_param_v<Function>)
{
// Deserialize input arguments from the signal message into the tuple
try
{
signal >> signalArgs;
}
catch (const sdbus::Error& e)
catch (const Error& err)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, e, signalArgs);
sdbus::apply(callback, err, signalArgs);
return;
}
// Invoke callback with no error and input arguments from the tuple.
sdbus::apply(callback, {}, signalArgs);
sdbus::apply(callback, std::nullopt, signalArgs);
}
else
{
@@ -486,10 +512,10 @@ namespace sdbus {
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncPropertyGetter::uponReplyInvoke(_Function&& callback)
template <typename Function>
PendingAsyncCall AsyncPropertyGetter::uponReplyInvoke(Function&& callback)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>, Variant>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>, Variant>
, "Property get callback function must accept std::optional<Error> and property value as Variant" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -497,13 +523,13 @@ namespace sdbus {
return proxy_.callMethodAsync("Get")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_)
.uponReplyInvoke(std::forward<_Function>(callback));
.uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot AsyncPropertyGetter::uponReplyInvoke(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot AsyncPropertyGetter::uponReplyInvoke(Function&& callback, return_slot_t)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>, Variant>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>, Variant>
, "Property get callback function must accept std::optional<Error> and property value as Variant" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -511,7 +537,7 @@ namespace sdbus {
return proxy_.callMethodAsync("Get")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_)
.uponReplyInvoke(std::forward<_Function>(callback), return_slot);
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
inline std::future<Variant> AsyncPropertyGetter::getResultAsFuture()
@@ -524,6 +550,16 @@ namespace sdbus {
.getResultAsFuture<Variant>();
}
inline Awaitable<Variant> AsyncPropertyGetter::getResultAsAwaitable()
{
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Get")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_)
.getResultAsAwaitable<Variant>();
}
/*** -------------- ***/
/*** PropertySetter ***/
/*** -------------- ***/
@@ -541,14 +577,14 @@ namespace sdbus {
return *this;
}
template <typename _Value>
inline void PropertySetter::toValue(const _Value& value)
template <typename Value>
inline void PropertySetter::toValue(const Value& value)
{
PropertySetter::toValue(Variant{value});
}
template <typename _Value>
inline void PropertySetter::toValue(const _Value& value, dont_expect_reply_t)
template <typename Value>
inline void PropertySetter::toValue(const Value& value, dont_expect_reply_t)
{
PropertySetter::toValue(Variant{value}, dont_expect_reply);
}
@@ -589,10 +625,10 @@ namespace sdbus {
return *this;
}
template <typename _Value>
inline AsyncPropertySetter& AsyncPropertySetter::toValue(_Value&& value)
template <typename Value>
inline AsyncPropertySetter& AsyncPropertySetter::toValue(Value&& value)
{
return AsyncPropertySetter::toValue(Variant{std::forward<_Value>(value)});
return AsyncPropertySetter::toValue(Variant{std::forward<Value>(value)});
}
inline AsyncPropertySetter& AsyncPropertySetter::toValue(Variant value)
@@ -602,10 +638,10 @@ namespace sdbus {
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncPropertySetter::uponReplyInvoke(_Function&& callback)
template <typename Function>
PendingAsyncCall AsyncPropertySetter::uponReplyInvoke(Function&& callback)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>>
, "Property set callback function must accept std::optional<Error> only" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -613,13 +649,13 @@ namespace sdbus {
return proxy_.callMethodAsync("Set")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_, std::move(value_))
.uponReplyInvoke(std::forward<_Function>(callback));
.uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot AsyncPropertySetter::uponReplyInvoke(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot AsyncPropertySetter::uponReplyInvoke(Function&& callback, return_slot_t)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>>
, "Property set callback function must accept std::optional<Error> only" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -627,7 +663,7 @@ namespace sdbus {
return proxy_.callMethodAsync("Set")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_, std::move(value_))
.uponReplyInvoke(std::forward<_Function>(callback), return_slot);
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
inline std::future<void> AsyncPropertySetter::getResultAsFuture()
@@ -640,6 +676,16 @@ namespace sdbus {
.getResultAsFuture<>();
}
inline Awaitable<void> AsyncPropertySetter::getResultAsAwaitable()
{
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("Set")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_, propertyName_, std::move(value_))
.getResultAsAwaitable<>();
}
/*** ------------------- ***/
/*** AllPropertiesGetter ***/
/*** ------------------- ***/
@@ -675,10 +721,10 @@ namespace sdbus {
return *this;
}
template <typename _Function>
PendingAsyncCall AsyncAllPropertiesGetter::uponReplyInvoke(_Function&& callback)
template <typename Function>
PendingAsyncCall AsyncAllPropertiesGetter::uponReplyInvoke(Function&& callback)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>, std::map<PropertyName, Variant>>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>, std::map<PropertyName, Variant>>
, "All properties get callback function must accept std::optional<Error> and a map of property names to their values" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -686,13 +732,13 @@ namespace sdbus {
return proxy_.callMethodAsync("GetAll")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_)
.uponReplyInvoke(std::forward<_Function>(callback));
.uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot AsyncAllPropertiesGetter::uponReplyInvoke(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot AsyncAllPropertiesGetter::uponReplyInvoke(Function&& callback, return_slot_t)
{
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>, std::map<PropertyName, Variant>>
static_assert( std::is_invocable_r_v<void, Function, std::optional<Error>, std::map<PropertyName, Variant>>
, "All properties get callback function must accept std::optional<Error> and a map of property names to their values" );
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
@@ -700,7 +746,7 @@ namespace sdbus {
return proxy_.callMethodAsync("GetAll")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_)
.uponReplyInvoke(std::forward<_Function>(callback), return_slot);
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
inline std::future<std::map<PropertyName, Variant>> AsyncAllPropertiesGetter::getResultAsFuture()
@@ -713,6 +759,16 @@ namespace sdbus {
.getResultAsFuture<std::map<PropertyName, Variant>>();
}
inline Awaitable<std::map<PropertyName, Variant>> AsyncAllPropertiesGetter::getResultAsAwaitable()
{
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
return proxy_.callMethodAsync("GetAll")
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
.withArguments(interfaceName_)
.getResultAsAwaitable<std::map<PropertyName, Variant>>();
}
} // namespace sdbus
#endif /* SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ */
+5 -4
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Error.h
*
@@ -27,7 +27,7 @@
#ifndef SDBUS_CXX_ERROR_H_
#define SDBUS_CXX_ERROR_H_
#include <errno.h>
#include <cerrno>
#include <stdexcept>
#include <string>
@@ -93,12 +93,13 @@ namespace sdbus {
Error createError(int errNo, std::string customMsg = {});
inline const Error::Name SDBUSCPP_ERROR_NAME{"org.sdbuscpp.Error"};
}
} // namespace sdbus
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
throw sdbus::createError((_ERRNO), (_MSG)) \
/**/
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
if (!(_COND)) ; else SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
/**/
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Flags.h
*
@@ -94,6 +94,6 @@ namespace sdbus {
std::bitset<FLAG_COUNT> flags_;
};
}
} // namespace sdbus
#endif /* SDBUS_CXX_FLAGS_H_ */
+23 -23
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file IConnection.h
*
@@ -43,7 +43,7 @@ namespace sdbus {
class ObjectPath;
class BusName;
using ServiceName = BusName;
}
} // namespace sdbus
namespace sdbus {
@@ -92,7 +92,7 @@ namespace sdbus {
virtual void leaveEventLoop() = 0;
/*!
* @brief Attaches the bus connection to an sd-event event loop
* @brief Attaches the bus connection to a sd-event event loop
*
* @param[in] event sd-event event loop object
* @param[in] priority Specified priority
@@ -104,7 +104,7 @@ namespace sdbus {
virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0;
/*!
* @brief Detaches the bus connection from an sd-event event loop
* @brief Detaches the bus connection from a sd-event event loop
*
* @throws sdbus::Error in case of failure
*/
@@ -144,7 +144,7 @@ namespace sdbus {
* in a form that can be passed to poll(2).
*
* The bus connection conveniently integrates sd-event event loop.
* To attach the bus connection to an sd-event event loop, use
* To attach the bus connection to a sd-event event loop, use
* attachSdEventLoop() function.
*
* @throws sdbus::Error in case of failure
@@ -168,7 +168,7 @@ namespace sdbus {
* You don't need to directly call this method or getEventLoopPollData() method
* when using convenient, internal bus connection event loops through
* enterEventLoop() or enterEventLoopAsync() calls, or when the bus is
* connected to an sd-event event loop through attachSdEventLoop().
* connected to a sd-event event loop through attachSdEventLoop().
* It is invoked automatically when necessary.
*
* @throws sdbus::Error in case of failure
@@ -207,8 +207,8 @@ namespace sdbus {
/*!
* @copydoc IConnection::setMethodCallTimeout(uint64_t)
*/
template <typename _Rep, typename _Period>
void setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
template <typename Rep, typename Period>
void setMethodCallTimeout(const std::chrono::duration<Rep, Period>& timeout);
/*!
* @brief Gets general method call timeout
@@ -426,8 +426,8 @@ namespace sdbus {
};
};
template <typename _Rep, typename _Period>
inline void IConnection::setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout)
template <typename Rep, typename Period>
inline void IConnection::setMethodCallTimeout(const std::chrono::duration<Rep, Period>& timeout)
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return setMethodCallTimeout(microsecs.count());
@@ -440,7 +440,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection();
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection();
/*!
* @brief Creates/opens D-Bus session bus connection with a name when in a user context, and a system bus connection with a name, otherwise.
@@ -450,7 +450,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection(const ServiceName& name);
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection(const ServiceName& name);
/*!
* @brief Creates/opens D-Bus system bus connection
@@ -459,7 +459,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection();
[[nodiscard]] std::unique_ptr<IConnection> createSystemBusConnection();
/*!
* @brief Creates/opens D-Bus system bus connection with a name
@@ -469,7 +469,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const ServiceName& name);
[[nodiscard]] std::unique_ptr<IConnection> createSystemBusConnection(const ServiceName& name);
/*!
* @brief Creates/opens D-Bus session bus connection
@@ -478,7 +478,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection();
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnection();
/*!
* @brief Creates/opens D-Bus session bus connection with a name
@@ -488,7 +488,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const ServiceName& name);
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnection(const ServiceName& name);
/*!
* @brief Creates/opens D-Bus session bus connection at a custom address
@@ -500,7 +500,7 @@ namespace sdbus {
*
* Consult manual pages for `sd_bus_set_address` of the underlying sd-bus library for more information.
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string& address);
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnectionWithAddress(const std::string& address);
/*!
* @brief Creates/opens D-Bus system connection on a remote host using ssh
@@ -510,7 +510,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host);
[[nodiscard]] std::unique_ptr<IConnection> createRemoteSystemBusConnection(const std::string& host);
/*!
* @brief Opens direct D-Bus connection at a custom address
@@ -520,7 +520,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address);
[[nodiscard]] std::unique_ptr<IConnection> createDirectBusConnection(const std::string& address);
/*!
* @brief Opens direct D-Bus connection at the given file descriptor
@@ -533,7 +533,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd);
[[nodiscard]] std::unique_ptr<IConnection> createDirectBusConnection(int fd);
/*!
* @brief Opens direct D-Bus connection at fd as a server
@@ -549,7 +549,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createServerBus(int fd);
[[nodiscard]] std::unique_ptr<IConnection> createServerBus(int fd);
/*!
* @brief Creates sdbus-c++ bus connection representation out of underlying sd_bus instance
@@ -578,7 +578,7 @@ namespace sdbus {
* auto con = sdbus::createBusConnection(bus); // IConnection consumes sd_bus object
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus);
}
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection(sd_bus *bus);
} // namespace sdbus
#endif /* SDBUS_CXX_ICONNECTION_H_ */
+12 -12
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file IObject.h
*
@@ -42,7 +42,7 @@ namespace sdbus {
class Signal;
class IConnection;
class ObjectPath;
}
} // namespace sdbus
namespace sdbus {
@@ -129,7 +129,7 @@ namespace sdbus {
* @throws sdbus::Error in case of failure
*/
template < typename... VTableItems
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> > // NOLINT(modernize-use-constraints): We are C++17 compatible at the moment
[[nodiscard]] VTableAdder addVTable(VTableItems&&... items);
/*!
@@ -309,7 +309,7 @@ namespace sdbus {
*/
virtual void unregister() = 0;
public: // Lower-level, message-based API
// Lower-level, message-based API
/*!
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
*
@@ -414,7 +414,7 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
virtual void emitSignal(const sdbus::Signal& message) = 0;
virtual void emitSignal(const Signal& message) = 0;
protected: // Internal API for efficiency reasons used by high-level API helper classes
friend SignalEmitter;
@@ -426,17 +426,17 @@ namespace sdbus {
inline SignalEmitter IObject::emitSignal(const SignalName& signalName)
{
return SignalEmitter(*this, signalName);
return {*this, signalName};
}
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
{
return SignalEmitter(*this, signalName.c_str());
return {*this, signalName.c_str()};
}
inline SignalEmitter IObject::emitSignal(const char* signalName)
{
return SignalEmitter(*this, signalName);
return {*this, signalName};
}
template <typename... VTableItems, typename>
@@ -453,7 +453,7 @@ namespace sdbus {
inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)
{
return VTableAdder(*this, std::move(vtable));
return {*this, std::move(vtable)};
}
/*!
@@ -474,11 +474,11 @@ namespace sdbus {
* auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, ObjectPath objectPath);
[[nodiscard]] std::unique_ptr<IObject> createObject(IConnection& connection, ObjectPath objectPath);
}
} // namespace sdbus
#include <sdbus-c++/ConvenienceApiClasses.inl>
#include <sdbus-c++/ConvenienceApiClasses.inl> // NOLINT(misc-header-include-cycle)
#include <sdbus-c++/VTableItems.inl>
#endif /* SDBUS_CXX_IOBJECT_H_ */
+115 -62
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file IProxy.h
*
@@ -29,6 +29,7 @@
#include <sdbus-c++/ConvenienceApiClasses.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Awaitable.h>
#include <chrono>
#include <functional>
@@ -46,8 +47,8 @@ namespace sdbus {
class PendingAsyncCall;
namespace internal {
class Proxy;
}
}
} // namespace internal
} // namespace sdbus
namespace sdbus {
@@ -350,7 +351,7 @@ namespace sdbus {
*/
virtual void unregister() = 0;
public: // Lower-level, message-based API
// Lower-level, message-based API
/*!
* @brief Creates a method call message
*
@@ -430,8 +431,8 @@ namespace sdbus {
/*!
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t)
*/
template <typename _Rep, typename _Period>
MethodReply callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout);
template <typename Rep, typename Period>
MethodReply callMethod(const MethodCall& message, const std::chrono::duration<Rep, Period>& timeout);
/*!
* @brief Calls method on the D-Bus object asynchronously
@@ -539,25 +540,24 @@ namespace sdbus {
/*!
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t)
*/
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
PendingAsyncCall callMethodAsync( const MethodCall& message
, async_reply_handler asyncReplyCallback
, const std::chrono::duration<_Rep, _Period>& timeout );
, const std::chrono::duration<Rep, Period>& timeout );
/*!
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t,return_slot_t)
*/
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
[[nodiscard]] Slot callMethodAsync( const MethodCall& message
, async_reply_handler asyncReplyCallback
, const std::chrono::duration<_Rep, _Period>& timeout
, const std::chrono::duration<Rep, Period>& timeout
, return_slot_t );
/*!
* @brief Calls method on the D-Bus object asynchronously
*
* @param[in] message Message representing an async method call
* @param[in] Tag denoting a std::future-based overload
* @return Future object providing access to the future method reply message
*
* This is a std::future-based way of asynchronously calling a remote D-Bus method.
@@ -579,7 +579,6 @@ namespace sdbus {
*
* @param[in] message Message representing an async method call
* @param[in] timeout Method call timeout
* @param[in] Tag denoting a std::future-based overload
* @return Future object providing access to the future method reply message
*
* This is a std::future-based way of asynchronously calling a remote D-Bus method.
@@ -601,11 +600,19 @@ namespace sdbus {
/*!
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t)
*/
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
std::future<MethodReply> callMethodAsync( const MethodCall& message
, const std::chrono::duration<_Rep, _Period>& timeout
, const std::chrono::duration<Rep, Period>& timeout
, with_future_t );
/*!
* @copydoc IProxy::callMethodAsync(const MethodCall&,uint64_t,with_awaitable_t)
*/
template <typename Rep, typename Period>
Awaitable<MethodReply> callMethodAsync( const MethodCall& message
, const std::chrono::duration<Rep, Period>& timeout
, with_awaitable_t );
/*!
* @brief Registers a handler for the desired signal emitted by the D-Bus object
*
@@ -660,6 +667,45 @@ namespace sdbus {
, const char* signalName
, signal_handler signalHandler
, return_slot_t ) = 0;
public: // New virtual functions in sdbus-c++ v2, for ABI compatibility
/*!
* @brief Calls method on the D-Bus object asynchronously
*
* @param[in] message Message representing a D-Bus method call
* @return An awaitable object that can be co_await'ed to retrieve the result
*
* This function call the remote D-Bus object asynchronously and return
* an awaitable that can be used with `co_await` to suspend a coroutine
* until the result is available.
*
* The call itself is non-blocking: the method call is performed and the method
* returns. The awaitable should be used to retrieve the result.
*
* The coroutine continuation (code after `co_await`) runs on the context of
* the bus connection I/O event loop thread.
*
* The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
*
* @throws sdbus::Error in case of failure (propagated when awaited)
*/
virtual Awaitable<MethodReply> callMethodAsync(const MethodCall& message, with_awaitable_t) = 0;
/*!
* @brief Calls method on the D-Bus object asynchronously, with custom timeout
*
* @param[in] message Message representing a D-Bus method call
* @param[in] timeout Timeout for the method call in microseconds
* @return An awaitable object that can be co_await'ed to retrieve the result
*
* This behaves the same as IProxy::callMethodAsync(const MethodCall&, with_awaitable_t),
* but with a custom timeout for the method call. If timeout is zero, the behavior is identical.
*
* @throws sdbus::Error in case of failure (propagated when awaited)
*/
virtual Awaitable<MethodReply> callMethodAsync( const MethodCall& message
, uint64_t timeout
, with_awaitable_t ) = 0;
};
/********************************************//**
@@ -698,132 +744,139 @@ namespace sdbus {
private:
friend internal::Proxy;
PendingAsyncCall(std::weak_ptr<void> callInfo);
explicit PendingAsyncCall(std::weak_ptr<void> callInfo);
private:
std::weak_ptr<void> callInfo_;
};
// Out-of-line member definitions
template <typename _Rep, typename _Period>
inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout)
template <typename Rep, typename Period>
inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<Rep, Period>& timeout)
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethod(message, microsecs.count());
}
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
inline PendingAsyncCall IProxy::callMethodAsync( const MethodCall& message
, async_reply_handler asyncReplyCallback
, const std::chrono::duration<_Rep, _Period>& timeout )
, const std::chrono::duration<Rep, Period>& timeout )
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethodAsync(message, std::move(asyncReplyCallback), microsecs.count());
}
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
inline Slot IProxy::callMethodAsync( const MethodCall& message
, async_reply_handler asyncReplyCallback
, const std::chrono::duration<_Rep, _Period>& timeout
, const std::chrono::duration<Rep, Period>& timeout
, return_slot_t )
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethodAsync(message, std::move(asyncReplyCallback), microsecs.count(), return_slot);
}
template <typename _Rep, typename _Period>
template <typename Rep, typename Period>
inline std::future<MethodReply> IProxy::callMethodAsync( const MethodCall& message
, const std::chrono::duration<_Rep, _Period>& timeout
, const std::chrono::duration<Rep, Period>& timeout
, with_future_t )
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethodAsync(message, microsecs.count(), with_future);
}
template <typename Rep, typename Period>
inline Awaitable<MethodReply> IProxy::callMethodAsync( const MethodCall& message
, const std::chrono::duration<Rep, Period>& timeout
, with_awaitable_t ) {
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
return callMethodAsync(message, microsecs.count(), with_awaitable);
}
inline MethodInvoker IProxy::callMethod(const MethodName& methodName)
{
return MethodInvoker(*this, methodName);
return {*this, methodName};
}
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
{
return MethodInvoker(*this, methodName.c_str());
return {*this, methodName.c_str()};
}
inline MethodInvoker IProxy::callMethod(const char* methodName)
{
return MethodInvoker(*this, methodName);
return {*this, methodName};
}
inline AsyncMethodInvoker IProxy::callMethodAsync(const MethodName& methodName)
{
return AsyncMethodInvoker(*this, methodName);
return {*this, methodName};
}
inline AsyncMethodInvoker IProxy::callMethodAsync(const std::string& methodName)
{
return AsyncMethodInvoker(*this, methodName.c_str());
return {*this, methodName.c_str()};
}
inline AsyncMethodInvoker IProxy::callMethodAsync(const char* methodName)
{
return AsyncMethodInvoker(*this, methodName);
return {*this, methodName};
}
inline SignalSubscriber IProxy::uponSignal(const SignalName& signalName)
{
return SignalSubscriber(*this, signalName);
return {*this, signalName};
}
inline SignalSubscriber IProxy::uponSignal(const std::string& signalName)
{
return SignalSubscriber(*this, signalName.c_str());
return {*this, signalName.c_str()};
}
inline SignalSubscriber IProxy::uponSignal(const char* signalName)
{
return SignalSubscriber(*this, signalName);
return {*this, signalName};
}
inline PropertyGetter IProxy::getProperty(const PropertyName& propertyName)
{
return PropertyGetter(*this, propertyName);
return {*this, propertyName};
}
inline PropertyGetter IProxy::getProperty(std::string_view propertyName)
{
return PropertyGetter(*this, std::move(propertyName));
return {*this, std::move(propertyName)};
}
inline AsyncPropertyGetter IProxy::getPropertyAsync(const PropertyName& propertyName)
{
return AsyncPropertyGetter(*this, propertyName);
return {*this, propertyName};
}
inline AsyncPropertyGetter IProxy::getPropertyAsync(std::string_view propertyName)
{
return AsyncPropertyGetter(*this, std::move(propertyName));
return {*this, std::move(propertyName)};
}
inline PropertySetter IProxy::setProperty(const PropertyName& propertyName)
{
return PropertySetter(*this, propertyName);
return {*this, propertyName};
}
inline PropertySetter IProxy::setProperty(std::string_view propertyName)
{
return PropertySetter(*this, std::move(propertyName));
return {*this, std::move(propertyName)};
}
inline AsyncPropertySetter IProxy::setPropertyAsync(const PropertyName& propertyName)
{
return AsyncPropertySetter(*this, propertyName);
return {*this, propertyName};
}
inline AsyncPropertySetter IProxy::setPropertyAsync(std::string_view propertyName)
{
return AsyncPropertySetter(*this, std::move(propertyName));
return {*this, std::move(propertyName)};
}
inline AllPropertiesGetter IProxy::getAllProperties()
@@ -858,9 +911,9 @@ namespace sdbus {
* auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( sdbus::IConnection& connection
, ServiceName destination
, ObjectPath objectPath );
[[nodiscard]] std::unique_ptr<IProxy> createProxy( IConnection& connection
, ServiceName destination
, ObjectPath objectPath );
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
@@ -884,9 +937,9 @@ namespace sdbus {
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath );
[[nodiscard]] std::unique_ptr<IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath );
/*!
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
@@ -911,19 +964,19 @@ namespace sdbus {
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread);
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t );
[[nodiscard]] std::unique_ptr<IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t );
/*!
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
*
* Does the same thing as createProxy(std::unique_ptr<sdbus::IConnection>&&, ServiceName, ObjectPath, dont_run_event_loop_thread_t);
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createLightWeightProxy( std::unique_ptr<sdbus::IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath );
[[nodiscard]] std::unique_ptr<IProxy> createLightWeightProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath );
/*!
* @brief Creates a proxy object for a specific remote D-Bus object
@@ -942,8 +995,8 @@ namespace sdbus {
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( ServiceName destination
, ObjectPath objectPath );
[[nodiscard]] std::unique_ptr<IProxy> createProxy( ServiceName destination
, ObjectPath objectPath );
/*!
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
@@ -963,19 +1016,19 @@ namespace sdbus {
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread );
* @endcode
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t );
[[nodiscard]] std::unique_ptr<IProxy> createProxy( ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t );
/*!
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
*
* Does the same thing as createProxy(ServiceName, ObjectPath, dont_run_event_loop_thread_t);
*/
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath);
[[nodiscard]] std::unique_ptr<IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath);
}
} // namespace sdbus
#include <sdbus-c++/ConvenienceApiClasses.inl>
#include <sdbus-c++/ConvenienceApiClasses.inl> // NOLINT(misc-header-include-cycle)
#endif /* SDBUS_CXX_IPROXY_H_ */
+204 -193
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Message.h
*
@@ -54,13 +54,13 @@ namespace sdbus {
class Variant;
class ObjectPath;
class Signature;
template <typename... _ValueTypes> class Struct;
template <typename... ValueTypes> class Struct;
class UnixFd;
class MethodReply;
namespace internal {
class IConnection;
}
}
} // namespace internal
} // namespace sdbus
namespace sdbus {
@@ -104,26 +104,27 @@ namespace sdbus {
Message& operator<<(const ObjectPath &item);
Message& operator<<(const Signature &item);
Message& operator<<(const UnixFd &item);
template <typename _Element, typename _Allocator>
Message& operator<<(const std::vector<_Element, _Allocator>& items);
template <typename _Element, std::size_t _Size>
Message& operator<<(const std::array<_Element, _Size>& items);
template <typename Element, typename Allocator>
Message& operator<<(const std::vector<Element, Allocator>& items);
template <typename Element, std::size_t Size>
Message& operator<<(const std::array<Element, Size>& items);
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
Message& operator<<(const std::span<_Element, _Extent>& items);
template <typename Element, std::size_t Extent>
Message& operator<<(const std::span<Element, Extent>& items);
#endif
template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
Message& operator<<(const _Enum& item);
template <typename _Key, typename _Value>
Message& operator<<(const DictEntry<_Key, _Value>& value);
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
Message& operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items);
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
Message& operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
template <typename... _ValueTypes>
Message& operator<<(const Struct<_ValueTypes...>& item);
template <typename... _ValueTypes>
Message& operator<<(const std::tuple<_ValueTypes...>& item);
// NOLINTNEXTLINE(modernize-use-constraints): Public API is C++17-compatible
template <typename Enum, typename = std::enable_if_t<std::is_enum_v<Enum>>>
Message& operator<<(const Enum& item);
template <typename Key, typename Value>
Message& operator<<(const DictEntry<Key, Value>& value);
template <typename Key, typename Value, typename Compare, typename Allocator>
Message& operator<<(const std::map<Key, Value, Compare, Allocator>& items);
template <typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator>
Message& operator<<(const std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& items);
template <typename... ValueTypes>
Message& operator<<(const Struct<ValueTypes...>& item);
template <typename... ValueTypes>
Message& operator<<(const std::tuple<ValueTypes...>& item);
Message& operator>>(bool& item);
Message& operator>>(int16_t& item);
@@ -142,57 +143,58 @@ namespace sdbus {
Message& operator>>(ObjectPath &item);
Message& operator>>(Signature &item);
Message& operator>>(UnixFd &item);
template <typename _Element, typename _Allocator>
Message& operator>>(std::vector<_Element, _Allocator>& items);
template <typename _Element, std::size_t _Size>
Message& operator>>(std::array<_Element, _Size>& items);
template <typename Element, typename Allocator>
Message& operator>>(std::vector<Element, Allocator>& items);
template <typename Element, std::size_t Size>
Message& operator>>(std::array<Element, Size>& items);
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
Message& operator>>(std::span<_Element, _Extent>& items);
template <typename Element, std::size_t Extent>
Message& operator>>(std::span<Element, Extent>& items);
#endif
template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
Message& operator>>(_Enum& item);
template <typename _Key, typename _Value>
Message& operator>>(DictEntry<_Key, _Value>& value);
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
Message& operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items);
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
Message& operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
template <typename... _ValueTypes>
Message& operator>>(Struct<_ValueTypes...>& item);
template <typename... _ValueTypes>
Message& operator>>(std::tuple<_ValueTypes...>& item);
// NOLINTNEXTLINE(modernize-use-constraints): Public API is C++17-compatible
template <typename Enum, typename = std::enable_if_t<std::is_enum_v<Enum>>>
Message& operator>>(Enum& item);
template <typename Key, typename Value>
Message& operator>>(DictEntry<Key, Value>& value);
template <typename Key, typename Value, typename Compare, typename Allocator>
Message& operator>>(std::map<Key, Value, Compare, Allocator>& items);
template <typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator>
Message& operator>>(std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& items);
template <typename... ValueTypes>
Message& operator>>(Struct<ValueTypes...>& item);
template <typename... ValueTypes>
Message& operator>>(std::tuple<ValueTypes...>& item);
template <typename _ElementType>
template <typename ElementType>
Message& openContainer();
Message& openContainer(const char* signature);
Message& closeContainer();
template <typename _KeyType, typename _ValueType>
template <typename KeyType, typename ValueType>
Message& openDictEntry();
Message& openDictEntry(const char* signature);
Message& closeDictEntry();
template <typename _ValueType>
template <typename ValueType>
Message& openVariant();
Message& openVariant(const char* signature);
Message& closeVariant();
template <typename... _ValueTypes>
template <typename... ValueTypes>
Message& openStruct();
Message& openStruct(const char* signature);
Message& closeStruct();
template <typename _ElementType>
template <typename ElementType>
Message& enterContainer();
Message& enterContainer(const char* signature);
Message& exitContainer();
template <typename _KeyType, typename _ValueType>
template <typename KeyType, typename ValueType>
Message& enterDictEntry();
Message& enterDictEntry(const char* signature);
Message& exitDictEntry();
template <typename _ValueType>
template <typename ValueType>
Message& enterVariant();
Message& enterVariant(const char* signature);
Message& exitVariant();
template <typename... _ValueTypes>
template <typename... ValueTypes>
Message& enterStruct();
Message& enterStruct(const char* signature);
Message& exitStruct();
@@ -200,12 +202,12 @@ namespace sdbus {
Message& appendArray(char type, const void *ptr, size_t size);
Message& readArray(char type, const void **ptr, size_t *size);
template <typename _Key, typename _Value, typename _Callback>
Message& serializeDictionary(const _Callback& callback);
template <typename _Key, typename _Value>
Message& serializeDictionary(const std::initializer_list<DictEntry<_Key, _Value>>& dictEntries);
template <typename _Key, typename _Value, typename _Callback>
Message& deserializeDictionary(const _Callback& callback);
template <typename Key, typename Value, typename Callback>
Message& serializeDictionary(const Callback& callback);
template <typename Key, typename Value>
Message& serializeDictionary(const std::initializer_list<DictEntry<Key, Value>>& dictEntries);
template <typename Key, typename Value, typename Callback>
Message& deserializeDictionary(const Callback& callback);
explicit operator bool() const;
void clearFlags();
@@ -226,6 +228,15 @@ namespace sdbus {
void seal();
void rewind(bool complete);
enum class DumpFlags : uint64_t // NOLINT(performance-enum-size): using size from sd-bus
{
Default = 0ULL,
WithHeader = 1ULL << 0,
SubtreeOnly = 1ULL << 1,
SubtreeOnlyWithHeader = WithHeader | SubtreeOnly
};
[[nodiscard]] std::string dumpToString(DumpFlags flags) const;
pid_t getCredsPid() const;
uid_t getCredsUid() const;
uid_t getCredsEuid() const;
@@ -237,18 +248,18 @@ namespace sdbus {
class Factory;
private:
template <typename _Array>
void serializeArray(const _Array& items);
template <typename _Array>
void deserializeArray(_Array& items);
template <typename _Array>
void deserializeArrayFast(_Array& items);
template <typename _Element, typename _Allocator>
void deserializeArrayFast(std::vector<_Element, _Allocator>& items);
template <typename _Array>
void deserializeArraySlow(_Array& items);
template <typename _Element, typename _Allocator>
void deserializeArraySlow(std::vector<_Element, _Allocator>& items);
template <typename Array>
void serializeArray(const Array& items);
template <typename Array>
void deserializeArray(Array& items);
template <typename Array>
void deserializeArrayFast(Array& items);
template <typename Element, typename Allocator>
void deserializeArrayFast(std::vector<Element, Allocator>& items);
template <typename Array>
void deserializeArraySlow(Array& items);
template <typename Element, typename Allocator>
void deserializeArraySlow(std::vector<Element, Allocator>& items);
protected:
Message() = default;
@@ -258,7 +269,6 @@ namespace sdbus {
friend Factory;
protected:
void* msg_{};
internal::IConnection* connection_{};
mutable bool ok_{true};
@@ -276,7 +286,7 @@ namespace sdbus {
[[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout, return_slot_t) const;
MethodReply createReply() const;
MethodReply createErrorReply(const sdbus::Error& error) const;
MethodReply createErrorReply(const Error& error) const;
void dontExpectReply();
bool doesntExpectReply() const;
@@ -355,16 +365,16 @@ namespace sdbus {
return *this;
}
template <typename _Element, typename _Allocator>
inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
template <typename Element, typename Allocator>
inline Message& Message::operator<<(const std::vector<Element, Allocator>& items)
{
serializeArray(items);
return *this;
}
template <typename _Element, std::size_t _Size>
inline Message& Message::operator<<(const std::array<_Element, _Size>& items)
template <typename Element, std::size_t Size>
inline Message& Message::operator<<(const std::array<Element, Size>& items)
{
serializeArray(items);
@@ -372,8 +382,8 @@ namespace sdbus {
}
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
template <typename Element, std::size_t Extent>
inline Message& Message::operator<<(const std::span<Element, Extent>& items)
{
serializeArray(items);
@@ -381,16 +391,16 @@ namespace sdbus {
}
#endif
template <typename _Enum, typename>
inline Message& Message::operator<<(const _Enum &item)
template <typename Enum, typename>
inline Message& Message::operator<<(const Enum &item)
{
return operator<<(static_cast<std::underlying_type_t<_Enum>>(item));
return operator<<(static_cast<std::underlying_type_t<Enum>>(item));
}
template <typename _Array>
inline void Message::serializeArray(const _Array& items)
template <typename Array>
inline void Message::serializeArray(const Array& items)
{
using ElementType = typename _Array::value_type;
using ElementType = typename Array::value_type;
// Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool,
// otherwise use step-by-step serialization of individual elements.
@@ -410,10 +420,10 @@ namespace sdbus {
}
}
template <typename _Key, typename _Value>
inline Message& Message::operator<<(const DictEntry<_Key, _Value>& value)
template <typename Key, typename Value>
inline Message& Message::operator<<(const DictEntry<Key, Value>& value)
{
openDictEntry<_Key, _Value>();
openDictEntry<Key, Value>();
*this << value.first;
*this << value.second;
closeDictEntry();
@@ -421,34 +431,34 @@ namespace sdbus {
return *this;
}
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
template <typename Key, typename Value, typename Compare, typename Allocator>
inline Message& Message::operator<<(const std::map<Key, Value, Compare, Allocator>& items)
{
serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
serializeDictionary<Key, Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
return *this;
}
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
template <typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator>
inline Message& Message::operator<<(const std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& items)
{
serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
serializeDictionary<Key, Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
return *this;
}
template <typename _Key, typename _Value>
inline Message& Message::serializeDictionary(const std::initializer_list<DictEntry<_Key, _Value>>& items)
template <typename Key, typename Value>
inline Message& Message::serializeDictionary(const std::initializer_list<DictEntry<Key, Value>>& dictEntries)
{
serializeDictionary<_Key, _Value>([&](Message& msg){ for (const auto& item : items) msg << item; });
serializeDictionary<Key, Value>([&](Message& msg){ for (const auto& entry : dictEntries) msg << entry; });
return *this;
}
template <typename _Key, typename _Value, typename _Callback>
inline Message& Message::serializeDictionary(const _Callback& callback)
template <typename Key, typename Value, typename Callback>
inline Message& Message::serializeDictionary(const Callback& callback)
{
openContainer<DictEntry<_Key, _Value>>();
openContainer<DictEntry<Key, Value>>();
callback(*this);
closeContainer();
@@ -457,75 +467,75 @@ namespace sdbus {
namespace detail
{
template <typename... _Args>
void serialize_pack(Message& msg, _Args&&... args)
template <typename... Args>
void serialize_pack(Message& msg, Args&&... args)
{
(void)(msg << ... << args);
(void)(msg << ... << std::forward<Args>(args));
}
template <class _Tuple, std::size_t... _Is>
template <class Tuple, std::size_t... Is>
void serialize_tuple( Message& msg
, const _Tuple& t
, std::index_sequence<_Is...>)
, const Tuple& tuple
, std::index_sequence<Is...>)
{
serialize_pack(msg, std::get<_Is>(t)...);
serialize_pack(msg, std::get<Is>(tuple)...);
}
}
} // namespace detail
template <typename... _ValueTypes>
inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
template <typename... ValueTypes>
inline Message& Message::operator<<(const Struct<ValueTypes...>& item)
{
openStruct<_ValueTypes...>();
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
openStruct<ValueTypes...>();
detail::serialize_tuple(*this, item, std::index_sequence_for<ValueTypes...>{});
closeStruct();
return *this;
}
template <typename... _ValueTypes>
inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item)
template <typename... ValueTypes>
inline Message& Message::operator<<(const std::tuple<ValueTypes...>& item)
{
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
detail::serialize_tuple(*this, item, std::index_sequence_for<ValueTypes...>{});
return *this;
}
namespace detail
{
template <typename _Element, typename... _Elements>
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const char* signature)
template <typename Element, typename... Elements>
bool deserialize_variant(Message& msg, std::variant<Elements...>& value, const char* signature)
{
constexpr auto elemSignature = as_null_terminated(sdbus::signature_of_v<_Element>);
constexpr auto elemSignature = as_null_terminated(signature_of_v<Element>);
if (std::strcmp(signature, elemSignature.data()) != 0)
return false;
_Element temp;
Element temp;
msg.enterVariant(signature);
msg >> temp;
msg.exitVariant();
value = std::move(temp);
return true;
}
}
} // namespace detail
template <typename... Elements>
inline Message& Message::operator>>(std::variant<Elements...>& value)
{
auto [type, contents] = peekType();
bool result = (detail::deserialize_variant<Elements>(*this, value, contents) || ...);
const bool result = (detail::deserialize_variant<Elements>(*this, value, contents) || ...);
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
return *this;
}
template <typename _Element, typename _Allocator>
inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
template <typename Element, typename Allocator>
inline Message& Message::operator>>(std::vector<Element, Allocator>& items)
{
deserializeArray(items);
return *this;
}
template <typename _Element, std::size_t _Size>
inline Message& Message::operator>>(std::array<_Element, _Size>& items)
template <typename Element, std::size_t Size>
inline Message& Message::operator>>(std::array<Element, Size>& items)
{
deserializeArray(items);
@@ -533,8 +543,8 @@ namespace sdbus {
}
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
template <typename Element, std::size_t Extent>
inline Message& Message::operator>>(std::span<Element, Extent>& items)
{
deserializeArray(items);
@@ -542,19 +552,19 @@ namespace sdbus {
}
#endif
template <typename _Enum, typename>
inline Message& Message::operator>>(_Enum& item)
template <typename Enum, typename>
inline Message& Message::operator>>(Enum& item)
{
std::underlying_type_t<_Enum> val;
std::underlying_type_t<Enum> val;
*this >> val;
item = static_cast<_Enum>(val);
item = static_cast<Enum>(val);
return *this;
}
template <typename _Array>
inline void Message::deserializeArray(_Array& items)
template <typename Array>
inline void Message::deserializeArray(Array& items)
{
using ElementType = typename _Array::value_type;
using ElementType = typename Array::value_type;
// Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool,
// otherwise use step-by-step deserialization of individual elements.
@@ -568,40 +578,41 @@ namespace sdbus {
}
}
template <typename _Array>
inline void Message::deserializeArrayFast(_Array& items)
template <typename Array>
inline void Message::deserializeArrayFast(Array& items)
{
using ElementType = typename _Array::value_type;
using ElementType = typename Array::value_type;
size_t arraySize{};
const ElementType* arrayPtr{};
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<ElementType>);
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
readArray(*signature.data(), reinterpret_cast<const void**>(&arrayPtr), &arraySize);
size_t elementsInMsg = arraySize / sizeof(ElementType);
bool notEnoughSpace = items.size() < elementsInMsg;
const size_t elementsInMsg = arraySize / sizeof(ElementType);
const bool notEnoughSpace = items.size() < elementsInMsg;
SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL);
std::copy_n(arrayPtr, elementsInMsg, items.begin());
}
template <typename _Element, typename _Allocator>
void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items)
template <typename Element, typename Allocator>
void Message::deserializeArrayFast(std::vector<Element, Allocator>& items)
{
size_t arraySize{};
const _Element* arrayPtr{};
const Element* arrayPtr{};
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>);
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
constexpr auto signature = as_null_terminated(signature_of_v<Element>);
readArray(*signature.data(), reinterpret_cast<const void**>(&arrayPtr), &arraySize);
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(Element)));
}
template <typename _Array>
inline void Message::deserializeArraySlow(_Array& items)
template <typename Array>
inline void Message::deserializeArraySlow(Array& items)
{
using ElementType = typename _Array::value_type;
using ElementType = typename Array::value_type;
if(!enterContainer<ElementType>())
return;
@@ -617,15 +628,15 @@ namespace sdbus {
exitContainer();
}
template <typename _Element, typename _Allocator>
void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
template <typename Element, typename Allocator>
void Message::deserializeArraySlow(std::vector<Element, Allocator>& items)
{
if(!enterContainer<_Element>())
if(!enterContainer<Element>())
return;
while (true)
{
_Element elem;
Element elem;
if (*this >> elem)
items.emplace_back(std::move(elem));
else
@@ -637,10 +648,10 @@ namespace sdbus {
exitContainer();
}
template <typename _Key, typename _Value>
inline Message& Message::operator>>(DictEntry<_Key, _Value>& value)
template <typename Key, typename Value>
inline Message& Message::operator>>(DictEntry<Key, Value>& value)
{
if (!enterDictEntry<_Key, _Value>())
if (!enterDictEntry<Key, Value>())
return *this;
*this >> value.first >> value.second;
exitDictEntry();
@@ -648,31 +659,31 @@ namespace sdbus {
return *this;
}
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
template <typename Key, typename Value, typename Compare, typename Allocator>
inline Message& Message::operator>>(std::map<Key, Value, Compare, Allocator>& items)
{
deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
deserializeDictionary<Key, Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
return *this;
}
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
template <typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator>
inline Message& Message::operator>>(std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& items)
{
deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
deserializeDictionary<Key, Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
return *this;
}
template <typename _Key, typename _Value, typename _Callback>
inline Message& Message::deserializeDictionary(const _Callback& callback)
template <typename Key, typename Value, typename Callback>
inline Message& Message::deserializeDictionary(const Callback& callback)
{
if (!enterContainer<DictEntry<_Key, _Value>>())
if (!enterContainer<DictEntry<Key, Value>>())
return *this;
while (true)
{
DictEntry<_Key, _Value> dictEntry;
DictEntry<Key, Value> dictEntry;
*this >> dictEntry;
if (!*this)
break;
@@ -687,97 +698,97 @@ namespace sdbus {
namespace detail
{
template <typename... _Args>
void deserialize_pack(Message& msg, _Args&... args)
template <typename... Args>
void deserialize_pack(Message& msg, Args&... args)
{
(void)(msg >> ... >> args);
}
template <class _Tuple, std::size_t... _Is>
template <class Tuple, std::size_t... Is>
void deserialize_tuple( Message& msg
, _Tuple& t
, std::index_sequence<_Is...> )
, Tuple& tuple
, std::index_sequence<Is...> )
{
deserialize_pack(msg, std::get<_Is>(t)...);
deserialize_pack(msg, std::get<Is>(tuple)...);
}
}
} // namespace detail
template <typename... _ValueTypes>
inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
template <typename... ValueTypes>
inline Message& Message::operator>>(Struct<ValueTypes...>& item)
{
if (!enterStruct<_ValueTypes...>())
if (!enterStruct<ValueTypes...>())
return *this;
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
detail::deserialize_tuple(*this, item, std::index_sequence_for<ValueTypes...>{});
exitStruct();
return *this;
}
template <typename... _ValueTypes>
inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item)
template <typename... ValueTypes>
inline Message& Message::operator>>(std::tuple<ValueTypes...>& item)
{
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
detail::deserialize_tuple(*this, item, std::index_sequence_for<ValueTypes...>{});
return *this;
}
template <typename _ElementType>
template <typename ElementType>
inline Message& Message::openContainer()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
return openContainer(signature.data());
}
template <typename _KeyType, typename _ValueType>
template <typename KeyType, typename ValueType>
inline Message& Message::openDictEntry()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<KeyType, ValueType>>);
return openDictEntry(signature.data());
}
template <typename _ValueType>
template <typename ValueType>
inline Message& Message::openVariant()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
constexpr auto signature = as_null_terminated(signature_of_v<ValueType>);
return openVariant(signature.data());
}
template <typename... _ValueTypes>
template <typename... ValueTypes>
inline Message& Message::openStruct()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<ValueTypes...>>);
return openStruct(signature.data());
}
template <typename _ElementType>
template <typename ElementType>
inline Message& Message::enterContainer()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
return enterContainer(signature.data());
}
template <typename _KeyType, typename _ValueType>
template <typename KeyType, typename ValueType>
inline Message& Message::enterDictEntry()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<KeyType, ValueType>>);
return enterDictEntry(signature.data());
}
template <typename _ValueType>
template <typename ValueType>
inline Message& Message::enterVariant()
{
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
constexpr auto signature = as_null_terminated(signature_of_v<ValueType>);
return enterVariant(signature.data());
}
template <typename... _ValueTypes>
template <typename... ValueTypes>
inline Message& Message::enterStruct()
{
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<ValueTypes...>>);
return enterStruct(signature.data());
}
}
} // namespace sdbus
#endif /* SDBUS_CXX_MESSAGE_H_ */
+14 -12
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file MethodResult.h
*
@@ -34,7 +34,7 @@
// Forward declarations
namespace sdbus {
class Error;
}
} // namespace sdbus
namespace sdbus {
@@ -46,12 +46,12 @@ namespace sdbus {
* by the method to either method return value or an error.
*
***********************************************/
template <typename... _Results>
template <typename... Results>
class Result
{
public:
Result() = default;
Result(MethodCall call);
explicit Result(MethodCall call);
Result(const Result&) = delete;
Result& operator=(const Result&) = delete;
@@ -59,21 +59,23 @@ namespace sdbus {
Result(Result&& other) = default;
Result& operator=(Result&& other) = default;
void returnResults(const _Results&... results) const;
~Result() = default;
void returnResults(const Results&... results) const;
void returnError(const Error& error) const;
private:
MethodCall call_;
};
template <typename... _Results>
inline Result<_Results...>::Result(MethodCall call)
template <typename... Results>
inline Result<Results...>::Result(MethodCall call)
: call_(std::move(call))
{
}
template <typename... _Results>
inline void Result<_Results...>::returnResults(const _Results&... results) const
template <typename... Results>
inline void Result<Results...>::returnResults(const Results&... results) const
{
assert(call_.isValid());
auto reply = call_.createReply();
@@ -81,13 +83,13 @@ namespace sdbus {
reply.send();
}
template <typename... _Results>
inline void Result<_Results...>::returnError(const Error& error) const
template <typename... Results>
inline void Result<Results...>::returnError(const Error& error) const
{
auto reply = call_.createErrorReply(error);
reply.send();
}
}
} // namespace sdbus
#endif /* SDBUS_CXX_METHODRESULT_H_ */
+23 -23
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ProxyInterfaces.h
*
@@ -29,13 +29,12 @@
#include <sdbus-c++/IProxy.h>
#include <cassert>
#include <string>
#include <memory>
// Forward declarations
namespace sdbus {
class IConnection;
}
} // namespace sdbus
namespace sdbus {
@@ -51,19 +50,19 @@ namespace sdbus {
class ProxyObjectHolder
{
protected:
ProxyObjectHolder(std::unique_ptr<IProxy>&& proxy)
explicit ProxyObjectHolder(std::unique_ptr<IProxy>&& proxy)
: proxy_(std::move(proxy))
{
assert(proxy_ != nullptr);
}
const IProxy& getProxy() const
[[nodiscard]] const IProxy& getProxy() const
{
assert(proxy_ != nullptr);
return *proxy_;
}
IProxy& getProxy()
[[nodiscard]] IProxy& getProxy()
{
assert(proxy_ != nullptr);
return *proxy_;
@@ -89,12 +88,17 @@ namespace sdbus {
* so that the signals are subscribed to and unsubscribed from at a proper time.
*
***********************************************/
template <typename... _Interfaces>
template <typename... Interfaces>
class ProxyInterfaces
: protected ProxyObjectHolder
, public _Interfaces...
, public Interfaces...
{
public:
ProxyInterfaces(const ProxyInterfaces&) = delete;
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
ProxyInterfaces(ProxyInterfaces&&) = delete;
ProxyInterfaces& operator=(ProxyInterfaces&&) = delete;
/*!
* @brief Creates native-like proxy object instance
*
@@ -106,7 +110,7 @@ namespace sdbus {
*/
ProxyInterfaces(ServiceName destination, ObjectPath objectPath)
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath)))
, _Interfaces(getProxy())...
, Interfaces(getProxy())...
{
}
@@ -121,7 +125,7 @@ namespace sdbus {
*/
ProxyInterfaces(ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t)
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
, _Interfaces(getProxy())...
, Interfaces(getProxy())...
{
}
@@ -137,7 +141,7 @@ namespace sdbus {
*/
ProxyInterfaces(IConnection& connection, ServiceName destination, ObjectPath objectPath)
: ProxyObjectHolder(createProxy(connection, std::move(destination), std::move(objectPath)))
, _Interfaces(getProxy())...
, Interfaces(getProxy())...
{
}
@@ -151,9 +155,9 @@ namespace sdbus {
* The proxy created this way becomes an owner of the connection.
* For more information on its behavior, consult @ref createProxy(std::unique_ptr<sdbus::IConnection>&&,std::string,std::string)
*/
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, ServiceName destination, ObjectPath objectPath)
ProxyInterfaces(std::unique_ptr<IConnection>&& connection, ServiceName destination, ObjectPath objectPath)
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath)))
, _Interfaces(getProxy())...
, Interfaces(getProxy())...
{
}
@@ -167,9 +171,9 @@ namespace sdbus {
* The proxy created this way becomes an owner of the connection.
* For more information on its behavior, consult @ref createProxy(std::unique_ptr<sdbus::IConnection>&&,std::string,std::string,sdbus::dont_run_event_loop_thread_t)
*/
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t)
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
, _Interfaces(getProxy())...
ProxyInterfaces(std::unique_ptr<IConnection>&& connection, ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t)
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
, Interfaces(getProxy())...
{
}
@@ -182,7 +186,7 @@ namespace sdbus {
*/
void registerProxy()
{
(_Interfaces::registerProxy(), ...);
(Interfaces::registerProxy(), ...);
}
/*!
@@ -205,13 +209,9 @@ namespace sdbus {
protected:
using base_type = ProxyInterfaces;
ProxyInterfaces(const ProxyInterfaces&) = delete;
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
ProxyInterfaces(ProxyInterfaces&&) = delete;
ProxyInterfaces& operator=(ProxyInterfaces&&) = delete;
~ProxyInterfaces() = default;
};
}
} // namespace sdbus
#endif /* SDBUS_CXX_INTERFACES_H_ */
#endif /* SDBUS_CXX_PROXYINTERFACES_H_ */
+162 -126
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file StandardInterfaces.h
*
@@ -43,16 +43,11 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Peer";
protected:
Peer_proxy(sdbus::IProxy& proxy)
explicit Peer_proxy(IProxy& proxy)
: m_proxy(proxy)
{
}
Peer_proxy(const Peer_proxy&) = delete;
Peer_proxy& operator=(const Peer_proxy&) = delete;
Peer_proxy(Peer_proxy&&) = delete;
Peer_proxy& operator=(Peer_proxy&&) = delete;
~Peer_proxy() = default;
void registerProxy()
@@ -60,6 +55,11 @@ namespace sdbus {
}
public:
Peer_proxy(const Peer_proxy&) = delete;
Peer_proxy& operator=(const Peer_proxy&) = delete;
Peer_proxy(Peer_proxy&&) = delete;
Peer_proxy& operator=(Peer_proxy&&) = delete;
void Ping()
{
m_proxy.callMethod("Ping").onInterface(INTERFACE_NAME);
@@ -73,7 +73,7 @@ namespace sdbus {
}
private:
sdbus::IProxy& m_proxy;
IProxy& m_proxy;
};
// Proxy for introspection
@@ -82,16 +82,11 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
protected:
Introspectable_proxy(sdbus::IProxy& proxy)
explicit Introspectable_proxy(IProxy& proxy)
: m_proxy(proxy)
{
}
Introspectable_proxy(const Introspectable_proxy&) = delete;
Introspectable_proxy& operator=(const Introspectable_proxy&) = delete;
Introspectable_proxy(Introspectable_proxy&&) = delete;
Introspectable_proxy& operator=(Introspectable_proxy&&) = delete;
~Introspectable_proxy() = default;
void registerProxy()
@@ -99,6 +94,11 @@ namespace sdbus {
}
public:
Introspectable_proxy(const Introspectable_proxy&) = delete;
Introspectable_proxy& operator=(const Introspectable_proxy&) = delete;
Introspectable_proxy(Introspectable_proxy&&) = delete;
Introspectable_proxy& operator=(Introspectable_proxy&&) = delete;
std::string Introspect()
{
std::string xml;
@@ -107,7 +107,7 @@ namespace sdbus {
}
private:
sdbus::IProxy& m_proxy;
IProxy& m_proxy;
};
// Proxy for properties
@@ -116,16 +116,11 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
protected:
Properties_proxy(sdbus::IProxy& proxy)
explicit Properties_proxy(IProxy& proxy)
: m_proxy(proxy)
{
}
Properties_proxy(const Properties_proxy&) = delete;
Properties_proxy& operator=(const Properties_proxy&) = delete;
Properties_proxy(Properties_proxy&&) = delete;
Properties_proxy& operator=(Properties_proxy&&) = delete;
~Properties_proxy() = default;
void registerProxy()
@@ -134,7 +129,7 @@ namespace sdbus {
.uponSignal("PropertiesChanged")
.onInterface(INTERFACE_NAME)
.call([this]( const InterfaceName& interfaceName
, const std::map<PropertyName, sdbus::Variant>& changedProperties
, const std::map<PropertyName, Variant>& changedProperties
, const std::vector<PropertyName>& invalidatedProperties )
{
this->onPropertiesChanged(interfaceName, changedProperties, invalidatedProperties);
@@ -142,154 +137,189 @@ namespace sdbus {
}
virtual void onPropertiesChanged( const InterfaceName& interfaceName
, const std::map<PropertyName, sdbus::Variant>& changedProperties
, const std::map<PropertyName, Variant>& changedProperties
, const std::vector<PropertyName>& invalidatedProperties ) = 0;
public:
sdbus::Variant Get(const InterfaceName& interfaceName, const PropertyName& propertyName)
Properties_proxy(const Properties_proxy&) = delete;
Properties_proxy& operator=(const Properties_proxy&) = delete;
Properties_proxy(Properties_proxy&&) = delete;
Properties_proxy& operator=(Properties_proxy&&) = delete;
Variant Get(const InterfaceName& interfaceName, const PropertyName& propertyName)
{
return m_proxy.getProperty(propertyName).onInterface(interfaceName);
}
sdbus::Variant Get(std::string_view interfaceName, std::string_view propertyName)
Variant Get(std::string_view interfaceName, std::string_view propertyName)
{
return m_proxy.getProperty(propertyName).onInterface(interfaceName);
}
template <typename _Function>
PendingAsyncCall GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, _Function&& callback)
template <typename Function>
PendingAsyncCall GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, Function&& callback)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, _Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, Function&& callback, return_slot_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<sdbus::Variant> GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_future_t)
std::future<Variant> GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_future_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
}
template <typename _Function>
PendingAsyncCall GetAsync(std::string_view interfaceName, std::string_view propertyName, _Function&& callback)
Awaitable<Variant> GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_awaitable_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsAwaitable();
}
template <typename _Function>
[[nodiscard]] Slot GetAsync(std::string_view interfaceName, std::string_view propertyName, _Function&& callback, return_slot_t)
template <typename Function>
PendingAsyncCall GetAsync(std::string_view interfaceName, std::string_view propertyName, Function&& callback)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
}
std::future<sdbus::Variant> GetAsync(std::string_view interfaceName, std::string_view propertyName, with_future_t)
template <typename Function>
[[nodiscard]] Slot GetAsync(std::string_view interfaceName, std::string_view propertyName, Function&& callback, return_slot_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<Variant> GetAsync(std::string_view interfaceName, std::string_view propertyName, with_future_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
}
void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value)
Awaitable<Variant> GetAsync(std::string_view interfaceName, std::string_view propertyName, with_awaitable_t)
{
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsAwaitable();
}
void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value)
{
m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value);
}
void Set(std::string_view interfaceName, const std::string_view propertyName, const sdbus::Variant& value)
void Set(std::string_view interfaceName, const std::string_view propertyName, const Variant& value)
{
m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value);
}
void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, dont_expect_reply_t)
void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, dont_expect_reply_t)
{
m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply);
}
void Set(std::string_view interfaceName, const std::string_view propertyName, const sdbus::Variant& value, dont_expect_reply_t)
void Set(std::string_view interfaceName, const std::string_view propertyName, const Variant& value, dont_expect_reply_t)
{
m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply);
}
template <typename _Function>
PendingAsyncCall SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, _Function&& callback)
template <typename Function>
PendingAsyncCall SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, Function&& callback)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, _Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, Function&& callback, return_slot_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<void> SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, with_future_t)
std::future<void> SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, with_future_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture();
}
template <typename _Function>
PendingAsyncCall SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, _Function&& callback)
Awaitable<void> SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, with_awaitable_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsAwaitable();
}
template <typename _Function>
[[nodiscard]] Slot SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, _Function&& callback, return_slot_t)
template <typename Function>
PendingAsyncCall SetAsync(std::string_view interfaceName, std::string_view propertyName, const Variant& value, Function&& callback)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<Function>(callback));
}
std::future<void> SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, with_future_t)
template <typename Function>
[[nodiscard]] Slot SetAsync(std::string_view interfaceName, std::string_view propertyName, const Variant& value, Function&& callback, return_slot_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<void> SetAsync(std::string_view interfaceName, std::string_view propertyName, const Variant& value, with_future_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture();
}
std::map<PropertyName, sdbus::Variant> GetAll(const InterfaceName& interfaceName)
Awaitable<void> SetAsync(std::string_view interfaceName, std::string_view propertyName, const Variant& value, with_awaitable_t)
{
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsAwaitable();
}
std::map<PropertyName, Variant> GetAll(const InterfaceName& interfaceName)
{
return m_proxy.getAllProperties().onInterface(interfaceName);
}
std::map<PropertyName, sdbus::Variant> GetAll(std::string_view interfaceName)
std::map<PropertyName, Variant> GetAll(std::string_view interfaceName)
{
return m_proxy.getAllProperties().onInterface(interfaceName);
}
template <typename _Function>
PendingAsyncCall GetAllAsync(const InterfaceName& interfaceName, _Function&& callback)
template <typename Function>
PendingAsyncCall GetAllAsync(const InterfaceName& interfaceName, Function&& callback)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot GetAllAsync(const InterfaceName& interfaceName, _Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot GetAllAsync(const InterfaceName& interfaceName, Function&& callback, return_slot_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<std::map<PropertyName, sdbus::Variant>> GetAllAsync(const InterfaceName& interfaceName, with_future_t)
std::future<std::map<PropertyName, Variant>> GetAllAsync(const InterfaceName& interfaceName, with_future_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture();
}
template <typename _Function>
PendingAsyncCall GetAllAsync(std::string_view interfaceName, _Function&& callback)
Awaitable<std::map<PropertyName, Variant>> GetAllAsync(const InterfaceName& interfaceName, with_awaitable_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsAwaitable();
}
template <typename _Function>
[[nodiscard]] Slot GetAllAsync(std::string_view interfaceName, _Function&& callback, return_slot_t)
template <typename Function>
PendingAsyncCall GetAllAsync(std::string_view interfaceName, Function&& callback)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
}
std::future<std::map<PropertyName, sdbus::Variant>> GetAllAsync(std::string_view interfaceName, with_future_t)
template <typename Function>
[[nodiscard]] Slot GetAllAsync(std::string_view interfaceName, Function&& callback, return_slot_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<std::map<PropertyName, Variant>> GetAllAsync(std::string_view interfaceName, with_future_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture();
}
Awaitable<std::map<PropertyName, Variant>> GetAllAsync(std::string_view interfaceName, with_awaitable_t)
{
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsAwaitable();
}
private:
sdbus::IProxy& m_proxy;
IProxy& m_proxy;
};
// Proxy for object manager
@@ -298,16 +328,11 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
protected:
ObjectManager_proxy(sdbus::IProxy& proxy)
explicit ObjectManager_proxy(IProxy& proxy)
: m_proxy(proxy)
{
}
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
ObjectManager_proxy(ObjectManager_proxy&&) = delete;
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = delete;
~ObjectManager_proxy() = default;
void registerProxy()
@@ -315,8 +340,8 @@ namespace sdbus {
m_proxy
.uponSignal("InterfacesAdded")
.onInterface(INTERFACE_NAME)
.call([this]( const sdbus::ObjectPath& objectPath
, const std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>& interfacesAndProperties )
.call([this]( const ObjectPath& objectPath
, const std::map<InterfaceName, std::map<PropertyName, Variant>>& interfacesAndProperties )
{
this->onInterfacesAdded(objectPath, interfacesAndProperties);
});
@@ -324,45 +349,55 @@ namespace sdbus {
m_proxy
.uponSignal("InterfacesRemoved")
.onInterface(INTERFACE_NAME)
.call([this]( const sdbus::ObjectPath& objectPath
, const std::vector<sdbus::InterfaceName>& interfaces )
.call([this]( const ObjectPath& objectPath
, const std::vector<InterfaceName>& interfaces )
{
this->onInterfacesRemoved(objectPath, interfaces);
});
}
virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath
, const std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>& interfacesAndProperties) = 0;
virtual void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
, const std::vector<sdbus::InterfaceName>& interfaces) = 0;
virtual void onInterfacesAdded( const ObjectPath& objectPath
, const std::map<InterfaceName, std::map<PropertyName, Variant>>& interfacesAndProperties) = 0;
virtual void onInterfacesRemoved( const ObjectPath& objectPath
, const std::vector<InterfaceName>& interfaces) = 0;
public:
std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>> GetManagedObjects()
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
ObjectManager_proxy(ObjectManager_proxy&&) = delete;
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = delete;
std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>> GetManagedObjects()
{
std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>> objectsInterfacesAndProperties;
std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>> objectsInterfacesAndProperties;
m_proxy.callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
return objectsInterfacesAndProperties;
}
template <typename _Function>
PendingAsyncCall GetManagedObjectsAsync(_Function&& callback)
template <typename Function>
PendingAsyncCall GetManagedObjectsAsync(Function&& callback)
{
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<_Function>(callback));
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<Function>(callback));
}
template <typename _Function>
[[nodiscard]] Slot GetManagedObjectsAsync(_Function&& callback, return_slot_t)
template <typename Function>
[[nodiscard]] Slot GetManagedObjectsAsync(Function&& callback, return_slot_t)
{
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<_Function>(callback), return_slot);
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<Function>(callback), return_slot);
}
std::future<std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>>> GetManagedObjectsAsync(with_future_t)
std::future<std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>>> GetManagedObjectsAsync(with_future_t)
{
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).getResultAsFuture<std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>>>();
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).getResultAsFuture<std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>>>();
}
Awaitable<std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>>> GetManagedObjectsAsync(with_awaitable_t)
{
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).getResultAsAwaitable<std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>>>();
}
private:
sdbus::IProxy& m_proxy;
IProxy& m_proxy;
};
// Adaptors for the above-listed standard D-Bus interfaces are not necessary because the functionality
@@ -375,15 +410,10 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
protected:
Properties_adaptor(sdbus::IObject& object) : m_object(object)
explicit Properties_adaptor(IObject& object) : m_object(object)
{
}
Properties_adaptor(const Properties_adaptor&) = delete;
Properties_adaptor& operator=(const Properties_adaptor&) = delete;
Properties_adaptor(Properties_adaptor&&) = delete;
Properties_adaptor& operator=(Properties_adaptor&&) = delete;
~Properties_adaptor() = default;
void registerAdaptor()
@@ -391,6 +421,11 @@ namespace sdbus {
}
public:
Properties_adaptor(const Properties_adaptor&) = delete;
Properties_adaptor& operator=(const Properties_adaptor&) = delete;
Properties_adaptor(Properties_adaptor&&) = delete;
Properties_adaptor& operator=(Properties_adaptor&&) = delete;
void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector<PropertyName>& properties)
{
m_object.emitPropertiesChangedSignal(interfaceName, properties);
@@ -412,13 +447,13 @@ namespace sdbus {
}
private:
sdbus::IObject& m_object;
IObject& m_object;
};
/*!
* @brief Object Manager Convenience Adaptor
*
* Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces
* Adding this class as Interfaces.. template parameter of class AdaptorInterfaces
* implements the *GetManagedObjects()* method of the [org.freedesktop.DBus.ObjectManager.GetManagedObjects](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
* interface.
*
@@ -430,15 +465,10 @@ namespace sdbus {
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
protected:
explicit ObjectManager_adaptor(sdbus::IObject& object) : m_object(object)
explicit ObjectManager_adaptor(IObject& object) : m_object(object)
{
}
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor(ObjectManager_adaptor&&) = delete;
ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = delete;
~ObjectManager_adaptor() = default;
void registerAdaptor()
@@ -446,34 +476,35 @@ namespace sdbus {
m_object.addObjectManager();
}
public:
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete;
ObjectManager_adaptor(ObjectManager_adaptor&&) = delete;
ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = delete;
private:
sdbus::IObject& m_object;
IObject& m_object;
};
/*!
* @brief Managed Object Convenience Adaptor
*
* Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces
* Adding this class as Interfaces.. template parameter of class AdaptorInterfaces
* will extend the resulting object adaptor with emitInterfacesAddedSignal()/emitInterfacesRemovedSignal()
* according to org.freedesktop.DBus.ObjectManager.InterfacesAdded/.InterfacesRemoved.
*
* Note that objects which implement this adaptor require an object manager (e.g via ObjectManager_adaptor) to be
* instantiated on one of it's parent object paths or the same path. InterfacesAdded/InterfacesRemoved
* Note that objects which implement this adaptor require an object manager (e.g., via ObjectManager_adaptor) to be
* instantiated on one of its parent object paths or the same path. InterfacesAdded/InterfacesRemoved
* signals are sent from the closest object manager at either the same path or the closest parent path of an object.
*/
class ManagedObject_adaptor
{
protected:
explicit ManagedObject_adaptor(sdbus::IObject& object)
explicit ManagedObject_adaptor(IObject& object)
: m_object(object)
{
}
ManagedObject_adaptor(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor(ManagedObject_adaptor&&) = delete;
ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = delete;
~ManagedObject_adaptor() = default;
void registerAdaptor()
@@ -481,6 +512,11 @@ namespace sdbus {
}
public:
ManagedObject_adaptor(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete;
ManagedObject_adaptor(ManagedObject_adaptor&&) = delete;
ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = delete;
/*!
* @brief Emits InterfacesAdded signal for this object path
*
@@ -496,7 +532,7 @@ namespace sdbus {
*
* See IObject::emitInterfacesAddedSignal().
*/
void emitInterfacesAddedSignal(const std::vector<sdbus::InterfaceName>& interfaces)
void emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces)
{
m_object.emitInterfacesAddedSignal(interfaces);
}
@@ -522,9 +558,9 @@ namespace sdbus {
}
private:
sdbus::IObject& m_object;
IObject& m_object;
};
}
} // namespace sdbus
#endif /* SDBUS_CXX_STANDARDINTERFACES_H_ */
+221 -198
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TypeTraits.h
*
@@ -52,11 +52,11 @@
// Forward declarations
namespace sdbus {
class Variant;
template <typename... _ValueTypes> class Struct;
template <typename... ValueTypes> class Struct;
class ObjectPath;
class Signature;
class UnixFd;
template<typename _T1, typename _T2> using DictEntry = std::pair<_T1, _T2>;
template<typename T1, typename T2> using DictEntry = std::pair<T1, T2>;
class BusName;
class InterfaceName;
class MemberName;
@@ -66,10 +66,10 @@ namespace sdbus {
class Message;
class PropertySetCall;
class PropertyGetReply;
template <typename... _Results> class Result;
template <typename... Results> class Result;
class Error;
template <typename _T, typename _Enable = void> struct signature_of;
}
template <typename T, typename Enable = void> struct signature_of;
} // namespace sdbus
namespace sdbus {
@@ -109,19 +109,22 @@ namespace sdbus {
// Tag denoting that the variant shall embed the other variant as its value, instead of creating a copy
struct embed_variant_t { explicit embed_variant_t() = default; };
inline constexpr embed_variant_t embed_variant{};
// Tag denoting an asynchronous call that returns an awaitable as a handle
struct with_awaitable_t { explicit with_awaitable_t() = default; };
inline constexpr with_awaitable_t with_awaitable{};
// Helper for static assert
template <class... _T> constexpr bool always_false = false;
template <class... T> constexpr bool always_false = false;
// Helper operator+ for concatenation of `std::array`s
template <typename _T, std::size_t _N1, std::size_t _N2>
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs);
template <typename T, std::size_t N1, std::size_t N2>
constexpr std::array<T, N1 + N2> operator+(std::array<T, N1> lhs, std::array<T, N2> rhs);
// Template specializations for getting D-Bus signatures from C++ types
template <typename _T>
constexpr auto signature_of_v = signature_of<_T>::value;
template <typename T>
constexpr auto signature_of_v = signature_of<T>::value;
template <typename _T, typename _Enable>
template <typename T, typename Enable>
struct signature_of
{
static constexpr bool is_valid = false;
@@ -131,28 +134,28 @@ namespace sdbus {
{
// See using-sdbus-c++.md, section "Extending sdbus-c++ type system",
// on how to teach sdbus-c++ about your custom types
static_assert(always_false<_T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)");
static_assert(always_false<T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)");
};
};
template <typename _T>
struct signature_of<const _T> : signature_of<_T>
template <typename T>
struct signature_of<const T> : signature_of<T>
{};
template <typename _T>
struct signature_of<volatile _T> : signature_of<_T>
template <typename T>
struct signature_of<volatile T> : signature_of<T>
{};
template <typename _T>
struct signature_of<const volatile _T> : signature_of<_T>
template <typename T>
struct signature_of<const volatile T> : signature_of<T>
{};
template <typename _T>
struct signature_of<_T&> : signature_of<_T>
template <typename T>
struct signature_of<T&> : signature_of<T>
{};
template <typename _T>
struct signature_of<_T&&> : signature_of<_T>
template <typename T>
struct signature_of<T&&> : signature_of<T>
{};
template <>
@@ -255,12 +258,12 @@ namespace sdbus {
struct signature_of<const char*> : signature_of<std::string>
{};
template <std::size_t _N>
struct signature_of<char[_N]> : signature_of<std::string>
template <std::size_t N>
struct signature_of<char[N]> : signature_of<std::string>
{};
template <std::size_t _N>
struct signature_of<const char[_N]> : signature_of<std::string>
template <std::size_t N>
struct signature_of<const char[N]> : signature_of<std::string>
{};
template <>
@@ -275,10 +278,10 @@ namespace sdbus {
struct signature_of<MemberName> : signature_of<std::string>
{};
template <typename... _ValueTypes>
struct signature_of<Struct<_ValueTypes...>>
template <typename... ValueTypes>
struct signature_of<Struct<ValueTypes...>>
{
static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...);
static constexpr std::array contents = (signature_of_v<ValueTypes> + ...);
static constexpr std::array value = std::array{'('} + contents + std::array{')'};
static constexpr char type_value{'r'}; /* Not actually used in signatures on D-Bus, see specs */
static constexpr bool is_valid = true;
@@ -321,93 +324,93 @@ namespace sdbus {
static constexpr bool is_trivial_dbus_type = false;
};
template <typename _T1, typename _T2>
struct signature_of<DictEntry<_T1, _T2>>
template <typename T1, typename T2>
struct signature_of<DictEntry<T1, T2>>
{
static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<_T1, _T2>> + std::array{'}'};
static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<T1, T2>> + std::array{'}'};
static constexpr char type_value{'e'}; /* Not actually used in signatures on D-Bus, see specs */
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
};
template <typename _Element, typename _Allocator>
struct signature_of<std::vector<_Element, _Allocator>>
template <typename Element, typename Allocator>
struct signature_of<std::vector<Element, Allocator>>
{
static constexpr std::array value = std::array{'a'} + signature_of_v<_Element>;
static constexpr std::array value = std::array{'a'} + signature_of_v<Element>;
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
};
template <typename _Element, std::size_t _Size>
struct signature_of<std::array<_Element, _Size>> : signature_of<std::vector<_Element>>
template <typename Element, std::size_t Size>
struct signature_of<std::array<Element, Size>> : signature_of<std::vector<Element>>
{
};
#ifdef __cpp_lib_span
template <typename _Element, std::size_t _Extent>
struct signature_of<std::span<_Element, _Extent>> : signature_of<std::vector<_Element>>
template <typename Element, std::size_t Extent>
struct signature_of<std::span<Element, Extent>> : signature_of<std::vector<Element>>
{
};
#endif
template <typename _Enum> // is_const_v and is_volatile_v to avoid ambiguity conflicts with const and volatile specializations of signature_of
struct signature_of<_Enum, typename std::enable_if_t<std::is_enum_v<_Enum> && !std::is_const_v<_Enum> && !std::is_volatile_v<_Enum>>>
: signature_of<std::underlying_type_t<_Enum>>
template <typename Enum> // is_const_v and is_volatile_v to avoid ambiguity conflicts with const and volatile specializations of signature_of
struct signature_of<Enum, std::enable_if_t<std::is_enum_v<Enum> && !std::is_const_v<Enum> && !std::is_volatile_v<Enum>>>
: signature_of<std::underlying_type_t<Enum>>
{};
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
template <typename Key, typename Value, typename Compare, typename Allocator>
struct signature_of<std::map<Key, Value, Compare, Allocator>>
{
static constexpr std::array value = std::array{'a'} + signature_of_v<DictEntry<_Key, _Value>>;
static constexpr std::array value = std::array{'a'} + signature_of_v<DictEntry<Key, Value>>;
static constexpr bool is_valid = true;
static constexpr bool is_trivial_dbus_type = false;
};
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
struct signature_of<std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>>
: signature_of<std::map<_Key, _Value>>
template <typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator>
struct signature_of<std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>>
: signature_of<std::map<Key, Value>>
{
};
template <typename... _Types>
struct signature_of<std::tuple<_Types...>> // A simple concatenation of signatures of _Types
template <typename... Types>
struct signature_of<std::tuple<Types...>> // A simple concatenation of signatures of _Types
{
static constexpr std::array value = (std::array<char, 0>{} + ... + signature_of_v<_Types>);
static constexpr std::array value = (std::array<char, 0>{} + ... + signature_of_v<Types>);
static constexpr bool is_valid = false;
static constexpr bool is_trivial_dbus_type = false;
};
// To simplify conversions of arrays to C strings
template <typename _T, std::size_t _N>
constexpr auto as_null_terminated(std::array<_T, _N> arr)
template <typename T, std::size_t N>
constexpr auto as_null_terminated(std::array<T, N> arr)
{
return arr + std::array<_T, 1>{0};
return arr + std::array<T, 1>{0};
}
// Function traits implementation inspired by (c) kennytm,
// https://github.com/kennytm/utils/blob/master/traits.hpp
template <typename _Type>
struct function_traits : function_traits<decltype(&_Type::operator())>
template <typename Type>
struct function_traits : function_traits<decltype(&Type::operator())>
{};
template <typename _Type>
struct function_traits<const _Type> : function_traits<_Type>
template <typename Type>
struct function_traits<const Type> : function_traits<Type>
{};
template <typename _Type>
struct function_traits<_Type&> : function_traits<_Type>
template <typename Type>
struct function_traits<Type&> : function_traits<Type>
{};
template <typename _ReturnType, typename... _Args>
template <typename ReturnType, typename... Args>
struct function_traits_base
{
typedef _ReturnType result_type;
typedef std::tuple<_Args...> arguments_type;
typedef std::tuple<std::decay_t<_Args>...> decayed_arguments_type;
using result_type = ReturnType;
using arguments_type = std::tuple<Args...>;
using decayed_arguments_type = std::tuple<std::decay_t<Args>...>;
typedef _ReturnType function_type(_Args...);
using function_type = ReturnType (Args...);
static constexpr std::size_t arity = sizeof...(_Args);
static constexpr std::size_t arity = sizeof...(Args);
// template <size_t _Idx, typename _Enabled = void>
// struct arg;
@@ -424,175 +427,192 @@ namespace sdbus {
// typedef void type;
// };
template <size_t _Idx>
template <size_t Idx>
struct arg
{
typedef std::tuple_element_t<_Idx, std::tuple<_Args...>> type;
using type = std::tuple_element_t<Idx, std::tuple<Args...>>;
};
template <size_t _Idx>
using arg_t = typename arg<_Idx>::type;
template <size_t Idx>
using arg_t = typename arg<Idx>::type;
};
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_Args...)> : function_traits_base<_ReturnType, _Args...>
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType(Args...)> : function_traits_base<ReturnType, Args...>
{
static constexpr bool is_async = false;
static constexpr bool has_error_param = false;
};
template <typename... _Args>
struct function_traits<void(std::optional<Error>, _Args...)> : function_traits_base<void, _Args...>
template <typename... Args>
struct function_traits<void(std::optional<Error>, Args...)> : function_traits_base<void, Args...>
{
static constexpr bool has_error_param = true;
};
template <typename... _Args, typename... _Results>
struct function_traits<void(Result<_Results...>, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
template <typename... Args>
struct function_traits<void(std::optional<Error>&&, Args...)> : function_traits_base<void, Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<_Results...>;
static constexpr bool has_error_param = true;
};
template <typename... _Args, typename... _Results>
struct function_traits<void(Result<_Results...>&&, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
template <typename... Args>
struct function_traits<void(const std::optional<Error>&, Args...)> : function_traits_base<void, Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<_Results...>;
static constexpr bool has_error_param = true;
};
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(*)(_Args...)> : function_traits<_ReturnType(_Args...)>
template <typename... Args, typename... Results>
struct function_traits<void(Result<Results...>, Args...)> : function_traits_base<std::tuple<Results...>, Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<Results...>;
};
template <typename... Args, typename... Results>
struct function_traits<void(Result<Results...>&&, Args...)> : function_traits_base<std::tuple<Results...>, Args...>
{
static constexpr bool is_async = true;
using async_result_t = Result<Results...>;
};
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType(*)(Args...)> : function_traits<ReturnType(Args...)>
{};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...)> : function_traits<_ReturnType(_Args...)>
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...)> : function_traits<ReturnType(Args...)>
{
typedef _ClassType& owner_type;
using owner_type = ClassType &;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const> : function_traits<_ReturnType(_Args...)>
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> : function_traits<ReturnType(Args...)>
{
typedef const _ClassType& owner_type;
using owner_type = const ClassType &;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile> : function_traits<_ReturnType(_Args...)>
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) volatile> : function_traits<ReturnType(Args...)>
{
typedef volatile _ClassType& owner_type;
using owner_type = volatile ClassType &;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile> : function_traits<_ReturnType(_Args...)>
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const volatile> : function_traits<ReturnType(Args...)>
{
typedef const volatile _ClassType& owner_type;
using owner_type = const volatile ClassType &;
};
template <typename FunctionType>
struct function_traits<std::function<FunctionType>> : function_traits<FunctionType>
{};
template <class _Function>
constexpr auto is_async_method_v = function_traits<_Function>::is_async;
template <class Function>
constexpr auto is_async_method_v = function_traits<Function>::is_async;
template <class _Function>
constexpr auto has_error_param_v = function_traits<_Function>::has_error_param;
template <class Function>
constexpr auto has_error_param_v = function_traits<Function>::has_error_param;
template <typename _FunctionType>
using function_arguments_t = typename function_traits<_FunctionType>::arguments_type;
template <typename FunctionType>
using function_arguments_t = typename function_traits<FunctionType>::arguments_type;
template <typename _FunctionType, size_t _Idx>
using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>;
template <typename FunctionType, size_t Idx>
using function_argument_t = typename function_traits<FunctionType>::template arg_t<Idx>;
template <typename _FunctionType>
constexpr auto function_argument_count_v = function_traits<_FunctionType>::arity;
template <typename FunctionType>
constexpr auto function_argument_count_v = function_traits<FunctionType>::arity;
template <typename _FunctionType>
using function_result_t = typename function_traits<_FunctionType>::result_type;
template <typename FunctionType>
using function_result_t = typename function_traits<FunctionType>::result_type;
template <typename _Function>
template <typename Function>
struct tuple_of_function_input_arg_types
{
typedef typename function_traits<_Function>::decayed_arguments_type type;
using type = typename function_traits<Function>::decayed_arguments_type;
};
template <typename _Function>
using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<_Function>::type;
template <typename Function>
using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<Function>::type;
template <typename _Function>
template <typename Function>
struct tuple_of_function_output_arg_types
{
typedef typename function_traits<_Function>::result_type type;
using type = typename function_traits<Function>::result_type;
};
template <typename _Function>
using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type;
template <typename Function>
using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<Function>::type;
template <typename _Function>
struct signature_of_function_input_arguments : signature_of<tuple_of_function_input_arg_types_t<_Function>>
template <typename Function>
struct signature_of_function_input_arguments : signature_of<tuple_of_function_input_arg_types_t<Function>>
{
static std::string value_as_string()
{
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_input_arg_types_t<_Function>>);
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_input_arg_types_t<Function>>);
return signature.data();
}
};
template <typename _Function>
inline auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<_Function>::value_as_string();
template <typename Function>
inline const auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<Function>::value_as_string();
template <typename _Function>
struct signature_of_function_output_arguments : signature_of<tuple_of_function_output_arg_types_t<_Function>>
template <typename Function>
struct signature_of_function_output_arguments : signature_of<tuple_of_function_output_arg_types_t<Function>>
{
static std::string value_as_string()
{
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_output_arg_types_t<_Function>>);
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_output_arg_types_t<Function>>);
return signature.data();
}
};
template <typename _Function>
inline auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<_Function>::value_as_string();
template <typename Function>
inline const auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<Function>::value_as_string();
// std::future stuff for return values of async calls
template <typename... _Args> struct future_return
template <typename... Args> struct future_return
{
typedef std::tuple<_Args...> type;
using type = std::tuple<Args...>;
};
template <> struct future_return<>
{
typedef void type;
using type = void;
};
template <typename _Type> struct future_return<_Type>
template <typename Type> struct future_return<Type>
{
typedef _Type type;
using type = Type;
};
template <typename... _Args>
using future_return_t = typename future_return<_Args...>::type;
template <typename... Args>
using future_return_t = typename future_return<Args...>::type;
// For awaitable return types, the same scheme from futures can be reused
// so just provide an alias for visual distinction between the two
template <typename... Args>
using awaitable_return_t = typename future_return<Args...>::type;
// Credit: Piotr Skotnicki (https://stackoverflow.com/a/57639506)
template <typename, typename>
constexpr bool is_one_of_variants_types = false;
template <typename... _VariantTypes, typename _QueriedType>
constexpr bool is_one_of_variants_types<std::variant<_VariantTypes...>, _QueriedType>
= (std::is_same_v<_QueriedType, _VariantTypes> || ...);
template <typename... VariantTypes, typename QueriedType>
constexpr bool is_one_of_variants_types<std::variant<VariantTypes...>, QueriedType>
= (std::is_same_v<QueriedType, VariantTypes> || ...);
// Wrapper (tag) denoting we want to serialize user-defined struct
// into a D-Bus message as a dictionary of strings to variants.
template <typename _Struct>
template <typename Struct>
struct as_dictionary
{
explicit as_dictionary(const _Struct& s) : m_struct(s) {}
const _Struct& m_struct;
explicit as_dictionary(const Struct& strct) : m_struct(strct) {}
const Struct& m_struct; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
};
template <typename _Type>
const _Type& as_dictionary_if_struct(const _Type& object)
template <typename Type>
const Type& as_dictionary_if_struct(const Type& object)
{
return object; // identity in case _Type is not struct (user-defined structs shall provide an overload)
}
@@ -601,7 +621,7 @@ namespace sdbus {
// Strict means that every key of the deserialized dictionary must have its counterpart member in the struct, otherwise an exception is thrown.
// Relaxed means that a key that does not have a matching struct member is silently ignored.
// The behavior can be overridden for user-defined struct by specializing this variable template.
template <typename _Struct>
template <typename Struct>
constexpr auto strict_dict_as_struct_deserialization_v = true;
// By default, the struct-as-dict serialization strategy is single-level only (as opposed to nested).
@@ -609,94 +629,97 @@ namespace sdbus {
// Nested means that the struct *and* its members that are structs are all serialized as a dictionary. If nested strategy is also
// defined for the nested struct, then the same behavior applies for that struct, recursively.
// The behavior can be overridden for user-defined struct by specializing this variable template.
template <typename _Struct>
template <typename Struct>
constexpr auto nested_struct_as_dict_serialization_v = false;
namespace detail
{
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
constexpr decltype(auto) apply_impl( _Function&& f
, Result<_Args...>&& r
, _Tuple&& t
, std::index_sequence<_I...> )
template <class Function, class Tuple, typename... Args, std::size_t... I>
constexpr decltype(auto) apply_impl( Function&& fun
, Result<Args...>&& res
, Tuple&& tuple
, std::index_sequence<I...> )
{
return std::forward<_Function>(f)(std::move(r), std::get<_I>(std::forward<_Tuple>(t))...);
return std::forward<Function>(fun)(std::move(res), std::get<I>(std::forward<Tuple>(tuple))...);
}
template <class _Function, class _Tuple, std::size_t... _I>
decltype(auto) apply_impl( _Function&& f
, std::optional<Error> e
, _Tuple&& t
, std::index_sequence<_I...> )
template <class Function, class Tuple, std::size_t... I>
decltype(auto) apply_impl( Function&& fun
, std::optional<Error> err
, Tuple&& tuple
, std::index_sequence<I...> )
{
return std::forward<_Function>(f)(std::move(e), std::get<_I>(std::forward<_Tuple>(t))...);
return std::forward<Function>(fun)(std::move(err), std::get<I>(std::forward<Tuple>(tuple))...);
}
// For non-void returning functions, apply_impl simply returns function return value (a tuple of values).
// For void-returning functions, apply_impl returns an empty tuple.
template <class _Function, class _Tuple, std::size_t... _I>
constexpr decltype(auto) apply_impl( _Function&& f
, _Tuple&& t
, std::index_sequence<_I...> )
template <class Function, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl( Function&& fun
, Tuple&& tuple
, std::index_sequence<I...> )
{
if constexpr (!std::is_void_v<function_result_t<_Function>>)
return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...);
if constexpr (!std::is_void_v<function_result_t<Function>>)
return std::forward<Function>(fun)(std::get<I>(std::forward<Tuple>(tuple))...);
else
return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...), std::tuple<>{};
return std::forward<Function>(fun)(std::get<I>(std::forward<Tuple>(tuple))...), std::tuple<>{};
}
} // namespace detail
// Convert tuple `t' of values into a list of arguments
// and invoke function `f' with those arguments.
template <class Function, class Tuple>
constexpr decltype(auto) apply(Function&& fun, Tuple&& tuple)
{
return detail::apply_impl( std::forward<Function>(fun)
, std::forward<Tuple>(tuple)
, std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{} );
}
// Convert tuple `t' of values into a list of arguments
// and invoke function `f' with those arguments.
template <class _Function, class _Tuple>
constexpr decltype(auto) apply(_Function&& f, _Tuple&& t)
template <class Function, class Tuple, typename... Args>
constexpr decltype(auto) apply(Function&& fun, Result<Args...>&& res, Tuple&& tuple)
{
return detail::apply_impl( std::forward<_Function>(f)
, std::forward<_Tuple>(t)
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
return detail::apply_impl( std::forward<Function>(fun)
, std::move(res)
, std::forward<Tuple>(tuple)
, std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{} );
}
// Convert tuple `t' of values into a list of arguments
// and invoke function `f' with those arguments.
template <class _Function, class _Tuple, typename... _Args>
constexpr decltype(auto) apply(_Function&& f, Result<_Args...>&& r, _Tuple&& t)
template <class Function, class Tuple>
decltype(auto) apply(Function&& fun, std::optional<Error> err, Tuple&& tuple)
{
return detail::apply_impl( std::forward<_Function>(f)
, std::move(r)
, std::forward<_Tuple>(t)
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
}
// Convert tuple `t' of values into a list of arguments
// and invoke function `f' with those arguments.
template <class _Function, class _Tuple>
decltype(auto) apply(_Function&& f, std::optional<Error> e, _Tuple&& t)
{
return detail::apply_impl( std::forward<_Function>(f)
, std::move(e)
, std::forward<_Tuple>(t)
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
return detail::apply_impl( std::forward<Function>(fun)
, std::move(err)
, std::forward<Tuple>(tuple)
, std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{} );
}
// Convenient concatenation of arrays
template <typename _T, std::size_t _N1, std::size_t _N2>
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs)
template <typename T, std::size_t N1, std::size_t N2>
constexpr std::array<T, N1 + N2> operator+(std::array<T, N1> lhs, std::array<T, N2> rhs)
{
std::array<_T, _N1 + _N2> result{};
std::size_t index = 0;
std::array<T, N1 + N2> result{};
for (auto& el : lhs) {
result[index] = std::move(el);
++index;
}
for (auto& el : rhs) {
result[index] = std::move(el);
++index;
}
std::move(lhs.begin(), lhs.end(), result.begin());
std::move(rhs.begin(), rhs.end(), result.begin() + N1);
// std::size_t index = 0;
// for (auto& item : lhs) {
// result[index] = std::move(item);
// ++index;
// }
// for (auto& item : rhs) {
// result[index] = std::move(item);
// ++index;
// }
return result;
}
}
} // namespace sdbus
#endif /* SDBUS_CXX_TYPETRAITS_H_ */
+73 -56
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Types.h
*
@@ -36,7 +36,6 @@
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <utility>
namespace sdbus {
@@ -50,7 +49,7 @@ namespace sdbus {
* Some const methods are conceptually const, but not physically const,
* thus are not thread-safe. This is by design: normally, clients
* should process a single Variant object in a single thread at a time.
* Otherwise they need to take care of synchronization by themselves.
* Otherwise, they need to take care of synchronization by themselves.
*
***********************************************/
class Variant
@@ -58,10 +57,10 @@ namespace sdbus {
public:
Variant();
template <typename _ValueType>
explicit Variant(const _ValueType& value) : Variant()
template <typename ValueType>
explicit Variant(const ValueType& value) : Variant()
{
msg_.openVariant<_ValueType>();
msg_.openVariant<ValueType>();
msg_ << value;
msg_.closeVariant();
msg_.seal();
@@ -75,8 +74,8 @@ namespace sdbus {
msg_.seal();
}
template <typename _Struct>
explicit Variant(const as_dictionary<_Struct>& value) : Variant()
template <typename Struct>
explicit Variant(const as_dictionary<Struct>& value) : Variant()
{
msg_.openVariant<std::map<std::string, Variant>>();
msg_ << as_dictionary(value.m_struct);
@@ -84,46 +83,54 @@ namespace sdbus {
msg_.seal();
}
template <typename... _Elements>
Variant(const std::variant<_Elements...>& value)
template <typename... Elements>
Variant(const std::variant<Elements...>& value) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions): implicit conversion intentional
: Variant()
{
msg_ << value;
msg_.seal();
}
template <typename _ValueType>
_ValueType get() const
template <typename ValueType>
ValueType get() const
{
msg_.rewind(false);
msg_.enterVariant<_ValueType>();
_ValueType val;
msg_.enterVariant<ValueType>();
ValueType val;
msg_ >> val;
msg_.exitVariant();
return val;
}
// Only allow conversion operator for true D-Bus type representations in C++
template <typename _ValueType, typename = std::enable_if_t<signature_of<_ValueType>::is_valid>>
explicit operator _ValueType() const
[[nodiscard]] std::string dumpToString() const
{
return get<_ValueType>();
msg_.rewind(false);
return msg_.dumpToString(Message::DumpFlags::SubtreeOnly);
}
template <typename... _Elements>
operator std::variant<_Elements...>() const
// Only allow conversion operator for true D-Bus type representations in C++
// NOLINTNEXTLINE(modernize-use-constraints): TODO for future: Use `requires signature_of<_ValueType>::is_valid` (when we stop supporting C++17 in public API)
template <typename ValueType, typename = std::enable_if_t<signature_of<ValueType>::is_valid>>
explicit operator ValueType() const
{
std::variant<_Elements...> result;
return get<ValueType>();
}
template <typename... Elements>
operator std::variant<Elements...>() const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions): implicit conversion intentional
{
std::variant<Elements...> result;
msg_.rewind(false);
msg_ >> result;
return result;
}
template <typename _Type>
template <typename Type>
bool containsValueOfType() const
{
constexpr auto signature = as_null_terminated(signature_of_v<_Type>);
constexpr auto signature = as_null_terminated(signature_of_v<Type>);
return std::strcmp(signature.data(), peekValueType()) == 0;
}
@@ -134,7 +141,7 @@ namespace sdbus {
const char* peekValueType() const;
private:
mutable PlainMessage msg_{};
mutable PlainMessage msg_;
};
/********************************************//**
@@ -147,42 +154,48 @@ namespace sdbus {
* std::tuple_size and in structured bindings.
*
***********************************************/
template <typename... _ValueTypes>
template <typename... ValueTypes>
class Struct
: public std::tuple<_ValueTypes...>
: public std::tuple<ValueTypes...>
{
public:
using std::tuple<_ValueTypes...>::tuple;
using std::tuple<ValueTypes...>::tuple;
Struct() = default;
explicit Struct(const std::tuple<_ValueTypes...>& t)
: std::tuple<_ValueTypes...>(t)
explicit Struct(const std::tuple<ValueTypes...>& tuple)
: std::tuple<ValueTypes...>(tuple)
{
}
template <std::size_t _I>
auto& get()
template <std::size_t I>
[[nodiscard]] auto& get()
{
return std::get<_I>(*this);
return std::get<I>(*this);
}
template <std::size_t _I>
const auto& get() const
template <std::size_t I>
[[nodiscard]] const auto& get() const
{
return std::get<_I>(*this);
return std::get<I>(*this);
}
};
template <typename... _Elements>
Struct(_Elements...) -> Struct<_Elements...>;
template <typename... Elements>
Struct(Elements...) -> Struct<Elements...>;
template<typename... _Elements>
constexpr Struct<std::decay_t<_Elements>...>
make_struct(_Elements&&... args)
template <typename... Elements>
Struct(const std::tuple<Elements...>&) -> Struct<Elements...>;
template <typename... Elements>
Struct(std::tuple<Elements...>&&) -> Struct<Elements...>;
template<typename... Elements>
constexpr Struct<std::decay_t<Elements>...>
make_struct(Elements&&... args)
{
typedef Struct<std::decay_t<_Elements>...> result_type;
return result_type(std::forward<_Elements>(args)...);
using result_type = Struct<std::decay_t<Elements>...>;
return result_type(std::forward<Elements>(args)...);
}
/********************************************//**
@@ -334,12 +347,12 @@ namespace sdbus {
return *this;
}
UnixFd(UnixFd&& other)
UnixFd(UnixFd&& other) noexcept
{
*this = std::move(other);
}
UnixFd& operator=(UnixFd&& other)
UnixFd& operator=(UnixFd&& other) noexcept
{
if (this == &other)
{
@@ -398,21 +411,23 @@ namespace sdbus {
* value_type in STL(-like) associative containers.
*
***********************************************/
template<typename _T1, typename _T2>
using DictEntry = std::pair<_T1, _T2>;
template<typename T1, typename T2>
using DictEntry = std::pair<T1, T2>;
}
} // namespace sdbus
// Making sdbus::Struct implement the tuple-protocol, i.e. be a tuple-like type
template <size_t _I, typename... _ValueTypes>
struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>>
: std::tuple_element<_I, std::tuple<_ValueTypes...>>
template <size_t I, typename... ValueTypes>
struct std::tuple_element<I, sdbus::Struct<ValueTypes...>> // NOLINT(cert-dcl58-cpp): specialization in std namespace allowed in this case
: std::tuple_element<I, std::tuple<ValueTypes...>>
{};
template <typename... _ValueTypes>
struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
: std::tuple_size<std::tuple<_ValueTypes...>>
template <typename... ValueTypes>
struct std::tuple_size<sdbus::Struct<ValueTypes...>> // NOLINT(cert-dcl58-cpp): specialization in std namespace allowed in this case
: std::tuple_size<std::tuple<ValueTypes...>>
{};
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
/********************************************//**
* @name SDBUSCPP_REGISTER_STRUCT
*
@@ -457,7 +472,7 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
\
template <> \
struct signature_of<STRUCT> \
: signature_of<sdbus::Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
: signature_of<Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
{}; \
\
inline auto as_dictionary_if_struct(const STRUCT& object) \
@@ -465,9 +480,9 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
return as_dictionary<STRUCT>(object); \
} \
\
inline sdbus::Message& operator<<(sdbus::Message& msg, const STRUCT& items) \
inline Message& operator<<(Message& msg, const STRUCT& items) \
{ \
return msg << sdbus::Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
return msg << Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
} \
\
inline Message& operator<<(Message& msg, const as_dictionary<STRUCT>& s) \
@@ -594,4 +609,6 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
#define SDBUSCPP_PP_COMMA ,
#define SDBUSCPP_PP_SPACE
// NOLINTEND(cppcoreguidelines-macro-usage)
#endif /* SDBUS_CXX_TYPES_H_ */
+9 -9
View File
@@ -1,5 +1,5 @@
/**
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file VTableItems.h
*
@@ -38,11 +38,11 @@ namespace sdbus {
struct MethodVTableItem
{
template <typename _Function> MethodVTableItem& implementedAs(_Function&& callback);
template <typename Function> MethodVTableItem& implementedAs(Function&& callback);
MethodVTableItem& withInputParamNames(std::vector<std::string> names);
template <typename... _String> MethodVTableItem& withInputParamNames(_String... names);
template <typename... String> MethodVTableItem& withInputParamNames(String... names);
MethodVTableItem& withOutputParamNames(std::vector<std::string> names);
template <typename... _String> MethodVTableItem& withOutputParamNames(_String... names);
template <typename... String> MethodVTableItem& withOutputParamNames(String... names);
MethodVTableItem& markAsDeprecated();
MethodVTableItem& markAsPrivileged();
MethodVTableItem& withNoReply();
@@ -61,9 +61,9 @@ namespace sdbus {
struct SignalVTableItem
{
template <typename... _Args> SignalVTableItem& withParameters();
template <typename... _Args> SignalVTableItem& withParameters(std::vector<std::string> names);
template <typename... _Args, typename... _String> SignalVTableItem& withParameters(_String... names);
template <typename... Args> SignalVTableItem& withParameters();
template <typename... Args> SignalVTableItem& withParameters(std::vector<std::string> names);
template <typename... Args, typename... String> SignalVTableItem& withParameters(String... names);
SignalVTableItem& markAsDeprecated();
SignalName name;
@@ -77,8 +77,8 @@ namespace sdbus {
struct PropertyVTableItem
{
template <typename _Function> PropertyVTableItem& withGetter(_Function&& callback);
template <typename _Function> PropertyVTableItem& withSetter(_Function&& callback);
template <typename Function> PropertyVTableItem& withGetter(Function&& callback);
template <typename Function> PropertyVTableItem& withSetter(Function&& callback);
PropertyVTableItem& markAsDeprecated();
PropertyVTableItem& markAsPrivileged();
PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
+37 -37
View File
@@ -1,5 +1,5 @@
/**
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file VTableItems.inl
*
@@ -39,21 +39,21 @@ namespace sdbus {
/*** Method VTable Item ***/
/*** -------------------- ***/
template <typename _Function>
MethodVTableItem& MethodVTableItem::implementedAs(_Function&& callback)
template <typename Function>
MethodVTableItem& MethodVTableItem::implementedAs(Function&& callback)
{
inputSignature = signature_of_function_input_arguments_v<_Function>;
outputSignature = signature_of_function_output_arguments_v<_Function>;
callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call)
inputSignature = signature_of_function_input_arguments_v<Function>;
outputSignature = signature_of_function_output_arguments_v<Function>;
callbackHandler = [callback = std::forward<Function>(callback)](MethodCall call)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the message.
tuple_of_function_input_arg_types_t<_Function> inputArgs;
tuple_of_function_input_arg_types_t<Function> inputArgs;
// Deserialize input arguments from the message into the tuple.
call >> inputArgs;
if constexpr (!is_async_method_v<_Function>)
if constexpr (!is_async_method_v<Function>)
{
// Invoke callback with input arguments from the tuple.
auto ret = sdbus::apply(callback, inputArgs);
@@ -66,7 +66,7 @@ namespace sdbus {
else
{
// Invoke callback with input arguments from the tuple and with result object to be set later
using AsyncResult = typename function_traits<_Function>::async_result_t;
using AsyncResult = typename function_traits<Function>::async_result_t;
sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs));
}
};
@@ -81,10 +81,10 @@ namespace sdbus {
return *this;
}
template <typename... _String>
inline MethodVTableItem& MethodVTableItem::withInputParamNames(_String... names)
template <typename... String>
inline MethodVTableItem& MethodVTableItem::withInputParamNames(String... names)
{
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
return withInputParamNames({names...});
}
@@ -96,10 +96,10 @@ namespace sdbus {
return *this;
}
template <typename... _String>
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(_String... names)
template <typename... String>
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(String... names)
{
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
return withOutputParamNames({names...});
}
@@ -139,29 +139,29 @@ namespace sdbus {
/*** Signal VTable Item ***/
/*** -------------------- ***/
template <typename... _Args>
template <typename... Args>
inline SignalVTableItem& SignalVTableItem::withParameters()
{
signature = signature_of_function_input_arguments_v<void(_Args...)>;
signature = signature_of_function_input_arguments_v<void(Args...)>;
return *this;
}
template <typename... _Args>
template <typename... Args>
inline SignalVTableItem& SignalVTableItem::withParameters(std::vector<std::string> names)
{
paramNames = std::move(names);
return withParameters<_Args...>();
return withParameters<Args...>();
}
template <typename... _Args, typename... _String>
inline SignalVTableItem& SignalVTableItem::withParameters(_String... names)
template <typename... Args, typename... String>
inline SignalVTableItem& SignalVTableItem::withParameters(String... names)
{
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
static_assert(sizeof...(_Args) == sizeof...(_String), "Numbers of signal parameters and their names don't match");
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
static_assert(sizeof...(Args) == sizeof...(String), "Numbers of signal parameters and their names don't match");
return withParameters<_Args...>({names...});
return withParameters<Args...>({names...});
}
inline SignalVTableItem& SignalVTableItem::markAsDeprecated()
@@ -185,16 +185,16 @@ namespace sdbus {
/*** Property VTable Item ***/
/*** -------------------- ***/
template <typename _Function>
inline PropertyVTableItem& PropertyVTableItem::withGetter(_Function&& callback)
template <typename Function>
inline PropertyVTableItem& PropertyVTableItem::withGetter(Function&& callback)
{
static_assert(function_argument_count_v<_Function> == 0, "Property getter function must not take any arguments");
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
static_assert(function_argument_count_v<Function> == 0, "Property getter function must not take any arguments");
static_assert(!std::is_void_v<function_result_t<Function>>, "Property getter function must return property value");
if (signature.empty())
signature = signature_of_function_output_arguments_v<_Function>;
signature = signature_of_function_output_arguments_v<Function>;
getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
getter = [callback = std::forward<Function>(callback)](PropertyGetReply& reply)
{
// Get the propety value and serialize it into the pre-constructed reply message
reply << callback();
@@ -203,19 +203,19 @@ namespace sdbus {
return *this;
}
template <typename _Function>
inline PropertyVTableItem& PropertyVTableItem::withSetter(_Function&& callback)
template <typename Function>
inline PropertyVTableItem& PropertyVTableItem::withSetter(Function&& callback)
{
static_assert(function_argument_count_v<_Function> == 1, "Property setter function must take one parameter - the property value");
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
static_assert(function_argument_count_v<Function> == 1, "Property setter function must take one parameter - the property value");
static_assert(std::is_void_v<function_result_t<Function>>, "Property setter function must not return any value");
if (signature.empty())
signature = signature_of_function_input_arguments_v<_Function>;
signature = signature_of_function_input_arguments_v<Function>;
setter = [callback = std::forward<_Function>(callback)](PropertySetCall call)
setter = [callback = std::forward<Function>(callback)](PropertySetCall call)
{
// Default-construct property value
using property_type = function_argument_t<_Function, 0>;
using property_type = function_argument_t<Function, 0>;
std::decay_t<property_type> property;
// Deserialize property value from the incoming call message
+3 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file sdbus-c++.h
*
@@ -24,6 +24,7 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
// IWYU pragma: begin_exports
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
@@ -36,3 +37,4 @@
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Error.h>
#include <sdbus-c++/Flags.h>
// IWYU pragma: end_exports
+116 -84
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Connection.cpp
*
@@ -27,21 +27,34 @@
#include "Connection.h"
#include "sdbus-c++/Error.h"
#include "sdbus-c++/IConnection.h"
#include "sdbus-c++/Message.h"
#include "sdbus-c++/Types.h"
#include "sdbus-c++/TypeTraits.h"
#include "ISdBus.h"
#include "MessageUtils.h"
#include "ScopeGuard.h"
#include "SdBus.h"
#include "Utils.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <chrono>
#include <cstdint>
#include <ctime>
#include <memory>
#include <poll.h>
#include <string>
#include <sys/eventfd.h>
#include SDBUS_HEADER
#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++
#include <systemd/sd-event.h>
#endif
#include <unistd.h>
#include <utility>
#include <vector>
namespace sdbus::internal {
@@ -105,9 +118,19 @@ Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
}
Connection::~Connection()
try
{
Connection::leaveEventLoop();
}
catch (...) // NOLINT(bugprone-empty-catch)
{
// Theoretically, we can fail to notify the event fd or join with the joinable thread...
// What to do now here in the destructor? That is the question:
// 1. Report the problem... but how, where?
// 2. Terminate immediately... too harsh?
// 3. Ignore and go on... even when some resources may be lingering?
// Since the failure here is expected to be very unlikely, we choose the defensive approach of (3).
}
void Connection::requestName(const ServiceName& name)
{
@@ -194,7 +217,7 @@ Slot Connection::addObjectManager(const ObjectPath& objectPath, return_slot_t)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
}
void Connection::setMethodCallTimeout(uint64_t timeout)
@@ -206,7 +229,7 @@ void Connection::setMethodCallTimeout(uint64_t timeout)
uint64_t Connection::getMethodCallTimeout() const
{
uint64_t timeout;
uint64_t timeout{};
auto r = sdbus_->sd_bus_get_method_call_timeout(bus_.get(), &timeout);
@@ -230,9 +253,9 @@ Slot Connection::addMatch(const std::string& match, message_handler callback, re
auto r = sdbus_->sd_bus_add_match(bus_.get(), &slot, match.c_str(), &Connection::sdbus_match_callback, matchInfo.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add match", -r);
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }};
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
}
void Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback)
@@ -259,9 +282,9 @@ Slot Connection::addMatchAsync( const std::string& match
, matchInfo.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add match", -r);
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }};
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
}
void Connection::attachSdEventLoop(sd_event *event, int priority)
@@ -306,7 +329,7 @@ Slot Connection::createSdEventSlot(sd_event *event)
(void)sd_event_default(&event);
SDBUS_THROW_ERROR_IF(!event, "Invalid sd_event handle", EINVAL);
return Slot{event, [](void* event){ sd_event_unref((sd_event*)event); }};
return Slot{event, [](void* event){ sd_event_unref(static_cast<sd_event*>(event)); }};
}
Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority)
@@ -314,7 +337,7 @@ Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority)
sd_event_source *timeEventSource{};
auto r = sd_event_add_time(event, &timeEventSource, CLOCK_MONOTONIC, 0, 0, onSdTimerEvent, this);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add timer event", -r);
Slot sdTimeEventSource{timeEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }};
Slot sdTimeEventSource{timeEventSource, [](void* source){ deleteSdEventSource(static_cast<sd_event_source*>(source)); }};
r = sd_event_source_set_priority(timeEventSource, priority);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event priority", -r);
@@ -325,12 +348,12 @@ Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority)
return sdTimeEventSource;
}
Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority)
Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority) // NOLINT(bugprone-easily-swappable-parameters)
{
sd_event_source *ioEventSource{};
auto r = sd_event_add_io(event, &ioEventSource, fd, 0, onSdIoEvent, this);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add io event", -r);
Slot sdIoEventSource{ioEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }};
Slot sdIoEventSource{ioEventSource, [](void* source){ deleteSdEventSource(static_cast<sd_event_source*>(source)); }};
r = sd_event_source_set_prepare(ioEventSource, onSdEventPrepare);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for IO event", -r);
@@ -344,12 +367,12 @@ Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority
return sdIoEventSource;
}
Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int priority)
Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int priority) // NOLINT(bugprone-easily-swappable-parameters)
{
sd_event_source *internalEventSource{};
auto r = sd_event_add_io(event, &internalEventSource, fd, 0, onSdInternalEvent, this);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add internal event", -r);
Slot sdInternalEventSource{internalEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }};
Slot sdInternalEventSource{internalEventSource, [](void* source){ deleteSdEventSource(static_cast<sd_event_source*>(source)); }};
// sd-event loop calls prepare callbacks for all event sources, not just for the one that fired now.
// So since onSdEventPrepare is already registered on ioEventSource, we don't need to duplicate it here.
@@ -367,7 +390,7 @@ Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int pr
int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
auto *connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
(void)connection->processPendingEvent();
@@ -377,7 +400,7 @@ int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *
int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
auto *connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
(void)connection->processPendingEvent();
@@ -387,7 +410,7 @@ int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*reven
int Connection::onSdInternalEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
auto *connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
// It's not really necessary to processPendingEvent() here. We just clear the event fd.
@@ -410,7 +433,7 @@ int Connection::onSdInternalEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /
int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
auto *connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
auto sdbusPollData = connection->getEventLoopPollData();
@@ -432,19 +455,19 @@ int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata)
// In case the timeout is infinite, we disable the timer in the sd_event loop.
// This prevents a syscall error, where `timerfd_settime` returns `EINVAL`,
// because the value is too big. See #324 for details
r = sd_event_source_set_enabled(sdTimeEventSource, sdbusPollData.timeout != sdbusPollData.timeout.max() ? SD_EVENT_ONESHOT : SD_EVENT_OFF);
r = sd_event_source_set_enabled(sdTimeEventSource, sdbusPollData.timeout != std::chrono::microseconds::max() ? SD_EVENT_ONESHOT : SD_EVENT_OFF);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enable time event source", -r);
return 1;
}
void Connection::deleteSdEventSource(sd_event_source *s)
void Connection::deleteSdEventSource(sd_event_source *source)
{
#if LIBSYSTEMD_VERSION>=243
sd_event_source_disable_unref(s);
sd_event_source_disable_unref(source);
#else
sd_event_source_set_enabled(s, SD_EVENT_OFF);
sd_event_source_unref(s);
sd_event_source_set_enabled(source, SD_EVENT_OFF);
sd_event_source_unref(source);
#endif
}
@@ -467,7 +490,7 @@ Slot Connection::addObjectVTable( const ObjectPath& objectPath
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register object vtable", -r);
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
}
PlainMessage Connection::createPlainMessage() const
@@ -478,6 +501,8 @@ PlainMessage Connection::createPlainMessage() const
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a plain message", -r);
// TODO: const_cast..? Finish the const correctness design
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return Message::Factory::create<PlainMessage>(sdbusMsg, const_cast<Connection*>(this), adopt_message);
}
@@ -498,13 +523,15 @@ MethodCall Connection::createMethodCall( const char* destination
auto r = sdbus_->sd_bus_message_new_method_call( bus_.get()
, &sdbusMsg
, !*destination ? nullptr : destination
, *destination == '\0' ? nullptr : destination
, objectPath
, interfaceName
, methodName);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method call", -r);
// TODO: const_cast..? Finish the const correctness design
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return Message::Factory::create<MethodCall>(sdbusMsg, const_cast<Connection*>(this), adopt_message);
}
@@ -525,6 +552,8 @@ Signal Connection::createSignal( const char* objectPath
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
// TODO: const_cast..? Finish the const correctness design
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return Message::Factory::create<Signal>(sdbusMsg, const_cast<Connection*>(this), adopt_message);
}
@@ -544,7 +573,7 @@ void Connection::emitPropertiesChangedSignal( const char* objectPath
auto r = sdbus_->sd_bus_emit_properties_changed_strv( bus_.get()
, objectPath
, interfaceName
, propNames.empty() ? nullptr : &names[0] );
, propNames.empty() ? nullptr : names.data() );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit PropertiesChanged signal", -r);
}
@@ -563,7 +592,7 @@ void Connection::emitInterfacesAddedSignal( const ObjectPath& objectPath
auto r = sdbus_->sd_bus_emit_interfaces_added_strv( bus_.get()
, objectPath.c_str()
, interfaces.empty() ? nullptr : &names[0] );
, interfaces.empty() ? nullptr : names.data() );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal", -r);
}
@@ -582,7 +611,7 @@ void Connection::emitInterfacesRemovedSignal( const ObjectPath& objectPath
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv( bus_.get()
, objectPath.c_str()
, interfaces.empty() ? nullptr : &names[0] );
, interfaces.empty() ? nullptr : names.data() );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal", -r);
}
@@ -599,16 +628,16 @@ Slot Connection::registerSignalHandler( const char* sender
auto r = sdbus_->sd_bus_match_signal( bus_.get()
, &slot
, !*sender ? nullptr : sender
, !*objectPath ? nullptr : objectPath
, !*interfaceName ? nullptr : interfaceName
, !*signalName ? nullptr : signalName
, *sender == '\0' ? nullptr : sender
, *objectPath == '\0' ? nullptr : objectPath
, *interfaceName == '\0' ? nullptr : interfaceName
, *signalName == '\0' ? nullptr : signalName
, callback
, userData );
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
}
sd_bus_message* Connection::incrementMessageRefCount(sd_bus_message* sdbusMsg)
@@ -646,7 +675,7 @@ sd_bus_message* Connection::callMethod(sd_bus_message* sdbusMsg, uint64_t timeou
sd_bus_message* sdbusReply{};
auto r = sdbus_->sd_bus_call(nullptr, sdbusMsg, timeout, &sdbusError, &sdbusReply);
if (sd_bus_error_is_set(&sdbusError))
if (sd_bus_error_is_set(&sdbusError) != 0)
throw Error(Error::Name{sdbusError.name}, sdbusError.message);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
@@ -664,7 +693,7 @@ Slot Connection::callMethodAsync(sd_bus_message* sdbusMsg, sd_bus_message_handle
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
auto timeoutBefore = getEventLoopPollData().timeout;
auto r = sdbus_->sd_bus_call_async(nullptr, &slot, sdbusMsg, (sd_bus_message_handler_t)callback, userData, timeout);
auto r = sdbus_->sd_bus_call_async(nullptr, &slot, sdbusMsg, callback, userData, timeout);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
auto timeoutAfter = getEventLoopPollData().timeout;
@@ -674,7 +703,7 @@ Slot Connection::callMethodAsync(sd_bus_message* sdbusMsg, sd_bus_message_handle
if (timeoutAfter < timeoutBefore || arePendingMessagesInQueues())
notifyEventLoopToWakeUpFromPoll();
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
}
void Connection::sendMessage(sd_bus_message* sdbusMsg)
@@ -713,7 +742,7 @@ sd_bus_message* Connection::createErrorReplyMessage(sd_bus_message* sdbusMsg, co
Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
{
sd_bus* bus{};
int r = busFactory(&bus);
const int r = busFactory(&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
BusPtr busPtr{bus, [this](sd_bus* bus){ return sdbus_->sd_bus_flush_close_unref(bus); }};
@@ -725,7 +754,7 @@ Connection::BusPtr Connection::openPseudoBus()
{
sd_bus* bus{};
int r = sdbus_->sd_bus_new(&bus);
const int r = sdbus_->sd_bus_new(&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open pseudo bus", -r);
(void)sdbus_->sd_bus_start(bus);
@@ -783,10 +812,10 @@ void Connection::joinWithEventLoop()
bool Connection::processPendingEvent()
{
auto bus = bus_.get();
auto *bus = bus_.get();
assert(bus != nullptr);
int r = sdbus_->sd_bus_process(bus, nullptr);
const int r = sdbus_->sd_bus_process(bus, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
// In correct use of sdbus-c++ API, r can be 0 only when processPendingEvent()
@@ -798,7 +827,7 @@ bool Connection::processPendingEvent()
return r > 0;
}
bool Connection::waitForNextEvent()
bool Connection::waitForNextEvent() // NOLINT(misc-no-recursion)
{
assert(bus_ != nullptr);
assert(loopExitFd_.fd >= 0);
@@ -821,7 +850,7 @@ bool Connection::waitForNextEvent()
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
// Wake up notification, in order that we re-enter poll with freshly read PollData (namely, new poll timeout thereof)
if (fds[1].revents & POLLIN)
if (fds[1].revents & POLLIN) // NOLINT(readability-implicit-bool-conversion)
{
auto cleared = eventFd_.clear();
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the event descriptor", -errno);
@@ -829,7 +858,7 @@ bool Connection::waitForNextEvent()
return waitForNextEvent();
}
// Loop exit notification
if (fds[2].revents & POLLIN)
if (fds[2].revents & POLLIN) // NOLINT(readability-implicit-bool-conversion)
{
auto cleared = loopExitFd_.clear();
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the loop exit descriptor", -errno);
@@ -854,6 +883,8 @@ Message Connection::getCurrentlyProcessedMessage() const
{
auto* sdbusMsg = sdbus_->sd_bus_get_current_message(bus_.get());
// TODO: const_cast..? Finish the const correctness design
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return Message::Factory::create<Message>(sdbusMsg, const_cast<Connection*>(this));
}
@@ -861,8 +892,9 @@ template <typename StringBasedType>
std::vector</*const */char*> Connection::to_strv(const std::vector<StringBasedType>& strings)
{
std::vector</*const */char*> strv;
strv.reserve(strings.size());
for (auto& str : strings)
strv.push_back(const_cast<char*>(str.c_str()));
strv.push_back(const_cast<char*>(str.c_str())); // NOLINT(cppcoreguidelines-pro-type-const-cast)
strv.push_back(nullptr);
return strv;
}
@@ -894,8 +926,8 @@ int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void
}
Connection::EventFd::EventFd()
: fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
{
fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
SDBUS_THROW_ERROR_IF(fd < 0, "Failed to create event object", -errno);
}
@@ -905,14 +937,14 @@ Connection::EventFd::~EventFd()
close(fd);
}
void Connection::EventFd::notify()
void Connection::EventFd::notify() // NOLINT(readability-make-member-function-const)
{
assert(fd >= 0);
auto r = eventfd_write(fd, 1);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify event descriptor", -errno);
}
bool Connection::EventFd::clear()
bool Connection::EventFd::clear() // NOLINT(readability-make-member-function-const)
{
assert(fd >= 0);
@@ -933,10 +965,10 @@ std::chrono::microseconds IConnection::PollData::getRelativeTimeout() const
if (timeout == zero)
return zero;
else if (timeout == max)
if (timeout == max)
return max;
else
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
}
int IConnection::PollData::getPollTimeout() const
@@ -945,18 +977,18 @@ int IConnection::PollData::getPollTimeout() const
if (relativeTimeout == decltype(relativeTimeout)::max())
return -1;
else
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
}
} // namespace sdbus
namespace sdbus::internal {
std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection()
std::unique_ptr<IConnection> createPseudoConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::pseudo_bus);
auto interface = std::make_unique<SdBus>();
return std::make_unique<Connection>(std::move(interface), Connection::pseudo_bus);
}
} // namespace sdbus::internal
@@ -965,81 +997,81 @@ namespace sdbus {
using internal::Connection;
std::unique_ptr<sdbus::IConnection> createBusConnection()
std::unique_ptr<IConnection> createBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::default_bus);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::default_bus);
}
std::unique_ptr<sdbus::IConnection> createBusConnection(const ServiceName& name)
std::unique_ptr<IConnection> createBusConnection(const ServiceName& name)
{
auto conn = createBusConnection();
conn->requestName(name);
return conn;
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
std::unique_ptr<IConnection> createSystemBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::system_bus);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::system_bus);
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const ServiceName& name)
std::unique_ptr<IConnection> createSystemBusConnection(const ServiceName& name)
{
auto conn = createSystemBusConnection();
conn->requestName(name);
return conn;
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
std::unique_ptr<IConnection> createSessionBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::session_bus);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::session_bus);
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const ServiceName& name)
std::unique_ptr<IConnection> createSessionBusConnection(const ServiceName& name)
{
auto conn = createSessionBusConnection();
conn->requestName(name);
return conn;
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string &address)
std::unique_ptr<IConnection> createSessionBusConnectionWithAddress(const std::string &address)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::custom_session_bus, address);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::custom_session_bus, address);
}
std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host)
std::unique_ptr<IConnection> createRemoteSystemBusConnection(const std::string& host)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::remote_system_bus, host);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::remote_system_bus, host);
}
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address)
std::unique_ptr<IConnection> createDirectBusConnection(const std::string& address)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, address);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::private_bus, address);
}
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd)
std::unique_ptr<IConnection> createDirectBusConnection(int fd)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, fd);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::private_bus, fd);
}
std::unique_ptr<sdbus::IConnection> createServerBus(int fd)
std::unique_ptr<IConnection> createServerBus(int fd)
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::server_bus, fd);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::server_bus, fd);
}
std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus)
std::unique_ptr<IConnection> createBusConnection(sd_bus *bus)
{
SDBUS_THROW_ERROR_IF(bus == nullptr, "Invalid bus argument", EINVAL);
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::sdbus_bus, bus);
auto interface = std::make_unique<internal::SdBus>();
return std::make_unique<internal::Connection>(std::move(interface), Connection::sdbus_bus, bus);
}
} // namespace sdbus
+29 -23
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Connection.h
*
@@ -33,7 +33,6 @@
#include "IConnection.h"
#include "ISdBus.h"
#include "ScopeGuard.h"
#include <memory>
#include <string>
@@ -52,33 +51,33 @@ namespace sdbus {
using MethodName = MemberName;
using SignalName = MemberName;
using PropertyName = MemberName;
}
} // namespace sdbus
namespace sdbus::internal {
class Connection final
: public sdbus::internal::IConnection
: public IConnection
{
public:
// Bus type tags
struct default_bus_t{};
inline static constexpr default_bus_t default_bus{};
static constexpr default_bus_t default_bus{};
struct system_bus_t{};
inline static constexpr system_bus_t system_bus{};
static constexpr system_bus_t system_bus{};
struct session_bus_t{};
inline static constexpr session_bus_t session_bus{};
static constexpr session_bus_t session_bus{};
struct custom_session_bus_t{};
inline static constexpr custom_session_bus_t custom_session_bus{};
static constexpr custom_session_bus_t custom_session_bus{};
struct remote_system_bus_t{};
inline static constexpr remote_system_bus_t remote_system_bus{};
static constexpr remote_system_bus_t remote_system_bus{};
struct private_bus_t{};
inline static constexpr private_bus_t private_bus{};
static constexpr private_bus_t private_bus{};
struct server_bus_t{};
inline static constexpr server_bus_t server_bus{};
static constexpr server_bus_t server_bus{};
struct sdbus_bus_t{}; // A bus connection created directly from existing sd_bus instance
inline static constexpr sdbus_bus_t sdbus_bus{};
static constexpr sdbus_bus_t sdbus_bus{};
struct pseudo_bus_t{}; // A bus connection that is not really established with D-Bus daemon
inline static constexpr pseudo_bus_t pseudo_bus{};
static constexpr pseudo_bus_t pseudo_bus{};
Connection(std::unique_ptr<ISdBus>&& interface, default_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, system_bus_t);
@@ -90,6 +89,10 @@ namespace sdbus::internal {
Connection(std::unique_ptr<ISdBus>&& interface, server_bus_t, int fd);
Connection(std::unique_ptr<ISdBus>&& interface, sdbus_bus_t, sd_bus *bus);
Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t);
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
Connection(Connection&&) = delete;
Connection& operator=(Connection&&) = delete;
~Connection() override;
void requestName(const ServiceName & name) override;
@@ -200,23 +203,27 @@ namespace sdbus::internal {
static int sdbus_match_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_match_install_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
private:
#ifndef SDBUS_basu // sd_event integration is not supported if instead of libsystemd we are based on basu
Slot createSdEventSlot(sd_event *event);
static Slot createSdEventSlot(sd_event *event);
Slot createSdTimeEventSourceSlot(sd_event *event, int priority);
Slot createSdIoEventSourceSlot(sd_event *event, int fd, int priority);
Slot createSdInternalEventSourceSlot(sd_event *event, int fd, int priority);
static void deleteSdEventSource(sd_event_source *s);
static void deleteSdEventSource(sd_event_source *source);
static int onSdTimerEvent(sd_event_source *s, uint64_t usec, void *userdata);
static int onSdIoEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata);
static int onSdInternalEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata);
static int onSdEventPrepare(sd_event_source *s, void *userdata);
static int onSdTimerEvent(sd_event_source *source, uint64_t usec, void *userdata);
static int onSdIoEvent(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int onSdInternalEvent(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int onSdEventPrepare(sd_event_source *source, void *userdata);
#endif
struct EventFd
{
EventFd();
EventFd(const EventFd&) = delete;
EventFd& operator=(const EventFd&) = delete;
EventFd(EventFd&&) = delete;
EventFd& operator=(EventFd&&) = delete;
~EventFd();
void notify();
bool clear();
@@ -228,7 +235,7 @@ namespace sdbus::internal {
{
message_handler callback;
message_handler installCallback;
Connection& connection;
Connection& connection; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
Slot slot;
};
@@ -241,7 +248,6 @@ namespace sdbus::internal {
Slot sdInternalEventSource;
};
private:
std::unique_ptr<ISdBus> sdbus_;
BusPtr bus_;
std::thread asyncLoopThread_;
@@ -251,6 +257,6 @@ namespace sdbus::internal {
std::unique_ptr<SdEvent> sdEvent_; // Integration of systemd sd-event event loop implementation
};
}
} // namespace sdbus::internal
#endif /* SDBUS_CXX_INTERNAL_CONNECTION_H_ */
+5 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Error.cpp
*
@@ -29,6 +29,8 @@
#include "ScopeGuard.h"
#include SDBUS_HEADER
#include <string>
#include <utility>
namespace sdbus
{
@@ -38,7 +40,7 @@ namespace sdbus
sd_bus_error_set_errno(&sdbusError, errNo);
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
Error::Name name(sd_bus_error_is_set(&sdbusError) ? sdbusError.name : "");
Error::Name name(sd_bus_error_is_set(&sdbusError) != 0 ? sdbusError.name : "");
std::string message(std::move(customMsg));
if (!message.empty() && sdbusError.message != nullptr)
{
@@ -51,6 +53,6 @@ namespace sdbus
message = sdbusError.message;
}
return Error(std::move(name), std::move(message));
return {std::move(name), std::move(message)};
}
} // namespace sdbus
+3 -7
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Flags.cpp
*
@@ -26,6 +26,7 @@
#include <sdbus-c++/Flags.h>
#include SDBUS_HEADER
#include <cstdint>
namespace sdbus
{
@@ -33,7 +34,6 @@ namespace sdbus
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
if (!flags_.test(Flags::PRIVILEGED))
@@ -55,7 +55,6 @@ namespace sdbus
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
if (!flags_.test(Flags::PRIVILEGED))
@@ -70,7 +69,6 @@ namespace sdbus
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
@@ -81,7 +79,6 @@ namespace sdbus
{
uint64_t sdbusFlags{};
using namespace sdbus;
if (flags_.test(Flags::DEPRECATED))
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
//if (!flags_.test(Flags::PRIVILEGED))
@@ -103,10 +100,9 @@ namespace sdbus
{
auto sdbusFlags = toSdBusPropertyFlags();
using namespace sdbus;
if (!flags_.test(Flags::PRIVILEGED))
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
return sdbusFlags;
}
}
} // namespace sdbus
+5 -7
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file IConnection.h
*
@@ -31,9 +31,7 @@
#include "sdbus-c++/TypeTraits.h"
#include <functional>
#include <memory>
#include <string>
#include SDBUS_HEADER
#include <vector>
@@ -54,8 +52,8 @@ namespace sdbus {
class Error;
namespace internal {
class ISdBus;
}
}
} // namespace internal
} // namespace sdbus
namespace sdbus::internal {
@@ -128,8 +126,8 @@ namespace sdbus::internal {
virtual sd_bus_message* createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error) = 0;
};
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection();
[[nodiscard]] std::unique_ptr<IConnection> createPseudoConnection();
}
} // namespace sdbus::internal
#endif /* SDBUS_CXX_INTERNAL_ICONNECTION_H_ */
+24 -24
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ISdBus.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -44,18 +44,18 @@ namespace sdbus::internal {
virtual ~ISdBus() = default;
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) = 0;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *msg) = 0;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *msg) = 0;
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) = 0;
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) = 0;
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) = 0;
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *msg, uint64_t *cookie) = 0;
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *msg, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) = 0;
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *msg, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) = 0;
virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) = 0;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) = 0;
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) = 0;
virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **msg, uint8_t type) = 0;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **msg, const char *destination, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **msg, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **msg) = 0;
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **msg, const sd_bus_error *err) = 0;
virtual int sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec) = 0;
virtual int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) = 0;
@@ -87,7 +87,7 @@ namespace sdbus::internal {
virtual int sd_bus_new(sd_bus **ret) = 0;
virtual int sd_bus_start(sd_bus *bus) = 0;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **ret) = 0;
virtual sd_bus_message* sd_bus_get_current_message(sd_bus *bus) = 0;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) = 0;
virtual int sd_bus_get_n_queued(sd_bus *bus, uint64_t *read, uint64_t* write) = 0;
@@ -95,21 +95,21 @@ namespace sdbus::internal {
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) = 0;
virtual sd_bus *sd_bus_close_unref(sd_bus *bus) = 0;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) = 0;
virtual int sd_bus_message_set_destination(sd_bus_message *msg, const char *destination) = 0;
virtual int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) = 0;
virtual sd_bus_creds* sd_bus_creds_ref(sd_bus_creds *c) = 0;
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) = 0;
virtual int sd_bus_query_sender_creds(sd_bus_message *msg, uint64_t mask, sd_bus_creds **creds) = 0;
virtual sd_bus_creds* sd_bus_creds_ref(sd_bus_creds *creds) = 0;
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *creds) = 0;
virtual int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) = 0;
virtual int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) = 0;
virtual int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *uid) = 0;
virtual int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) = 0;
virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) = 0;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) = 0;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) = 0;
virtual int sd_bus_creds_get_pid(sd_bus_creds *creds, pid_t *pid) = 0;
virtual int sd_bus_creds_get_uid(sd_bus_creds *creds, uid_t *uid) = 0;
virtual int sd_bus_creds_get_euid(sd_bus_creds *creds, uid_t *uid) = 0;
virtual int sd_bus_creds_get_gid(sd_bus_creds *creds, gid_t *gid) = 0;
virtual int sd_bus_creds_get_egid(sd_bus_creds *creds, gid_t *egid) = 0;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *creds, const gid_t **gids) = 0;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *creds, const char **label) = 0;
};
}
} // namespace sdbus::internal
#endif //SDBUS_CXX_ISDBUS_H
+148 -111
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Message.cpp
*
@@ -28,13 +28,25 @@
#include "sdbus-c++/Error.h"
#include "sdbus-c++/Types.h"
#include "sdbus-c++/TypeTraits.h"
#include "IConnection.h"
#include "MessageUtils.h"
#include "ScopeGuard.h"
#include <cassert>
#include <cerrno>
#include <cstdint> // int16_t, uint64_t, ...
#include <cstdio>
#include <cstdlib> // atexit
#include <cstring>
#include <string>
#include <string_view>
#include <sys/types.h> // pid_t, gid_t, ...
#include <tuple> // std::ignore
#include <memory> // std::unique_ptr
#include <utility> // std::move
#include <vector>
#include SDBUS_HEADER
namespace sdbus {
@@ -51,7 +63,7 @@ Message::Message(void *msg, internal::IConnection* connection) noexcept
{
assert(msg_ != nullptr);
assert(connection_ != nullptr);
connection_->incrementMessageRefCount((sd_bus_message*)msg_);
connection_->incrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
}
Message::Message(void *msg, internal::IConnection* connection, adopt_message_t) noexcept
@@ -69,14 +81,17 @@ Message::Message(const Message& other) noexcept
Message& Message::operator=(const Message& other) noexcept
{
if (this == &other)
return *this;
if (msg_)
connection_->decrementMessageRefCount((sd_bus_message*)msg_);
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
msg_ = other.msg_;
connection_ = other.connection_;
ok_ = other.ok_;
connection_->incrementMessageRefCount((sd_bus_message*)msg_);
connection_->incrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
return *this;
}
@@ -89,7 +104,7 @@ Message::Message(Message&& other) noexcept
Message& Message::operator=(Message&& other) noexcept
{
if (msg_)
connection_->decrementMessageRefCount((sd_bus_message*)msg_);
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
msg_ = other.msg_;
other.msg_ = nullptr;
@@ -104,18 +119,18 @@ Message& Message::operator=(Message&& other) noexcept
Message::~Message()
{
if (msg_)
connection_->decrementMessageRefCount((sd_bus_message*)msg_);
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
}
Message& Message::operator<<(bool item)
{
int intItem = item;
int itemAsInt = static_cast<int>(item);
// Direct sd-bus method, bypassing SdBus mutex, are called here, since Message serialization/deserialization,
// as well as getter/setter methods are not thread safe by design. Additionally, they are called frequently,
// so some overhead is spared. What is thread-safe in Message class is Message constructors, copy/move operations
// and the destructor, so the Message instance can be passed from one thread to another safely.
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BOOLEAN, &itemAsInt);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a bool value", -r);
return *this;
@@ -123,7 +138,7 @@ Message& Message::operator<<(bool item)
Message& Message::operator<<(int16_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT16, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int16_t value", -r);
return *this;
@@ -131,7 +146,7 @@ Message& Message::operator<<(int16_t item)
Message& Message::operator<<(int32_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT32, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int32_t value", -r);
return *this;
@@ -139,7 +154,7 @@ Message& Message::operator<<(int32_t item)
Message& Message::operator<<(int64_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT64, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int64_t value", -r);
return *this;
@@ -147,7 +162,7 @@ Message& Message::operator<<(int64_t item)
Message& Message::operator<<(uint8_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BYTE, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a byte value", -r);
return *this;
@@ -155,7 +170,7 @@ Message& Message::operator<<(uint8_t item)
Message& Message::operator<<(uint16_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT16, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint16_t value", -r);
return *this;
@@ -163,7 +178,7 @@ Message& Message::operator<<(uint16_t item)
Message& Message::operator<<(uint32_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT32, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint32_t value", -r);
return *this;
@@ -171,7 +186,7 @@ Message& Message::operator<<(uint32_t item)
Message& Message::operator<<(uint64_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT64, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint64_t value", -r);
return *this;
@@ -179,7 +194,7 @@ Message& Message::operator<<(uint64_t item)
Message& Message::operator<<(double item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DOUBLE, &item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a double value", -r);
return *this;
@@ -187,7 +202,7 @@ Message& Message::operator<<(double item)
Message& Message::operator<<(const char* item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, item);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a C-string value", -r);
return *this;
@@ -195,7 +210,7 @@ Message& Message::operator<<(const char* item)
Message& Message::operator<<(const std::string& item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item.c_str());
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, item.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a string value", -r);
return *this;
@@ -204,7 +219,7 @@ Message& Message::operator<<(const std::string& item)
Message& Message::operator<<(std::string_view item)
{
char* destPtr{};
auto r = sd_bus_message_append_string_space((sd_bus_message*)msg_, item.length(), &destPtr);
auto r = sd_bus_message_append_string_space(static_cast<sd_bus_message*>(msg_), item.length(), &destPtr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a string_view value", -r);
std::memcpy(destPtr, item.data(), item.length());
@@ -221,7 +236,7 @@ Message& Message::operator<<(const Variant &item)
Message& Message::operator<<(const ObjectPath &item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, item.c_str());
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_OBJECT_PATH, item.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an ObjectPath value", -r);
return *this;
@@ -229,7 +244,7 @@ Message& Message::operator<<(const ObjectPath &item)
Message& Message::operator<<(const Signature &item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, item.c_str());
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_SIGNATURE, item.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a Signature value", -r);
return *this;
@@ -238,7 +253,7 @@ Message& Message::operator<<(const Signature &item)
Message& Message::operator<<(const UnixFd &item)
{
auto fd = item.get();
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UNIX_FD, &fd);
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UNIX_FD, &fd);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a UnixFd value", -r);
return *this;
@@ -246,7 +261,7 @@ Message& Message::operator<<(const UnixFd &item)
Message& Message::appendArray(char type, const void *ptr, size_t size)
{
auto r = sd_bus_message_append_array((sd_bus_message*)msg_, type, ptr, size);
auto r = sd_bus_message_append_array(static_cast<sd_bus_message*>(msg_), type, ptr, size);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an array", -r);
return *this;
@@ -254,8 +269,8 @@ Message& Message::appendArray(char type, const void *ptr, size_t size)
Message& Message::operator>>(bool& item)
{
int intItem;
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
int intItem{};
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BOOLEAN, &intItem);
if (r == 0)
ok_ = false;
@@ -268,7 +283,7 @@ Message& Message::operator>>(bool& item)
Message& Message::operator>>(int16_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT16, &item);
if (r == 0)
ok_ = false;
@@ -279,7 +294,7 @@ Message& Message::operator>>(int16_t& item)
Message& Message::operator>>(int32_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT32, &item);
if (r == 0)
ok_ = false;
@@ -290,7 +305,7 @@ Message& Message::operator>>(int32_t& item)
Message& Message::operator>>(int64_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT64, &item);
if (r == 0)
ok_ = false;
@@ -301,7 +316,7 @@ Message& Message::operator>>(int64_t& item)
Message& Message::operator>>(uint8_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BYTE, &item);
if (r == 0)
ok_ = false;
@@ -312,7 +327,7 @@ Message& Message::operator>>(uint8_t& item)
Message& Message::operator>>(uint16_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT16, &item);
if (r == 0)
ok_ = false;
@@ -323,7 +338,7 @@ Message& Message::operator>>(uint16_t& item)
Message& Message::operator>>(uint32_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT32, &item);
if (r == 0)
ok_ = false;
@@ -334,7 +349,7 @@ Message& Message::operator>>(uint32_t& item)
Message& Message::operator>>(uint64_t& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT64, &item);
if (r == 0)
ok_ = false;
@@ -345,7 +360,7 @@ Message& Message::operator>>(uint64_t& item)
Message& Message::readArray(char type, const void **ptr, size_t *size)
{
auto r = sd_bus_message_read_array((sd_bus_message*)msg_, type, ptr, size);
auto r = sd_bus_message_read_array(static_cast<sd_bus_message*>(msg_), type, ptr, size);
if (r == 0)
ok_ = false;
@@ -356,7 +371,7 @@ Message& Message::readArray(char type, const void **ptr, size_t *size)
Message& Message::operator>>(double& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DOUBLE, &item);
if (r == 0)
ok_ = false;
@@ -367,7 +382,7 @@ Message& Message::operator>>(double& item)
Message& Message::operator>>(char*& item)
{
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, &item);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, reinterpret_cast<void*>(&item));
if (r == 0)
ok_ = false;
@@ -403,7 +418,7 @@ Message& Message::operator>>(Variant &item)
Message& Message::operator>>(ObjectPath &item)
{
char* str{};
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, &str);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_OBJECT_PATH, reinterpret_cast<void*>(&str));
if (r == 0)
ok_ = false;
@@ -418,7 +433,7 @@ Message& Message::operator>>(ObjectPath &item)
Message& Message::operator>>(Signature &item)
{
char* str{};
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, &str);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_SIGNATURE, reinterpret_cast<void*>(&str));
if (r == 0)
ok_ = false;
@@ -433,7 +448,7 @@ Message& Message::operator>>(Signature &item)
Message& Message::operator>>(UnixFd &item)
{
int fd = -1;
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UNIX_FD, &fd);
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UNIX_FD, &fd);
if (r == 0)
ok_ = false;
@@ -446,7 +461,7 @@ Message& Message::operator>>(UnixFd &item)
Message& Message::openContainer(const char* signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature);
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_ARRAY, signature);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a container", -r);
return *this;
@@ -454,7 +469,7 @@ Message& Message::openContainer(const char* signature)
Message& Message::closeContainer()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a container", -r);
return *this;
@@ -462,7 +477,7 @@ Message& Message::closeContainer()
Message& Message::openDictEntry(const char* signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature);
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DICT_ENTRY, signature);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a dictionary entry", -r);
return *this;
@@ -470,7 +485,7 @@ Message& Message::openDictEntry(const char* signature)
Message& Message::closeDictEntry()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a dictionary entry", -r);
return *this;
@@ -478,7 +493,7 @@ Message& Message::closeDictEntry()
Message& Message::openVariant(const char* signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature);
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_VARIANT, signature);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a variant", -r);
return *this;
@@ -486,7 +501,7 @@ Message& Message::openVariant(const char* signature)
Message& Message::closeVariant()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a variant", -r);
return *this;
@@ -494,7 +509,7 @@ Message& Message::closeVariant()
Message& Message::openStruct(const char* signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature);
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRUCT, signature);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a struct", -r);
return *this;
@@ -502,7 +517,7 @@ Message& Message::openStruct(const char* signature)
Message& Message::closeStruct()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a struct", -r);
return *this;
@@ -510,7 +525,7 @@ Message& Message::closeStruct()
Message& Message::enterContainer(const char* signature)
{
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature);
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_ARRAY, signature);
if (r == 0)
ok_ = false;
@@ -521,7 +536,7 @@ Message& Message::enterContainer(const char* signature)
Message& Message::exitContainer()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a container", -r);
return *this;
@@ -529,7 +544,7 @@ Message& Message::exitContainer()
Message& Message::enterDictEntry(const char* signature)
{
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature);
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DICT_ENTRY, signature);
if (r == 0)
ok_ = false;
@@ -540,7 +555,7 @@ Message& Message::enterDictEntry(const char* signature)
Message& Message::exitDictEntry()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a dictionary entry", -r);
return *this;
@@ -548,7 +563,7 @@ Message& Message::exitDictEntry()
Message& Message::enterVariant(const char* signature)
{
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature);
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_VARIANT, signature);
if (r == 0)
ok_ = false;
@@ -559,7 +574,7 @@ Message& Message::enterVariant(const char* signature)
Message& Message::exitVariant()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a variant", -r);
return *this;
@@ -567,7 +582,7 @@ Message& Message::exitVariant()
Message& Message::enterStruct(const char* signature)
{
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature);
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRUCT, signature);
if (r == 0)
ok_ = false;
@@ -578,7 +593,7 @@ Message& Message::enterStruct(const char* signature)
Message& Message::exitStruct()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a struct", -r);
return *this;
@@ -597,7 +612,7 @@ void Message::clearFlags()
void Message::copyTo(Message& destination, bool complete) const
{
auto r = sd_bus_message_copy((sd_bus_message*)destination.msg_, (sd_bus_message*)msg_, complete);
auto r = sd_bus_message_copy(static_cast<sd_bus_message*>(destination.msg_), static_cast<sd_bus_message*>(msg_), complete); // NOLINT(readability-implicit-bool-conversion)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to copy the message", -r);
}
@@ -605,45 +620,67 @@ void Message::seal()
{
const auto messageCookie = 1;
const auto sealTimeout = 0;
auto r = sd_bus_message_seal((sd_bus_message*)msg_, messageCookie, sealTimeout);
auto r = sd_bus_message_seal(static_cast<sd_bus_message*>(msg_), messageCookie, sealTimeout);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to seal the message", -r);
}
void Message::rewind(bool complete)
{
auto r = sd_bus_message_rewind((sd_bus_message*)msg_, complete);
auto r = sd_bus_message_rewind(static_cast<sd_bus_message*>(msg_), complete); // NOLINT(readability-implicit-bool-conversion)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
}
std::string Message::dumpToString(DumpFlags flags) const
{
#if LIBSYSTEMD_VERSION>=245 && !defined(SDBUS_basu)
char* buffer{};
SCOPE_EXIT{ free(buffer); }; // NOLINT(cppcoreguidelines-no-malloc,hicpp-no-malloc,cppcoreguidelines-owning-memory)
size_t size{};
const std::unique_ptr<FILE, int(*)(FILE*)> stream{open_memstream(&buffer, &size), fclose};
SDBUS_THROW_ERROR_IF(!stream, "Failed to open memory stream", errno);
auto r = sd_bus_message_dump(static_cast<sd_bus_message*>(msg_), stream.get(), static_cast<uint64_t>(flags));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to dump the message", -r);
(void)fflush(stream.get());
return {buffer, size};
#else
(void)flags;
throw Error(Error::Name{SD_BUS_ERROR_NOT_SUPPORTED}, "Dumping sd-bus message not supported by underlying version of libsystemd");
#endif
}
const char* Message::getInterfaceName() const
{
return sd_bus_message_get_interface((sd_bus_message*)msg_);
return sd_bus_message_get_interface(static_cast<sd_bus_message*>(msg_));
}
const char* Message::getMemberName() const
{
return sd_bus_message_get_member((sd_bus_message*)msg_);
return sd_bus_message_get_member(static_cast<sd_bus_message*>(msg_));
}
const char* Message::getSender() const
{
return sd_bus_message_get_sender((sd_bus_message*)msg_);
return sd_bus_message_get_sender(static_cast<sd_bus_message*>(msg_));
}
const char* Message::getPath() const
{
return sd_bus_message_get_path((sd_bus_message*)msg_);
return sd_bus_message_get_path(static_cast<sd_bus_message*>(msg_));
}
const char* Message::getDestination() const
{
return sd_bus_message_get_destination((sd_bus_message*)msg_);
return sd_bus_message_get_destination(static_cast<sd_bus_message*>(msg_));
}
uint64_t Message::getCookie() const
{
uint64_t cookie;
auto r = sd_bus_message_get_cookie((sd_bus_message*)msg_, &cookie);
uint64_t cookie{};
auto r = sd_bus_message_get_cookie(static_cast<sd_bus_message*>(msg_), &cookie);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get cookie", -r);
return cookie;
}
@@ -652,7 +689,7 @@ std::pair<char, const char*> Message::peekType() const
{
char typeSignature{};
const char* contentsSignature{};
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSignature, &contentsSignature);
auto r = sd_bus_message_peek_type(static_cast<sd_bus_message*>(msg_), &typeSignature, &contentsSignature);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
return {typeSignature, contentsSignature};
}
@@ -664,12 +701,12 @@ bool Message::isValid() const
bool Message::isEmpty() const
{
return sd_bus_message_is_empty((sd_bus_message*)msg_) != 0;
return sd_bus_message_is_empty(static_cast<sd_bus_message*>(msg_)) != 0;
}
bool Message::isAtEnd(bool complete) const
{
return sd_bus_message_at_end((sd_bus_message*)msg_, complete) > 0;
return sd_bus_message_at_end(static_cast<sd_bus_message*>(msg_), complete) > 0; // NOLINT(readability-implicit-bool-conversion)
}
// TODO: Create a RAII ownership class for creds with copy&move semantics, doing ref()/unref() under the hood.
@@ -677,11 +714,11 @@ bool Message::isAtEnd(bool complete) const
// The class will expose methods like getPid(), getUid(), etc. that will directly call sd_bus_creds_* functions, no need for mutex here.
pid_t Message::getCredsPid() const
{
uint64_t mask = SD_BUS_CREDS_PID | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_PID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
pid_t pid = 0;
@@ -692,13 +729,13 @@ pid_t Message::getCredsPid() const
uid_t Message::getCredsUid() const
{
uint64_t mask = SD_BUS_CREDS_UID | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_UID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
uid_t uid = (uid_t)-1;
auto uid = static_cast<uid_t>(-1);
r = sd_bus_creds_get_uid(creds, &uid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred uid", -r);
return uid;
@@ -706,13 +743,13 @@ uid_t Message::getCredsUid() const
uid_t Message::getCredsEuid() const
{
uint64_t mask = SD_BUS_CREDS_EUID | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_EUID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
uid_t euid = (uid_t)-1;
auto euid = static_cast<uid_t>(-1);
r = sd_bus_creds_get_euid(creds, &euid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred euid", -r);
return euid;
@@ -720,13 +757,13 @@ uid_t Message::getCredsEuid() const
gid_t Message::getCredsGid() const
{
uint64_t mask = SD_BUS_CREDS_GID | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_GID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
gid_t gid = (gid_t)-1;
auto gid = static_cast<gid_t>(-1);
r = sd_bus_creds_get_gid(creds, &gid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred gid", -r);
return gid;
@@ -734,13 +771,13 @@ gid_t Message::getCredsGid() const
gid_t Message::getCredsEgid() const
{
uint64_t mask = SD_BUS_CREDS_EGID | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_EGID | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
gid_t egid = (gid_t)-1;
auto egid = static_cast<gid_t>(-1);
r = sd_bus_creds_get_egid(creds, &egid);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred egid", -r);
return egid;
@@ -748,10 +785,10 @@ gid_t Message::getCredsEgid() const
std::vector<gid_t> Message::getCredsSupplementaryGids() const
{
uint64_t mask = SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_AUGMENT;
const uint64_t mask = SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_AUGMENT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
const gid_t *cGids = nullptr;
@@ -762,7 +799,7 @@ std::vector<gid_t> Message::getCredsSupplementaryGids() const
if (cGids != nullptr)
{
for (int i = 0; i < r; i++)
gids.push_back(cGids[i]);
gids.push_back(cGids[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
return gids;
@@ -770,10 +807,10 @@ std::vector<gid_t> Message::getCredsSupplementaryGids() const
std::string Message::getSELinuxContext() const
{
uint64_t mask = SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_SELINUX_CONTEXT;
const uint64_t mask = SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_SELINUX_CONTEXT;
sd_bus_creds *creds = nullptr;
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
int r = connection_->querySenderCredentials((sd_bus_message*)msg_, mask, &creds);
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
const char *cLabel = nullptr;
@@ -792,13 +829,13 @@ MethodCall::MethodCall( void *msg
void MethodCall::dontExpectReply()
{
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)msg_, 0);
auto r = sd_bus_message_set_expect_reply(static_cast<sd_bus_message*>(msg_), 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
}
bool MethodCall::doesntExpectReply() const
{
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)msg_);
auto r = sd_bus_message_get_expect_reply(static_cast<sd_bus_message*>(msg_));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
return r == 0;
}
@@ -807,69 +844,69 @@ MethodReply MethodCall::send(uint64_t timeout) const
{
if (!doesntExpectReply())
return sendWithReply(timeout);
else
return sendWithNoReply();
return sendWithNoReply();
}
MethodReply MethodCall::sendWithReply(uint64_t timeout) const
{
auto* sdbusReply = connection_->callMethod((sd_bus_message*)msg_, timeout);
auto* sdbusReply = connection_->callMethod(static_cast<sd_bus_message*>(msg_), timeout);
return Factory::create<MethodReply>(sdbusReply, connection_, adopt_message);
}
MethodReply MethodCall::sendWithNoReply() const
{
connection_->sendMessage((sd_bus_message*)msg_);
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
return Factory::create<MethodReply>(); // No reply
}
Slot MethodCall::send(void* callback, void* userData, uint64_t timeout, return_slot_t) const
Slot MethodCall::send(void* callback, void* userData, uint64_t timeout, return_slot_t) const // NOLINT(bugprone-easily-swappable-parameters)
{
return connection_->callMethodAsync((sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, timeout, return_slot);
return connection_->callMethodAsync(static_cast<sd_bus_message*>(msg_), reinterpret_cast<sd_bus_message_handler_t>(callback), userData, timeout, return_slot);
}
MethodReply MethodCall::createReply() const
{
auto* sdbusReply = connection_->createMethodReply((sd_bus_message*)msg_);
auto* sdbusReply = connection_->createMethodReply(static_cast<sd_bus_message*>(msg_));
return Factory::create<MethodReply>(sdbusReply, connection_, adopt_message);
}
MethodReply MethodCall::createErrorReply(const Error& error) const
{
sd_bus_message* sdbusErrorReply = connection_->createErrorReplyMessage((sd_bus_message*)msg_, error);
sd_bus_message* sdbusErrorReply = connection_->createErrorReplyMessage(static_cast<sd_bus_message*>(msg_), error);
return Factory::create<MethodReply>(sdbusErrorReply, connection_, adopt_message);
}
void MethodReply::send() const
{
connection_->sendMessage((sd_bus_message*)msg_);
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
}
uint64_t MethodReply::getReplyCookie() const
{
uint64_t cookie;
auto r = sd_bus_message_get_reply_cookie((sd_bus_message*)msg_, &cookie);
uint64_t cookie{};
auto r = sd_bus_message_get_reply_cookie(static_cast<sd_bus_message*>(msg_), &cookie);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get cookie", -r);
return cookie;
}
void Signal::send() const
{
connection_->sendMessage((sd_bus_message*)msg_);
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
}
void Signal::setDestination(const std::string& destination)
{
return setDestination(destination.c_str());
setDestination(destination.c_str());
}
void Signal::setDestination(const char* destination)
{
auto r = sd_bus_message_set_destination((sd_bus_message*)msg_, destination);
auto r = sd_bus_message_set_destination(static_cast<sd_bus_message*>(msg_), destination);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
}
@@ -886,30 +923,30 @@ namespace {
// Another common solution is global sdbus-c++ startup/shutdown functions, but that would be an intrusive change.
#ifdef __cpp_constinit
constinit static bool pseudoConnectionDestroyed{};
constinit bool pseudoConnectionDestroyed{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#else
static bool pseudoConnectionDestroyed{};
bool pseudoConnectionDestroyed{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#endif
std::unique_ptr<sdbus::internal::IConnection, void(*)(sdbus::internal::IConnection*)> createPseudoConnection()
std::unique_ptr<internal::IConnection, void(*)(internal::IConnection*)> createPseudoConnection()
{
auto deleter = [](sdbus::internal::IConnection* con)
auto deleter = [](internal::IConnection* con)
{
delete con;
delete con; // NOLINT(cppcoreguidelines-owning-memory)
pseudoConnectionDestroyed = true;
};
return {internal::createPseudoConnection().release(), std::move(deleter)};
}
sdbus::internal::IConnection& getPseudoConnectionInstance()
internal::IConnection& getPseudoConnectionInstance()
{
static auto connection = createPseudoConnection();
if (pseudoConnectionDestroyed)
{
connection = createPseudoConnection(); // Phoenix rising from the ashes
atexit([](){ connection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
std::ignore = atexit([](){ connection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
pseudoConnectionDestroyed = false;
}
@@ -918,7 +955,7 @@ sdbus::internal::IConnection& getPseudoConnectionInstance()
return *connection;
}
}
} // namespace
PlainMessage createPlainMessage()
{
@@ -930,4 +967,4 @@ PlainMessage createPlainMessage()
return connection.createPlainMessage();
}
}
} // namespace sdbus
+14 -14
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file MessageUtils.h
*
@@ -34,30 +34,30 @@ namespace sdbus
class Message::Factory
{
public:
template<typename _Msg>
static _Msg create()
template<typename Msg>
static Msg create()
{
return _Msg{};
return Msg{};
}
template<typename _Msg>
static _Msg create(void *msg)
template<typename Msg>
static Msg create(void *msg)
{
return _Msg{msg};
return Msg{msg};
}
template<typename _Msg>
static _Msg create(void *msg, internal::IConnection* connection)
template<typename Msg>
static Msg create(void *msg, internal::IConnection* connection)
{
return _Msg{msg, connection};
return Msg{msg, connection};
}
template<typename _Msg>
static _Msg create(void *msg, internal::IConnection* connection, adopt_message_t)
template<typename Msg>
static Msg create(void *msg, internal::IConnection* connection, adopt_message_t)
{
return _Msg{msg, connection, adopt_message};
return Msg{msg, connection, adopt_message};
}
};
}
} // namespace sdbus
#endif /* SDBUS_CXX_INTERNAL_MESSAGEUTILS_H_ */
+22 -14
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Object.cpp
*
@@ -29,21 +29,29 @@
#include "sdbus-c++/Error.h"
#include "sdbus-c++/Flags.h"
#include "sdbus-c++/IConnection.h"
#include "sdbus-c++/IObject.h"
#include "sdbus-c++/Message.h"
#include "sdbus-c++/TypeTraits.h"
#include "sdbus-c++/VTableItems.h"
#include "IConnection.h"
#include "MessageUtils.h"
#include "ScopeGuard.h"
#include "Utils.h"
#include "VTableUtils.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <memory>
#include SDBUS_HEADER
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
namespace sdbus::internal {
Object::Object(sdbus::internal::IConnection& connection, ObjectPath objectPath)
Object::Object(IConnection& connection, ObjectPath objectPath)
: connection_(connection), objectPath_(std::move(objectPath))
{
SDBUS_CHECK_OBJECT_PATH(objectPath_.c_str());
@@ -69,12 +77,12 @@ Slot Object::addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtab
// 3rd step -- register the vtable with sd-bus
internalVTable->slot = connection_.addObjectVTable( objectPath_
, internalVTable->interfaceName
, &internalVTable->sdbusVTable[0]
, internalVTable->sdbusVTable.data()
, internalVTable.get()
, return_slot );
// Return vtable wrapped in a Slot object
return {internalVTable.release(), [](void *ptr){ delete static_cast<VTable*>(ptr); }};
return {internalVTable.release(), [](void *ptr){ delete static_cast<VTable*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
}
void Object::unregister()
@@ -93,7 +101,7 @@ Signal Object::createSignal(const char* interfaceName, const char* signalName) c
return connection_.createSignal(objectPath_.c_str(), interfaceName, signalName);
}
void Object::emitSignal(const sdbus::Signal& message)
void Object::emitSignal(const Signal& message)
{
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid signal message provided", EINVAL);
@@ -181,9 +189,9 @@ Object::VTable Object::createInternalVTable(InterfaceName interfaceName, std::ve
}
// Sort arrays so we can do fast searching for an item in sd-bus callback handlers
std::sort(internalVTable.methods.begin(), internalVTable.methods.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
std::sort(internalVTable.signals.begin(), internalVTable.signals.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
std::sort(internalVTable.properties.begin(), internalVTable.properties.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
std::sort(internalVTable.methods.begin(), internalVTable.methods.end(), [](const auto& lhs, const auto& rhs){ return lhs.name < rhs.name; });
std::sort(internalVTable.signals.begin(), internalVTable.signals.end(), [](const auto& lhs, const auto& rhs){ return lhs.name < rhs.name; });
std::sort(internalVTable.properties.begin(), internalVTable.properties.end(), [](const auto& lhs, const auto& rhs){ return lhs.name < rhs.name; });
internalVTable.object = this;
@@ -389,16 +397,16 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
return ok ? 1 : -1;
}
}
} // namespace sdbus::internal
namespace sdbus {
std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, ObjectPath objectPath)
std::unique_ptr<IObject> createObject(IConnection& connection, ObjectPath objectPath)
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(&connection);
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
return std::make_unique<sdbus::internal::Object>(*sdbusConnection, std::move(objectPath));
return std::make_unique<internal::Object>(*sdbusConnection, std::move(objectPath));
}
}
} // namespace sdbus
+19 -13
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Object.h
*
@@ -29,7 +29,6 @@
#include "sdbus-c++/IObject.h"
#include "IConnection.h"
#include "sdbus-c++/Types.h"
#include <cassert>
@@ -41,21 +40,29 @@
#include SDBUS_HEADER
#include <vector>
// Forward declarations
namespace sdbus {
class IConnection;
namespace internal {
class IConnection;
} // namespace internal
} // namespace sdbus
namespace sdbus::internal {
class Object
: public IObject
{
public:
Object(sdbus::internal::IConnection& connection, ObjectPath objectPath);
Object(IConnection& connection, ObjectPath objectPath);
void addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable) override;
Slot addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable, return_slot_t) override;
void unregister() override;
Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const override;
[[nodiscard]] Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const override;
Signal createSignal(const char* interfaceName, const char* signalName) const override;
void emitSignal(const sdbus::Signal& message) override;
void emitSignal(const Signal& message) override;
void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector<PropertyName>& propNames) override;
void emitPropertiesChangedSignal(const char* interfaceName, const std::vector<PropertyName>& propNames) override;
void emitPropertiesChangedSignal(const InterfaceName& interfaceName) override;
@@ -126,12 +133,12 @@ namespace sdbus::internal {
};
VTable createInternalVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable);
void writeInterfaceFlagsToVTable(InterfaceFlagsVTableItem flags, VTable& vtable);
void writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable);
void writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable);
void writePropertyRecordToVTable(PropertyVTableItem property, VTable& vtable);
static void writeInterfaceFlagsToVTable(InterfaceFlagsVTableItem flags, VTable& vtable);
static void writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable);
static void writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable);
static void writePropertyRecordToVTable(PropertyVTableItem property, VTable& vtable);
std::vector<sd_bus_vtable> createInternalSdBusVTable(const VTable& vtable);
static std::vector<sd_bus_vtable> createInternalSdBusVTable(const VTable& vtable);
static void startSdBusVTable(const Flags& interfaceFlags, std::vector<sd_bus_vtable>& vtable);
static void writeMethodRecordToSdBusVTable(const VTable::MethodItem& method, std::vector<sd_bus_vtable>& vtable);
static void writeSignalRecordToSdBusVTable(const VTable::SignalItem& signal, std::vector<sd_bus_vtable>& vtable);
@@ -159,13 +166,12 @@ namespace sdbus::internal {
, void *userData
, sd_bus_error *retError );
private:
sdbus::internal::IConnection& connection_;
IConnection& connection_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
ObjectPath objectPath_;
std::vector<Slot> vtables_;
Slot objectManagerSlot_;
};
}
} // namespace sdbus::internal
#endif /* SDBUS_CXX_INTERNAL_OBJECT_H_ */
+91 -55
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Proxy.cpp
*
@@ -28,22 +28,33 @@
#include "sdbus-c++/Error.h"
#include "sdbus-c++/IConnection.h"
#include "sdbus-c++/IProxy.h"
#include "sdbus-c++/Message.h"
#include "sdbus-c++/TypeTraits.h"
#include "IConnection.h"
#include "MessageUtils.h"
#include "ScopeGuard.h"
#include "Utils.h"
#include <algorithm>
#include <atomic>
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include <exception>
#include <future>
#include <memory>
#include <mutex>
#include <optional>
#include SDBUS_HEADER
#include <utility>
namespace sdbus::internal {
Proxy::Proxy(sdbus::internal::IConnection& connection, ServiceName destination, ObjectPath objectPath)
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
Proxy::Proxy(IConnection& connection, ServiceName destination, ObjectPath objectPath)
: connection_(&connection, [](IConnection *){ /* Intentionally left empty */ })
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
@@ -54,7 +65,7 @@ Proxy::Proxy(sdbus::internal::IConnection& connection, ServiceName destination,
// it here, so we expect the client to manage the event loop upon this connection themselves.
}
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
Proxy::Proxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath )
: connection_(std::move(connection))
@@ -69,7 +80,7 @@ Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
connection_->enterEventLoopAsync();
}
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
Proxy::Proxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t )
@@ -122,15 +133,16 @@ PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_h
auto asyncCallInfo = std::make_shared<AsyncCallInfo>(AsyncCallInfo{ .callback = std::move(asyncReplyCallback)
, .proxy = *this
, .slot = {}
, .floating = false });
asyncCallInfo->slot = message.send((void*)&Proxy::sdbus_async_reply_handler, asyncCallInfo.get(), timeout, return_slot);
asyncCallInfo->slot = message.send(reinterpret_cast<void*>(&Proxy::sdbus_async_reply_handler), asyncCallInfo.get(), timeout, return_slot);
auto asyncCallInfoWeakPtr = std::weak_ptr{asyncCallInfo};
floatingAsyncCallSlots_.push_back(std::move(asyncCallInfo));
return {asyncCallInfoWeakPtr};
return PendingAsyncCall{asyncCallInfoWeakPtr};
}
Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout, return_slot_t)
@@ -139,11 +151,12 @@ Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler async
auto asyncCallInfo = std::make_unique<AsyncCallInfo>(AsyncCallInfo{ .callback = std::move(asyncReplyCallback)
, .proxy = *this
, .slot = {}
, .floating = true });
asyncCallInfo->slot = message.send((void*)&Proxy::sdbus_async_reply_handler, asyncCallInfo.get(), timeout, return_slot);
asyncCallInfo->slot = message.send(reinterpret_cast<void*>(&Proxy::sdbus_async_reply_handler), asyncCallInfo.get(), timeout, return_slot);
return {asyncCallInfo.release(), [](void *ptr){ delete static_cast<AsyncCallInfo*>(ptr); }};
return {asyncCallInfo.release(), [](void *ptr){ delete static_cast<AsyncCallInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
}
std::future<MethodReply> Proxy::callMethodAsync(const MethodCall& message, with_future_t)
@@ -169,6 +182,31 @@ std::future<MethodReply> Proxy::callMethodAsync(const MethodCall& message, uint6
return future;
}
Awaitable<MethodReply> Proxy::callMethodAsync(const MethodCall& message, with_awaitable_t)
{
return Proxy::callMethodAsync(message, /*timeout*/ 0, with_awaitable);
}
Awaitable<MethodReply> Proxy::callMethodAsync(const MethodCall& message, uint64_t timeout, with_awaitable_t)
{
auto data = std::make_shared<AwaitableData<MethodReply>>();
async_reply_handler asyncReplyCallback = [data](MethodReply reply, std::optional<Error> error) noexcept
{
if (!error)
data->result = std::move(reply);
else
data->result = std::make_exception_ptr(*std::move(error));
auto previous = data->status.exchange(AwaitableState::Completed, std::memory_order_acq_rel);
if (previous == AwaitableState::Waiting)
data->resumeCoroutine();
};
(void)Proxy::callMethodAsync(message, std::move(asyncReplyCallback), timeout);
return Awaitable{data};
}
void Proxy::registerSignalHandler( const InterfaceName& interfaceName
, const SignalName& signalName
, signal_handler signalHandler )
@@ -212,7 +250,7 @@ Slot Proxy::registerSignalHandler( const char* interfaceName
, signalInfo.get()
, return_slot );
return {signalInfo.release(), [](void *ptr){ delete static_cast<SignalInfo*>(ptr); }};
return {signalInfo.release(), [](void *ptr){ delete static_cast<SignalInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
}
void Proxy::unregister()
@@ -290,7 +328,7 @@ Proxy::FloatingAsyncCallSlots::~FloatingAsyncCallSlots()
void Proxy::FloatingAsyncCallSlots::push_back(std::shared_ptr<AsyncCallInfo> asyncCallInfo)
{
std::lock_guard lock(mutex_);
const std::lock_guard lock(mutex_);
if (!asyncCallInfo->finished) // The call may have finished in the meantime
slots_.emplace_back(std::move(asyncCallInfo));
}
@@ -326,7 +364,7 @@ void Proxy::FloatingAsyncCallSlots::clear()
// mutex) is in progress in a different thread, we get double-mutex deadlock.
}
}
} // namespace sdbus::internal
namespace sdbus {
@@ -354,90 +392,88 @@ bool PendingAsyncCall::isPending() const
return !callInfo_.expired();
}
}
} // namespace sdbus
namespace sdbus {
std::unique_ptr<sdbus::IProxy> createProxy( IConnection& connection
std::unique_ptr<IProxy> createProxy( IConnection& connection
, ServiceName destination
, ObjectPath objectPath )
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(&connection);
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
return std::make_unique<sdbus::internal::Proxy>( *sdbusConnection
return std::make_unique<internal::Proxy>( *sdbusConnection
, std::move(destination)
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath )
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved): connection is moved but cast to an internal type
std::unique_ptr<IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath )
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(connection.release());
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
connection.release();
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath) );
return std::make_unique<internal::Proxy>( std::unique_ptr<internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t )
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved): connection is moved cast to an internal type
std::unique_ptr<IProxy> createProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t )
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(connection.release());
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
connection.release();
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
return std::make_unique<internal::Proxy>( std::unique_ptr<internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
}
std::unique_ptr<sdbus::IProxy> createLightWeightProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath )
std::unique_ptr<IProxy> createLightWeightProxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath )
{
return createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread);
}
std::unique_ptr<sdbus::IProxy> createProxy( ServiceName destination
, ObjectPath objectPath )
std::unique_ptr<IProxy> createProxy( ServiceName destination
, ObjectPath objectPath )
{
auto connection = sdbus::createBusConnection();
auto connection = createBusConnection();
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
auto sdbusConnection = std::unique_ptr<internal::IConnection>(dynamic_cast<internal::IConnection*>(connection.release()));
assert(sdbusConnection != nullptr);
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
, std::move(destination)
, std::move(objectPath) );
return std::make_unique<internal::Proxy>( std::move(sdbusConnection)
, std::move(destination)
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IProxy> createProxy( ServiceName destination
std::unique_ptr<IProxy> createProxy( ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t )
{
auto connection = sdbus::createBusConnection();
auto connection = createBusConnection();
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
auto sdbusConnection = std::unique_ptr<internal::IConnection>(dynamic_cast<internal::IConnection*>(connection.release()));
assert(sdbusConnection != nullptr);
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
return std::make_unique<internal::Proxy>( std::move(sdbusConnection)
, std::move(destination)
, std::move(objectPath)
, dont_run_event_loop_thread );
}
std::unique_ptr<sdbus::IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath)
std::unique_ptr<IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath)
{
return createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread);
}
}
} // namespace sdbus
+21 -14
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Proxy.h
*
@@ -45,19 +45,19 @@ namespace sdbus::internal {
: public IProxy
{
public:
Proxy( sdbus::internal::IConnection& connection
Proxy( IConnection& connection
, ServiceName destination
, ObjectPath objectPath );
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
Proxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath );
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
Proxy( std::unique_ptr<IConnection>&& connection
, ServiceName destination
, ObjectPath objectPath
, dont_run_event_loop_thread_t );
MethodCall createMethodCall(const InterfaceName& interfaceName, const MethodName& methodName) const override;
MethodCall createMethodCall(const char* interfaceName, const char* methodName) const override;
[[nodiscard]] MethodCall createMethodCall(const InterfaceName& interfaceName, const MethodName& methodName) const override;
[[nodiscard]] MethodCall createMethodCall(const char* interfaceName, const char* methodName) const override;
MethodReply callMethod(const MethodCall& message) override;
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) override;
@@ -73,6 +73,10 @@ namespace sdbus::internal {
, return_slot_t ) override;
std::future<MethodReply> callMethodAsync(const MethodCall& message, with_future_t) override;
std::future<MethodReply> callMethodAsync(const MethodCall& message, uint64_t timeout, with_future_t) override;
Awaitable<MethodReply> callMethodAsync(const MethodCall& message, with_awaitable_t) override;
Awaitable<MethodReply> callMethodAsync( const MethodCall& message
, uint64_t timeout
, with_awaitable_t ) override;
void registerSignalHandler( const InterfaceName& interfaceName
, const SignalName& signalName
@@ -98,12 +102,9 @@ namespace sdbus::internal {
static int sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
private:
friend PendingAsyncCall;
std::unique_ptr< sdbus::internal::IConnection
, std::function<void(sdbus::internal::IConnection*)>
> connection_;
std::unique_ptr<IConnection, std::function<void(IConnection*)>> connection_;
ServiceName destination_;
ObjectPath objectPath_;
@@ -112,15 +113,15 @@ namespace sdbus::internal {
struct SignalInfo
{
signal_handler callback;
Proxy& proxy;
Proxy& proxy; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
Slot slot;
};
struct AsyncCallInfo
{
async_reply_handler callback;
Proxy& proxy;
Slot slot{};
Proxy& proxy; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
Slot slot;
bool finished{false};
bool floating;
};
@@ -129,7 +130,13 @@ namespace sdbus::internal {
class FloatingAsyncCallSlots
{
public:
FloatingAsyncCallSlots() = default;
FloatingAsyncCallSlots(const FloatingAsyncCallSlots&) = delete;
FloatingAsyncCallSlots& operator=(const FloatingAsyncCallSlots&) = delete;
FloatingAsyncCallSlots(FloatingAsyncCallSlots&& other) = delete;
FloatingAsyncCallSlots& operator=(FloatingAsyncCallSlots&&) = delete;
~FloatingAsyncCallSlots();
void push_back(std::shared_ptr<AsyncCallInfo> asyncCallInfo);
void erase(AsyncCallInfo* info);
void clear();
@@ -142,6 +149,6 @@ namespace sdbus::internal {
FloatingAsyncCallSlots floatingAsyncCallSlots_;
};
}
} // namespace sdbus::internal
#endif /* SDBUS_CXX_INTERNAL_PROXY_H_ */
+21 -16
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ScopeGuard.h
*
@@ -30,6 +30,8 @@
#include <exception>
#include <utility>
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
// Straightforward, modern, easy-to-use RAII utility to perform work on scope exit in an exception-safe manner.
//
// The utility helps providing basic exception safety guarantee by ensuring that the resources are always
@@ -105,21 +107,22 @@ namespace sdbus::internal {
}
};
template <class _Fun, typename _Tag>
template <class Fun, typename Tag>
class ScopeGuard
{
public:
ScopeGuard(_Fun f) : fnc_(std::move(f))
explicit ScopeGuard(Fun fun) : fnc_(std::move(fun))
{
}
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs) : fnc_(std::move(rhs.fnc_)), active_(rhs.active_), exceptions_(rhs.exceptions_)
ScopeGuard(ScopeGuard&& rhs) noexcept : fnc_(std::move(rhs.fnc_)), exceptions_(rhs.exceptions_), active_(rhs.active_)
{
rhs.dismiss();
}
ScopeGuard& operator=(ScopeGuard&&) = delete;
void dismiss()
{
@@ -128,35 +131,35 @@ namespace sdbus::internal {
~ScopeGuard()
{
if (active_ && _Tag::holds(exceptions_))
if (active_ && Tag::holds(exceptions_))
fnc_();
}
private:
_Fun fnc_;
Fun fnc_;
int exceptions_{std::uncaught_exceptions()};
bool active_{true};
};
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitTag> operator+(ScopeGuardOnExitTag, _Fun&& fnc)
template <typename Fun>
ScopeGuard<Fun, ScopeGuardOnExitTag> operator+(ScopeGuardOnExitTag, Fun&& fnc)
{
return ScopeGuard<_Fun, ScopeGuardOnExitTag>(std::forward<_Fun>(fnc));
return ScopeGuard<Fun, ScopeGuardOnExitTag>(std::forward<Fun>(fnc));
}
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitSuccessTag> operator+(ScopeGuardOnExitSuccessTag, _Fun&& fnc)
template <typename Fun>
ScopeGuard<Fun, ScopeGuardOnExitSuccessTag> operator+(ScopeGuardOnExitSuccessTag, Fun&& fnc)
{
return ScopeGuard<_Fun, ScopeGuardOnExitSuccessTag>(std::forward<_Fun>(fnc));
return ScopeGuard<Fun, ScopeGuardOnExitSuccessTag>(std::forward<Fun>(fnc));
}
template <typename _Fun>
ScopeGuard<_Fun, ScopeGuardOnExitFailureTag> operator+(ScopeGuardOnExitFailureTag, _Fun&& fnc)
template <typename Fun>
ScopeGuard<Fun, ScopeGuardOnExitFailureTag> operator+(ScopeGuardOnExitFailureTag, Fun&& fnc)
{
return ScopeGuard<_Fun, ScopeGuardOnExitFailureTag>(std::forward<_Fun>(fnc));
return ScopeGuard<Fun, ScopeGuardOnExitFailureTag>(std::forward<Fun>(fnc));
}
}
} // namespace sdbus::internal
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
@@ -167,4 +170,6 @@ namespace sdbus::internal {
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
#endif
// NOLINTEND(cppcoreguidelines-macro-usage)
#endif /* SDBUS_CPP_INTERNAL_SCOPEGUARD_H_ */
+96 -91
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file SdBus.cpp
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -26,93 +26,97 @@
*/
#include "SdBus.h"
#include <sdbus-c++/Error.h>
#include "sdbus-c++/Error.h" // NOLINT(misc-include-cleaner)
#include SDBUS_HEADER
#include <algorithm>
#include <cstdint>
#include <mutex>
#include <sys/types.h>
namespace sdbus::internal {
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *m)
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *msg)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_ref(m);
return ::sd_bus_message_ref(msg);
}
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *msg)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_unref(m);
return ::sd_bus_message_unref(msg);
}
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *msg, uint64_t *cookie)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
auto r = ::sd_bus_send(bus, m, cookie);
auto r = ::sd_bus_send(bus, msg, cookie);
if (r < 0)
return r;
return r;
}
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *msg, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_call(bus, m, usec, ret_error, reply);
return ::sd_bus_call(bus, msg, usec, ret_error, reply);
}
int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec)
int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *msg, sd_bus_message_handler_t callback, void *userdata, uint64_t usec)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
auto r = ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
auto r = ::sd_bus_call_async(bus, slot, msg, callback, userdata, usec);
if (r < 0)
return r;
return r;
}
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type)
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **msg, uint8_t type)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_new(bus, m, type);
return ::sd_bus_message_new(bus, msg, type);
}
int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)
int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **msg, const char *destination, const char *path, const char *interface, const char *member)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
return ::sd_bus_message_new_method_call(bus, msg, destination, path, interface, member);
}
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **msg, const char *path, const char *interface, const char *member)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_new_signal(bus, m, path, interface, member);
return ::sd_bus_message_new_signal(bus, msg, path, interface, member);
}
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m)
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **msg)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_new_method_return(call, m);
return ::sd_bus_message_new_method_return(call, msg);
}
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e)
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **msg, const sd_bus_error *err)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_new_method_error(call, m, e);
return ::sd_bus_message_new_method_error(call, msg, err);
}
int SdBus::sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec)
{
#if LIBSYSTEMD_VERSION>=240
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_set_method_call_timeout(bus, usec);
#else
@@ -125,7 +129,7 @@ int SdBus::sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec)
int SdBus::sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret)
{
#if LIBSYSTEMD_VERSION>=240
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_get_method_call_timeout(bus, ret);
#else
@@ -137,35 +141,35 @@ int SdBus::sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret)
int SdBus::sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_emit_properties_changed_strv(bus, path, interface, names);
}
int SdBus::sd_bus_emit_object_added(sd_bus *bus, const char *path)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_emit_object_added(bus, path);
}
int SdBus::sd_bus_emit_object_removed(sd_bus *bus, const char *path)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_emit_object_removed(bus, path);
}
int SdBus::sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
}
int SdBus::sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
}
@@ -197,14 +201,14 @@ int SdBus::sd_bus_open_user_with_address(sd_bus **ret, const char* address)
if (r < 0)
return r;
r = ::sd_bus_set_bus_client(bus, true);
r = ::sd_bus_set_bus_client(bus, true); // NOLINT(readability-implicit-bool-conversion)
if (r < 0)
return r;
// Copying behavior from
// https://github.com/systemd/systemd/blob/fee6441601c979165ebcbb35472036439f8dad5f/src/libsystemd/sd-bus/sd-bus.c#L1381
// Here, we make the bus as trusted
r = ::sd_bus_set_trusted(bus, true);
r = ::sd_bus_set_trusted(bus, true); // NOLINT(readability-implicit-bool-conversion)
if (r < 0)
return r;
@@ -276,7 +280,7 @@ int SdBus::sd_bus_open_server(sd_bus **ret, int fd)
if (r < 0)
return r;
r = ::sd_bus_set_server(bus, true, id);
r = ::sd_bus_set_server(bus, true, id); // NOLINT(readability-implicit-bool-conversion)
if (r < 0)
return r;
@@ -303,62 +307,63 @@ int SdBus::sd_bus_open_system_remote(sd_bus **ret, const char *host)
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_request_name(bus, name, flags);
}
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_release_name(bus, name);
}
int SdBus::sd_bus_get_unique_name(sd_bus *bus, const char **name)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_get_unique_name(bus, name);
}
int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
}
int SdBus::sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_object_manager(bus, slot, path);
}
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_match(bus, slot, match, callback, userdata);
}
int SdBus::sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_add_match_async(bus, slot, match, callback, install_callback, userdata);
}
int SdBus::sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_match_signal(bus, ret, sender, path, interface, member, callback, userdata);
}
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_slot_unref(slot);
}
@@ -373,11 +378,11 @@ int SdBus::sd_bus_start(sd_bus *bus)
return ::sd_bus_start(bus);
}
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **msg)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_process(bus, r);
return ::sd_bus_process(bus, msg);
}
sd_bus_message* SdBus::sd_bus_get_current_message(sd_bus *bus)
@@ -387,7 +392,7 @@ sd_bus_message* SdBus::sd_bus_get_current_message(sd_bus *bus)
int SdBus::sd_bus_get_poll_data(sd_bus *bus, PollData* data)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
auto r = ::sd_bus_get_fd(bus);
if (r < 0)
@@ -404,9 +409,9 @@ int SdBus::sd_bus_get_poll_data(sd_bus *bus, PollData* data)
return r;
}
int SdBus::sd_bus_get_n_queued(sd_bus *bus, uint64_t *read, uint64_t* write)
int SdBus::sd_bus_get_n_queued(sd_bus *bus, uint64_t *read, uint64_t* write) // NOLINT(bugprone-easily-swappable-parameters)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
auto r1 = ::sd_bus_get_n_queued_read(bus, read);
auto r2 = ::sd_bus_get_n_queued_write(bus, write);
@@ -434,81 +439,81 @@ sd_bus* SdBus::sd_bus_close_unref(sd_bus *bus)
#endif
}
int SdBus::sd_bus_message_set_destination(sd_bus_message *m, const char *destination)
int SdBus::sd_bus_message_set_destination(sd_bus_message *msg, const char *destination)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_message_set_destination(m, destination);
return ::sd_bus_message_set_destination(msg, destination);
}
int SdBus::sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c)
int SdBus::sd_bus_query_sender_creds(sd_bus_message *msg, uint64_t mask, sd_bus_creds **creds)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_query_sender_creds(m, mask, c);
return ::sd_bus_query_sender_creds(msg, mask, creds);
}
sd_bus_creds* SdBus::sd_bus_creds_ref(sd_bus_creds *c)
sd_bus_creds* SdBus::sd_bus_creds_ref(sd_bus_creds *creds)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_ref(c);
return ::sd_bus_creds_ref(creds);
}
sd_bus_creds* SdBus::sd_bus_creds_unref(sd_bus_creds *c)
sd_bus_creds* SdBus::sd_bus_creds_unref(sd_bus_creds *creds)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_unref(c);
return ::sd_bus_creds_unref(creds);
}
int SdBus::sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid)
int SdBus::sd_bus_creds_get_pid(sd_bus_creds *creds, pid_t *pid)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_pid(c, pid);
return ::sd_bus_creds_get_pid(creds, pid);
}
int SdBus::sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid)
int SdBus::sd_bus_creds_get_uid(sd_bus_creds *creds, uid_t *uid)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_uid(c, uid);
return ::sd_bus_creds_get_uid(creds, uid);
}
int SdBus::sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid)
int SdBus::sd_bus_creds_get_euid(sd_bus_creds *creds, uid_t *euid)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_euid(c, euid);
return ::sd_bus_creds_get_euid(creds, euid);
}
int SdBus::sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid)
int SdBus::sd_bus_creds_get_gid(sd_bus_creds *creds, gid_t *gid)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_gid(c, gid);
return ::sd_bus_creds_get_gid(creds, gid);
}
int SdBus::sd_bus_creds_get_egid(sd_bus_creds *c, uid_t *egid)
int SdBus::sd_bus_creds_get_egid(sd_bus_creds *creds, uid_t *egid)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_egid(c, egid);
return ::sd_bus_creds_get_egid(creds, egid);
}
int SdBus::sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids)
int SdBus::sd_bus_creds_get_supplementary_gids(sd_bus_creds *creds, const gid_t **gids)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_supplementary_gids(c, gids);
return ::sd_bus_creds_get_supplementary_gids(creds, gids);
}
int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label)
int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *creds, const char **label)
{
std::lock_guard lock(sdbusMutex_);
const std::lock_guard lock(sdbusMutex_);
return ::sd_bus_creds_get_selinux_context(c, label);
return ::sd_bus_creds_get_selinux_context(creds, label);
}
}
} // namespace sdbus::internal
+57 -57
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file SdBus.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -36,75 +36,75 @@ namespace sdbus::internal {
class SdBus final : public ISdBus
{
public:
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) override;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
sd_bus_message* sd_bus_message_ref(sd_bus_message *msg) override;
sd_bus_message* sd_bus_message_unref(sd_bus_message *msg) override;
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) override;
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) override;
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) override;
int sd_bus_send(sd_bus *bus, sd_bus_message *msg, uint64_t *cookie) override;
int sd_bus_call(sd_bus *bus, sd_bus_message *msg, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) override;
int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *msg, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) override;
virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) override;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) override;
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) override;
int sd_bus_message_new(sd_bus *bus, sd_bus_message **msg, uint8_t type) override;
int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **msg, const char *destination, const char *path, const char *interface, const char *member) override;
int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **msg, const char *path, const char *interface, const char *member) override;
int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **msg) override;
int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **msg, const sd_bus_error *err) override;
virtual int sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec) override;
virtual int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) override;
int sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec) override;
int sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret) override;
virtual int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names) override;
virtual int sd_bus_emit_object_added(sd_bus *bus, const char *path) override;
virtual int sd_bus_emit_object_removed(sd_bus *bus, const char *path) override;
virtual int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) override;
virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) override;
int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names) override;
int sd_bus_emit_object_added(sd_bus *bus, const char *path) override;
int sd_bus_emit_object_removed(sd_bus *bus, const char *path) override;
int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) override;
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) override;
virtual int sd_bus_open(sd_bus **ret) override;
virtual int sd_bus_open_system(sd_bus **ret) override;
virtual int sd_bus_open_user(sd_bus **ret) override;
virtual int sd_bus_open_user_with_address(sd_bus **ret, const char* address) override;
virtual int sd_bus_open_system_remote(sd_bus **ret, const char* hsot) override;
virtual int sd_bus_open_direct(sd_bus **ret, const char* address) override;
virtual int sd_bus_open_direct(sd_bus **ret, int fd) override;
virtual int sd_bus_open_server(sd_bus **ret, int fd) override;
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
virtual int sd_bus_release_name(sd_bus *bus, const char *name) override;
virtual int sd_bus_get_unique_name(sd_bus *bus, const char **name) override;
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
virtual int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) override;
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
virtual int sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata) override;
virtual int sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata) override;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
int sd_bus_open(sd_bus **ret) override;
int sd_bus_open_system(sd_bus **ret) override;
int sd_bus_open_user(sd_bus **ret) override;
int sd_bus_open_user_with_address(sd_bus **ret, const char* address) override;
int sd_bus_open_system_remote(sd_bus **ret, const char* host) override;
int sd_bus_open_direct(sd_bus **ret, const char* address) override;
int sd_bus_open_direct(sd_bus **ret, int fd) override;
int sd_bus_open_server(sd_bus **ret, int fd) override;
int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
int sd_bus_release_name(sd_bus *bus, const char *name) override;
int sd_bus_get_unique_name(sd_bus *bus, const char **name) override;
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) override;
int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
int sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata) override;
int sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata) override;
sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
virtual int sd_bus_new(sd_bus **ret) override;
virtual int sd_bus_start(sd_bus *bus) override;
int sd_bus_new(sd_bus **ret) override;
int sd_bus_start(sd_bus *bus) override;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
virtual sd_bus_message* sd_bus_get_current_message(sd_bus *bus) override;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) override;
virtual int sd_bus_get_n_queued(sd_bus *bus, uint64_t *read, uint64_t* write) override;
virtual int sd_bus_flush(sd_bus *bus) override;
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
virtual sd_bus *sd_bus_close_unref(sd_bus *bus) override;
int sd_bus_process(sd_bus *bus, sd_bus_message **msg) override;
sd_bus_message* sd_bus_get_current_message(sd_bus *bus) override;
int sd_bus_get_poll_data(sd_bus *bus, PollData* data) override;
int sd_bus_get_n_queued(sd_bus *bus, uint64_t *read, uint64_t* write) override;
int sd_bus_flush(sd_bus *bus) override;
sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
sd_bus *sd_bus_close_unref(sd_bus *bus) override;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) override;
int sd_bus_message_set_destination(sd_bus_message *msg, const char *destination) override;
virtual int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) override;
virtual sd_bus_creds* sd_bus_creds_ref(sd_bus_creds *c) override;
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) override;
int sd_bus_query_sender_creds(sd_bus_message *msg, uint64_t mask, sd_bus_creds **creds) override;
sd_bus_creds* sd_bus_creds_ref(sd_bus_creds *creds) override;
sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *creds) override;
virtual int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) override;
virtual int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) override;
virtual int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) override;
virtual int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) override;
virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) override;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) override;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) override;
int sd_bus_creds_get_pid(sd_bus_creds *creds, pid_t *pid) override;
int sd_bus_creds_get_uid(sd_bus_creds *creds, uid_t *uid) override;
int sd_bus_creds_get_euid(sd_bus_creds *creds, uid_t *euid) override;
int sd_bus_creds_get_gid(sd_bus_creds *creds, gid_t *gid) override;
int sd_bus_creds_get_egid(sd_bus_creds *creds, gid_t *egid) override;
int sd_bus_creds_get_supplementary_gids(sd_bus_creds *creds, const gid_t **gids) override;
int sd_bus_creds_get_selinux_context(sd_bus_creds *creds, const char **label) override;
private:
std::recursive_mutex sdbusMutex_;
};
}
} // namespace sdbus::internal
#endif //SDBUS_C_SDBUS_H
#endif // SDBUS_CXX_SDBUS_H
+4 -6
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Types.cpp
*
@@ -24,11 +24,9 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sdbus-c++/Types.h"
#include "sdbus-c++/Error.h"
#include "MessageUtils.h"
#include "sdbus-c++/Message.h"
#include "sdbus-c++/Types.h"
#include <cerrno>
#include <system_error>
@@ -82,7 +80,7 @@ int UnixFd::checkedDup(int fd)
return fd;
}
int ret = ::dup(fd); // NOLINT(android-cloexec-dup) // TODO: verify
const int ret = ::dup(fd); // NOLINT(android-cloexec-dup) // TODO: verify
if (ret < 0)
{
throw std::system_error(errno, std::generic_category(), "dup failed");
+8 -4
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Utils.h
*
@@ -30,6 +30,8 @@
#include <sdbus-c++/Error.h>
#include SDBUS_HEADER
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#if LIBSYSTEMD_VERSION>=246
#define SDBUS_CHECK_OBJECT_PATH(_PATH) \
SDBUS_THROW_ERROR_IF(!sd_bus_object_path_is_valid(_PATH), std::string("Invalid object path '") + _PATH + "' provided", EINVAL) \
@@ -50,10 +52,12 @@
#define SDBUS_CHECK_MEMBER_NAME(_NAME)
#endif
// NOLINTEND(cppcoreguidelines-macro-usage)
namespace sdbus::internal {
template <typename _Callable>
bool invokeHandlerAndCatchErrors(_Callable callable, sd_bus_error *retError)
template <typename Callable>
bool invokeHandlerAndCatchErrors(Callable callable, sd_bus_error *retError)
{
try
{
@@ -93,6 +97,6 @@ namespace sdbus::internal {
template <class... Ts> struct overload : Ts... { using Ts::operator()...; };
template <class... Ts> overload(Ts...) -> overload<Ts...>;
}
} // namespace sdbus::internal
#endif /* SDBUS_CXX_INTERNAL_UTILS_H_ */
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file VTableUtils.c
*
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file VTableUtils.h
*
+23 -21
View File
@@ -54,48 +54,46 @@ set(UNITTESTS_SRCS
${UNITTESTS_SOURCE_DIR}/mocks/SdBusMock.h)
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
set(INTEGRATIONTESTS_GENERATED_DIR ${INTEGRATIONTESTS_SOURCE_DIR}/dbus-api/gen-cpp)
set(INTEGRATIONTESTS_SRCS
${INTEGRATIONTESTS_SOURCE_DIR}/DBusConnectionTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusGeneralTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusMethodsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusAsyncMethodsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusAwaitableMethodsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusSignalsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusPropertiesTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusStandardInterfacesTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/Defs.h
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-adaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-proxy.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp)
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp
${INTEGRATIONTESTS_GENERATED_DIR}/integrationtests-adaptor.h
${INTEGRATIONTESTS_GENERATED_DIR}/integrationtests-proxy.h)
set(PERFTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/perftests)
set(STRESSTESTS_CLIENT_SRCS
set(PERFTESTS_GENERATED_DIR ${PERFTESTS_SOURCE_DIR}/dbus-api/gen-cpp)
set(PERFTESTS_CLIENT_SRCS
${PERFTESTS_SOURCE_DIR}/client.cpp
${PERFTESTS_SOURCE_DIR}/perftests-proxy.h)
set(STRESSTESTS_SERVER_SRCS
${PERFTESTS_GENERATED_DIR}/perftests-proxy.h)
set(PERFTESTS_SERVER_SRCS
${PERFTESTS_SOURCE_DIR}/server.cpp
${PERFTESTS_SOURCE_DIR}/perftests-adaptor.h)
${PERFTESTS_GENERATED_DIR}/perftests-adaptor.h)
set(STRESSTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/stresstests)
set(STRESSTESTS_GENERATED_DIR ${STRESSTESTS_SOURCE_DIR}/dbus-api/gen-cpp)
set(STRESSTESTS_SRCS
${STRESSTESTS_SOURCE_DIR}/sdbus-c++-stress-tests.cpp
${STRESSTESTS_SOURCE_DIR}/fahrenheit-thermometer-adaptor.h
${STRESSTESTS_SOURCE_DIR}/fahrenheit-thermometer-proxy.h
${STRESSTESTS_SOURCE_DIR}/celsius-thermometer-adaptor.h
${STRESSTESTS_SOURCE_DIR}/celsius-thermometer-proxy.h
${STRESSTESTS_SOURCE_DIR}/concatenator-adaptor.h
${STRESSTESTS_SOURCE_DIR}/concatenator-proxy.h)
#-------------------------------
# GENERAL COMPILER CONFIGURATION
#-------------------------------
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
${STRESSTESTS_GENERATED_DIR}/fahrenheit-thermometer-adaptor.h
${STRESSTESTS_GENERATED_DIR}/fahrenheit-thermometer-proxy.h
${STRESSTESTS_GENERATED_DIR}/celsius-thermometer-adaptor.h
${STRESSTESTS_GENERATED_DIR}/celsius-thermometer-proxy.h
${STRESSTESTS_GENERATED_DIR}/concatenator-adaptor.h
${STRESSTESTS_GENERATED_DIR}/concatenator-proxy.h)
#----------------------------------
# BUILD INFORMATION
@@ -112,6 +110,7 @@ add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS})
target_compile_definitions(sdbus-c++-integration-tests PRIVATE
LIBSYSTEMD_VERSION=${SDBUSCPP_LIBSYSTEMD_VERSION}
SDBUS_${SDBUS_IMPL})
target_include_directories(sdbus-c++-integration-tests SYSTEM PRIVATE ${INTEGRATIONTESTS_GENERATED_DIR})
if(NOT SDBUS_IMPL STREQUAL "basu")
# Systemd::Libsystemd is included because integration tests use sd-event. Otherwise sdbus-c++ encapsulates and hides libsystemd.
target_link_libraries(sdbus-c++-integration-tests sdbus-c++ Systemd::Libsystemd GTest::gmock)
@@ -126,15 +125,18 @@ if(SDBUSCPP_BUILD_PERF_TESTS OR SDBUSCPP_BUILD_STRESS_TESTS)
if(SDBUSCPP_BUILD_PERF_TESTS)
message(STATUS "Building with performance tests")
add_executable(sdbus-c++-perf-tests-client ${STRESSTESTS_CLIENT_SRCS})
add_executable(sdbus-c++-perf-tests-client ${PERFTESTS_CLIENT_SRCS})
target_include_directories(sdbus-c++-perf-tests-client SYSTEM PRIVATE ${PERFTESTS_GENERATED_DIR})
target_link_libraries(sdbus-c++-perf-tests-client sdbus-c++ Threads::Threads)
add_executable(sdbus-c++-perf-tests-server ${STRESSTESTS_SERVER_SRCS})
add_executable(sdbus-c++-perf-tests-server ${PERFTESTS_SERVER_SRCS})
target_include_directories(sdbus-c++-perf-tests-server SYSTEM PRIVATE ${PERFTESTS_GENERATED_DIR})
target_link_libraries(sdbus-c++-perf-tests-server sdbus-c++ Threads::Threads)
endif()
if(SDBUSCPP_BUILD_STRESS_TESTS)
message(STATUS "Building with stress tests")
add_executable(sdbus-c++-stress-tests ${STRESSTESTS_SRCS})
target_include_directories(sdbus-c++-stress-tests SYSTEM PRIVATE ${STRESSTESTS_GENERATED_DIR})
target_link_libraries(sdbus-c++-stress-tests sdbus-c++ Threads::Threads)
endif()
endif()
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusAsyncMethodsTests.cpp
*
@@ -25,27 +25,30 @@
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include <sdbus-c++/sdbus-c++.h>
#include <cstdint>
#include <exception>
#include <atomic>
#include <cstddef>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <optional>
#include <mutex>
#include <map>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
#include <utility>
#include <vector>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::Le;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -92,22 +95,22 @@ TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchronousMethodAsynchronously)
// Yeah, this is kinda timing-dependent test, but times should be safe...
std::mutex mtx;
std::vector<uint32_t> results;
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
std::atomic invoke{false};
std::atomic startedCount{0};
auto call = [&](uint32_t param)
{
TestProxy proxy{SERVICE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
auto result = proxy.doOperationAsync(param);
std::lock_guard<std::mutex> guard(mtx);
std::lock_guard const guard(mtx);
results.push_back(result);
};
std::thread invocations[]{std::thread{call, 1500}, std::thread{call, 1000}, std::thread{call, 500}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
std::for_each(std::begin(invocations), std::end(invocations), [](auto& thread){ thread.join(); });
ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
}
@@ -115,8 +118,8 @@ TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchronousMethodAsynchronously)
TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
{
std::atomic<size_t> resultCount{};
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
std::atomic invoke{false};
std::atomic startedCount{0};
auto call = [&]()
{
TestProxy proxy{SERVICE_NAME, OBJECT_PATH};
@@ -137,7 +140,7 @@ TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncM
std::thread invocations[]{std::thread{call}, std::thread{call}, std::thread{call}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
std::for_each(std::begin(invocations), std::end(invocations), [](auto& thread){ thread.join(); });
ASSERT_THAT(resultCount, Eq(1500));
}
@@ -203,7 +206,7 @@ TYPED_TEST(AsyncSdbusTestObject, InvokesMethodWithLargeDataAsynchronouslyOnClien
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
{
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){});
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){});
auto call = this->m_proxy->doOperationClientSideAsync(100);
@@ -214,7 +217,7 @@ TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
auto call = this->m_proxy->doOperationClientSideAsync(100);
call.cancel();
@@ -226,7 +229,7 @@ TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSideByDestroying
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
{
auto slot = this->m_proxy->doOperationClientSideAsync(100, sdbus::return_slot);
@@ -239,8 +242,7 @@ TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSideByDestroying
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
auto call = this->m_proxy->doOperationClientSideAsync(100);
call.cancel();
@@ -252,7 +254,7 @@ TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenC
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
auto call = this->m_proxy->doOperationClientSideAsync(0);
(void) future.get(); // Wait for the call to finish
@@ -262,7 +264,7 @@ TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenC
TYPED_TEST(AsyncSdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending)
{
sdbus::PendingAsyncCall call;
sdbus::PendingAsyncCall const call;
ASSERT_FALSE(call.isPending());
}
@@ -276,7 +278,7 @@ TYPED_TEST(AsyncSdbusTestObject, SupportsAsyncCallCopyAssignment)
ASSERT_TRUE(call.isPending());
}
TYPED_TEST(AsyncSdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
TYPED_TEST(AsyncSdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails) // NOLINT(readability-function-cognitive-complexity)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
@@ -0,0 +1,247 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2026 - Alex Cani <alexcani109@gmail.com>
*
* @file DBusAwaitableMethodsTests.cpp
*
* Created on: Mar 1, 2026
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include <coroutine>
#include <cstdint>
#include <exception>
#include <future>
#include <map>
#include <string>
#include <utility>
#include <sdbus-c++/sdbus-c++.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "TestFixture.h"
#include "TestProxy.h"
using ::testing::Eq;
using namespace std::chrono_literals;
using namespace sdbus::test;
// Simple coroutine task type for testing purposes
// Uses a promise/future pair to communicate results and exceptions
// between the coroutine and the test code. Do not mistake this for
// the std::future-based async API of sdbus-c++.
template<typename T>
struct Task {
struct promise_type {
T value;
std::exception_ptr exception;
std::promise<T> completion;
std::future<T> future;
promise_type() : future(completion.get_future()) {}
Task get_return_object() {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
// Lazy coroutine
std::suspend_always initial_suspend() noexcept { return {}; }
// final_suspend suspends so that the test code can retrieve the result
// or exception from the promise before the coroutine is destroyed
std::suspend_always final_suspend() noexcept
{
if (exception)
{
completion.set_exception(exception);
}
else
{
completion.set_value(std::move(value));
}
return {};
}
void return_value(T val) { value = std::move(val); }
void unhandled_exception() { exception = std::current_exception(); }
};
std::coroutine_handle<promise_type> handle;
// Ctor and rule of 5 for proper handle management
explicit Task(std::coroutine_handle<promise_type> hnd) : handle(hnd) {}
Task(Task&& other) noexcept : handle(std::exchange(other.handle, {})) {}
Task& operator=(Task&& other) noexcept {
if (this != &other) {
if (handle) handle.destroy();
handle = std::exchange(other.handle, {});
}
return *this;
}
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
~Task() { if (handle) handle.destroy(); }
// "User API" for the test code, allows starting the task and retrieving the result or exception
void resume() { if (handle && !handle.done()) handle.resume(); }
T get() { return handle.promise().future.get(); }
};
// Specialization for void
template<>
struct Task<void> {
struct promise_type {
std::exception_ptr exception;
std::promise<void> completion;
std::future<void> future;
promise_type() : future(completion.get_future()) {}
Task get_return_object() {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() noexcept { return {}; } // NOLINT(readability-convert-member-functions-to-static)
std::suspend_always final_suspend() noexcept
{
if (exception)
{
completion.set_exception(exception);
}
else
{
completion.set_value();
}
return {};
}
void return_void() {}
void unhandled_exception() { exception = std::current_exception(); }
};
std::coroutine_handle<promise_type> handle;
explicit Task(std::coroutine_handle<promise_type> hnd) : handle(hnd) {}
Task(Task&& other) noexcept : handle(std::exchange(other.handle, {})) {}
Task& operator=(Task&& other) noexcept {
if (this != &other) {
if (handle) handle.destroy();
handle = std::exchange(other.handle, {});
}
return *this;
}
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
~Task() { if (handle) handle.destroy(); }
void resume() { if (handle && !handle.done()) handle.resume(); } // NOLINT(readability-make-member-function-const)
void get() { handle.promise().future.get(); } // NOLINT(readability-make-member-function-const)
};
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithAwaitable)
{
auto task = [](TestProxy* proxy) -> Task<uint32_t> {
co_return co_await proxy->doOperationClientSideAsync(100, sdbus::with_awaitable);
}(this->m_proxy.get());
task.resume();
ASSERT_THAT(task.get(), Eq(100));
}
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithAwaitableOnBasicAPILevel)
{
auto task = [](TestProxy* proxy) -> Task<uint32_t> {
auto methodReply = co_await proxy->doOperationClientSideAsyncOnBasicAPILevel(100, sdbus::with_awaitable);
uint32_t returnValue{};
methodReply >> returnValue;
co_return returnValue;
}(this->m_proxy.get());
task.resume();
ASSERT_THAT(task.get(), Eq(100));
}
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodWithLargeDataAsynchronouslyOnClientSideWithAwaitable)
{
std::map<int32_t, std::string> largeMap;
for (int32_t i = 0; i < 40'000; ++i)
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1));
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines) -- lambda closure has guaranteed lifetime
auto lambda = [&largeMap, this]() -> Task<std::map<int32_t, std::string>> {
co_return co_await this->m_proxy->doOperationWithLargeDataClientSideAsync(largeMap, sdbus::with_awaitable);
};
auto task = lambda();
task.resume();
ASSERT_THAT(task.get(), Eq(largeMap));
}
TYPED_TEST(AsyncSdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithAwaitableFails)
{
auto task = [](TestProxy* proxy) -> Task<void> {
co_await proxy->doErroneousOperationClientSideAsync(sdbus::with_awaitable);
}(this->m_proxy.get());
task.resume();
ASSERT_THROW(task.get(), sdbus::Error);
}
TYPED_TEST(AsyncSdbusTestObject, AwaitableSupportsMultipleSequentialCalls)
{
auto task = [](TestProxy* proxy) -> Task<uint32_t> {
auto result1 = co_await proxy->doOperationClientSideAsync(10, sdbus::with_awaitable);
auto result2 = co_await proxy->doOperationClientSideAsync(20, sdbus::with_awaitable);
auto result3 = co_await proxy->doOperationClientSideAsync(30, sdbus::with_awaitable);
co_return result1 + result2 + result3;
}(this->m_proxy.get());
task.resume();
ASSERT_THAT(task.get(), Eq(60));
}
TYPED_TEST(AsyncSdbusTestObject, AwaitablePropagatesExceptionsCorrectly)
{
auto task = [](TestProxy* proxy) -> Task<std::string> {
try {
co_await proxy->doErroneousOperationClientSideAsync(sdbus::with_awaitable);
co_return "FAILED";
} catch (const sdbus::Error& e) {
// Verify we can inspect the exception
co_return std::string(e.getName());
}
}(this->m_proxy.get());
task.resume();
ASSERT_THAT(task.get(), ::testing::HasSubstr("Error"));
}
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusConnectionTests.cpp
*
@@ -33,13 +33,10 @@
// gmock
#include <gtest/gtest.h>
#include <gmock/gmock.h>
// STL
#include <thread>
#include <chrono>
using ::testing::Eq;
using namespace sdbus::test;
/*-------------------------------------*/
@@ -63,7 +60,7 @@ TEST(Connection, CanRequestName)
TEST(SystemBusConnection, CannotRequestNonregisteredDbusName)
{
auto connection = sdbus::createSystemBusConnection();
sdbus::ServiceName notSupportedBusName{"some.random.not.supported.dbus.name"};
sdbus::ServiceName const notSupportedBusName{"some.random.not.supported.dbus.name"};
ASSERT_THROW(connection->requestName(notSupportedBusName), sdbus::Error);
}
@@ -79,7 +76,7 @@ TEST(Connection, CanReleaseRequestedName)
TEST(Connection, CannotReleaseNonrequestedName)
{
auto connection = sdbus::createBusConnection();
sdbus::ServiceName notAcquiredBusName{"some.random.unacquired.name"};
sdbus::ServiceName const notAcquiredBusName{"some.random.unacquired.name"};
ASSERT_THROW(connection->releaseName(notAcquiredBusName), sdbus::Error);
}
+21 -23
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusGeneralTests.cpp
*
@@ -27,20 +27,18 @@
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "TestFixture.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include <sdbus-c++/sdbus-c++.h>
#include <atomic>
#include <cassert>
#include <cstddef>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <string_view>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
#include <variant>
#include <type_traits>
using ::testing::ElementsAre;
using ::testing::Eq;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -57,8 +55,8 @@ TEST(AdaptorAndProxy, CanBeConstructedSuccessfully)
auto connection = sdbus::createBusConnection();
connection->requestName(SERVICE_NAME);
ASSERT_NO_THROW(TestAdaptor adaptor(*connection, OBJECT_PATH));
ASSERT_NO_THROW(TestProxy proxy(SERVICE_NAME, OBJECT_PATH));
ASSERT_NO_THROW(const TestAdaptor adaptor(*connection, OBJECT_PATH));
ASSERT_NO_THROW(const TestProxy proxy(SERVICE_NAME, OBJECT_PATH));
connection->releaseName(SERVICE_NAME);
}
@@ -78,8 +76,8 @@ TEST(AnAdaptor, DoesNotSupportMoveSemantics)
TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
{
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
std::atomic matchingMessageReceived{false};
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](const sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
@@ -93,15 +91,15 @@ TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRu
TYPED_TEST(AConnection, CanInstallMatchRuleAsynchronously)
{
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
std::atomic<bool> matchRuleInstalled{false};
std::atomic matchingMessageReceived{false};
std::atomic matchRuleInstalled{false};
auto slot = this->s_proxyConnection->addMatchAsync( matchRule
, [&](sdbus::Message msg)
, [&](const sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
}
, [&](sdbus::Message /*msg*/)
, [&](const sdbus::Message& /*msg*/)
{
matchRuleInstalled = true;
}
@@ -117,8 +115,8 @@ TYPED_TEST(AConnection, CanInstallMatchRuleAsynchronously)
TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot)
{
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
std::atomic matchingMessageReceived{false};
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](const sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
@@ -133,10 +131,10 @@ TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedS
TYPED_TEST(AConnection, CanAddFloatingMatchRule)
{
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false};
std::atomic matchingMessageReceived{false};
auto con = sdbus::createBusConnection();
con->enterEventLoopAsync();
auto callback = [&](sdbus::Message msg)
auto callback = [&](const sdbus::Message& msg)
{
if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true;
@@ -157,7 +155,7 @@ TYPED_TEST(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule)
{
auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'";
std::atomic<size_t> numberOfMatchingMessages{};
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](const sdbus::Message& msg)
{
if(msg.getMemberName() == "simpleSignal"sv)
numberOfMatchingMessages++;
+28 -31
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusMethodsTests.cpp
*
@@ -25,27 +25,24 @@
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include <sdbus-c++/sdbus-c++.h>
#include <cstdint>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <map>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
#include <vector>
#include <variant>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::Le;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -54,15 +51,15 @@ using namespace sdbus::test;
namespace my {
struct Struct
{
int i;
int i{};
std::string s;
std::vector<double> l;
friend bool operator==(const Struct &lhs, const Struct &rhs) = default;
};
}
} // namespace my
SDBUSCPP_REGISTER_STRUCT(my::Struct, i, s, l);
SDBUSCPP_REGISTER_STRUCT(my::Struct, i, s, l); // NOLINT(readability-identifier-length)
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -91,36 +88,36 @@ TYPED_TEST(SdbusTestObject, CallsMethodsWithTuplesSuccessfully)
TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccessfully)
{
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
auto vectorRes = this->m_proxy->getInts16FromStruct(a);
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> const strctA{};
auto vectorRes = this->m_proxy->getInts16FromStruct(strctA);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> const strctB{
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE}
};
vectorRes = this->m_proxy->getInts16FromStruct(b);
vectorRes = this->m_proxy->getInts16FromStruct(strctB);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
}
TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccessfully)
{
sdbus::Variant v{DOUBLE_VALUE};
sdbus::Variant variantRes = this->m_proxy->processVariant(v);
sdbus::Variant const var{DOUBLE_VALUE};
sdbus::Variant const variantRes = this->m_proxy->processVariant(var);
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
}
TYPED_TEST(SdbusTestObject, CallsMethodWithStdVariantSuccessfully)
{
std::variant<int32_t, double, std::string> v{DOUBLE_VALUE};
auto variantRes = this->m_proxy->processVariant(v);
std::variant<int32_t, double, std::string> const var{DOUBLE_VALUE};
auto variantRes = this->m_proxy->processVariant(var);
ASSERT_THAT(std::get<int32_t>(variantRes), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
}
TYPED_TEST(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccessfully)
{
std::vector<int32_t> x{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
std::map<int32_t, sdbus::Variant> mapOfVariants = this->m_proxy->getMapOfVariants(x, y);
std::vector const vec{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> const strct{false, true};
std::map<int32_t, sdbus::Variant> mapOfVariants = this->m_proxy->getMapOfVariants(vec, strct);
decltype(mapOfVariants) res{ {-2, sdbus::Variant{false}}
, {0, sdbus::Variant{false}}
, {2, sdbus::Variant{true}}};
@@ -352,10 +349,10 @@ TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
{
auto& object = this->m_adaptor->getObject();
sdbus::InterfaceName interfaceName{"org.sdbuscpp.integrationtests2"};
sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"};
auto vtableSlot = object.addVTable( interfaceName
, { sdbus::registerMethod("add").implementedAs([](const int64_t& a, const double& b){ return a + b; })
, sdbus::registerMethod("subtract").implementedAs([](const int& a, const int& b){ return a - b; }) }
, { sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; })
, sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) }
, sdbus::return_slot );
// The new remote vtable is registered as long as we keep vtableSlot, so remote method calls now should pass
@@ -369,11 +366,11 @@ TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
TYPED_TEST(SdbusTestObject, CanUnregisterAdditionallyRegisteredVTableAtAnyTime)
{
auto& object = this->m_adaptor->getObject();
sdbus::InterfaceName interfaceName{"org.sdbuscpp.integrationtests2"};
sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"};
auto vtableSlot = object.addVTable( interfaceName
, { sdbus::registerMethod("add").implementedAs([](const int64_t& a, const double& b){ return a + b; })
, sdbus::registerMethod("subtract").implementedAs([](const int& a, const int& b){ return a - b; }) }
, { sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; })
, sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) }
, sdbus::return_slot );
vtableSlot.reset(); // Letting the slot go means letting go the associated vtable registration
+6 -17
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusPropertiesTests.cpp
*
@@ -25,26 +25,15 @@
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include <sdbus-c++/sdbus-c++.h>
#include <cstdint>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using ::testing::Not;
using ::testing::IsEmpty;
@@ -67,7 +56,7 @@ TYPED_TEST(SdbusTestObject, FailsWritingToReadOnlyProperty)
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWritePropertySuccessfully)
{
uint32_t newActionValue = 5678;
uint32_t const newActionValue = 5678;
this->m_proxy->action(newActionValue);
@@ -84,7 +73,7 @@ TYPED_TEST(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHa
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWriteVariantPropertySuccessfully)
{
sdbus::Variant newActionValue{5678};
sdbus::Variant const newActionValue{5678};
this->m_proxy->actionVariant(newActionValue);
+17 -11
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file AdaptorAndProxy_test.cpp
*
@@ -27,19 +27,17 @@
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include <sdbus-c++/sdbus-c++.h>
#include <cstdint>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <map>
#include <string>
#include <chrono>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using ::testing::NotNull;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -69,7 +67,7 @@ TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccessfully)
TYPED_TEST(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
{
sdbus::ServiceName otherBusName{SERVICE_NAME + "2"};
sdbus::ServiceName const otherBusName{SERVICE_NAME + "2"};
auto connection2 = sdbus::createBusConnection(otherBusName);
auto adaptor2 = std::make_unique<TestAdaptor>(*connection2, OBJECT_PATH);
@@ -101,11 +99,11 @@ TYPED_TEST(SdbusTestObject, EmitsSignalWithLargeMapSuccessfully)
TYPED_TEST(SdbusTestObject, EmitsSignalWithVariantSuccessfully)
{
double d = 3.14;
this->m_adaptor->emitSignalWithVariant(sdbus::Variant{d});
double const val = 3.14;
this->m_adaptor->emitSignalWithVariant(sdbus::Variant{val});
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithVariant));
ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(d));
ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(val));
}
TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccessfully)
@@ -116,6 +114,14 @@ TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccessfully)
ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq(sdbus::Signature{"av"}));
}
TYPED_TEST(SdbusTestObject, EmitsSignalWithErrorAndTypeMismatchSuccessfully)
{
this->m_adaptor->emitSignalWithErrorAndTypeMismatch();
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithTypeMismatch));
ASSERT_TRUE(this->m_proxy->m_errorFromSignal.has_value());
}
TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
{
this->m_adaptor->emitSimpleSignal();
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file DBusStandardInterfacesTests.cpp
*
@@ -26,24 +26,25 @@
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include "Defs.h"
#include "integrationtests-adaptor.h"
#include <sdbus-c++/sdbus-c++.h>
#include <exception>
#include <cstdint>
#include <atomic>
#include <cstddef>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <optional>
#include <map>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
#include <utility>
#include <vector>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
@@ -82,7 +83,7 @@ TYPED_TEST(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterface)
std::promise<std::string> promise;
auto future = promise.get_future();
this->m_proxy->GetAsync(INTERFACE_NAME, "state", [&](std::optional<sdbus::Error> err, sdbus::Variant value)
this->m_proxy->GetAsync(INTERFACE_NAME, "state", [&](std::optional<sdbus::Error> err, const sdbus::Variant& value)
{
if (!err)
promise.set_value(value.get<std::string>());
@@ -102,7 +103,7 @@ TYPED_TEST(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterfaceWith
TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{
uint32_t newActionValue = 2345;
uint32_t const newActionValue = 2345;
this->m_proxy->Set(INTERFACE_NAME, "action", sdbus::Variant{newActionValue});
@@ -111,7 +112,7 @@ TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface)
{
uint32_t newActionValue = 2346;
uint32_t const newActionValue = 2346;
std::promise<void> promise;
auto future = promise.get_future();
@@ -129,7 +130,7 @@ TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface)
TYPED_TEST(SdbusTestObject, CancelsAsynchronousPropertySettingViaPropertiesInterface)
{
uint32_t newActionValue = 2346;
uint32_t const newActionValue = 2346;
std::promise<void> promise;
auto future = promise.get_future();
@@ -149,7 +150,7 @@ TYPED_TEST(SdbusTestObject, CancelsAsynchronousPropertySettingViaPropertiesInter
TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture)
{
uint32_t newActionValue = 2347;
uint32_t const newActionValue = 2347;
auto future = this->m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, sdbus::with_future);
@@ -204,7 +205,7 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfac
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const sdbus::InterfaceName& interfaceName
, const std::map<sdbus::PropertyName, sdbus::Variant>& changedProperties
, const std::vector<sdbus::PropertyName>& /*invalidatedProperties*/ )
@@ -222,9 +223,9 @@ TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
ASSERT_TRUE(waitUntil(signalReceived));
}
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) // NOLINT(readability-function-cognitive-complexity)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const sdbus::InterfaceName& interfaceName
, const std::map<sdbus::PropertyName, sdbus::Variant>& changedProperties
, const std::vector<sdbus::PropertyName>& invalidatedProperties )
@@ -270,7 +271,7 @@ TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronously)
auto future = promise.get_future();
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
this->m_objectManagerProxy->GetManagedObjectsAsync([&](std::optional<sdbus::Error> /*err*/, const std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>>& objectsInterfacesAndProperties)
this->m_objectManagerProxy->GetManagedObjectsAsync([&](const std::optional<sdbus::Error>& /*err*/, const std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>>& objectsInterfacesAndProperties)
{
promise.set_value(objectsInterfacesAndProperties.size());
});
@@ -284,7 +285,7 @@ TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronouslyViaSlotReturningOver
auto future = promise.get_future();
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
auto slot = this->m_objectManagerProxy->GetManagedObjectsAsync([&](std::optional<sdbus::Error> /*err*/, const std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>>& objectsInterfacesAndProperties)
auto slot = this->m_objectManagerProxy->GetManagedObjectsAsync([&](const std::optional<sdbus::Error>& /*err*/, const std::map<sdbus::ObjectPath, std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>>& objectsInterfacesAndProperties)
{
promise.set_value(objectsInterfacesAndProperties.size());
}, sdbus::return_slot);
@@ -301,9 +302,10 @@ TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronouslyViaFutureOverload)
ASSERT_THAT(future.get().size(), Eq(2));
}
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) // NOLINT(readability-function-cognitive-complexity)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>& interfacesAndProperties )
{
@@ -334,9 +336,9 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterface
ASSERT_TRUE(waitUntil(signalReceived));
}
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) // NOLINT(readability-function-cognitive-complexity)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>& interfacesAndProperties )
{
@@ -374,7 +376,7 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<sdbus::InterfaceName>& interfaces )
{
@@ -391,7 +393,7 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfa
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
std::atomic signalReceived{false};
this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<sdbus::InterfaceName>& interfaces )
{
+9 -8
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Defs.h
*
@@ -32,7 +32,7 @@
#include <ostream>
#include <filesystem>
namespace sdbus { namespace test {
namespace sdbus::test {
const InterfaceName INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
const ServiceName SERVICE_NAME{"org.sdbuscpp.integrationtests"};
@@ -64,18 +64,19 @@ const bool DEFAULT_BLOCKING_VALUE{true};
constexpr const double DOUBLE_VALUE{3.24L};
}}
} // namespace sdbus::test
namespace testing::internal {
// Printer for std::chrono::duration types.
// This is a workaround, since it's not a good thing to add this to std namespace.
template< class Rep, class Period >
void PrintTo(const ::std::chrono::duration<Rep, Period>& d, ::std::ostream* os) {
auto seconds = std::chrono::duration_cast<std::chrono::duration<double>>(d);
*os << seconds.count() << "s";
template<class Rep, class Period>
void PrintTo(const ::std::chrono::duration<Rep, Period>& duration, ::std::ostream* stream)
{
auto seconds = std::chrono::duration_cast<std::chrono::duration<double>>(duration);
*stream << seconds.count() << "s";
}
}
} // namespace testing::internal
#endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */
+49 -27
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestAdaptor.cpp
*
@@ -25,11 +25,28 @@
*/
#include "TestAdaptor.h"
#include "sdbus-c++/IConnection.h"
#include "sdbus-c++/Types.h"
#include "sdbus-c++/AdaptorInterfaces.h"
#include <cstdint>
#include "Defs.h"
#include <string>
#include <map>
#include <array>
#include <memory>
#include "sdbus-c++/Message.h"
#include "sdbus-c++/MethodResult.h"
#include "sdbus-c++/Error.h"
#include <thread>
#include <chrono>
#include <atomic>
#include <utility>
#include <tuple>
#include <vector>
#include <variant>
#include <unordered_map>
namespace sdbus { namespace test {
namespace sdbus::test {
TestAdaptor::TestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path) :
AdaptorInterfaces(connection, std::move(path))
@@ -56,37 +73,37 @@ std::tuple<uint32_t, std::string> TestAdaptor::getTuple()
return std::make_tuple(UINT32_VALUE, STRING_VALUE);
}
double TestAdaptor::multiply(const int64_t& a, const double& b)
double TestAdaptor::multiply(const int64_t& lhs, const double& rhs)
{
return a * b;
return lhs * rhs; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
}
void TestAdaptor::multiplyWithNoReply(const int64_t& a, const double& b)
void TestAdaptor::multiplyWithNoReply(const int64_t& lhs, const double& rhs)
{
m_multiplyResult = a * b;
m_multiplyResult = lhs * rhs; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
m_wasMultiplyCalled = true;
}
std::vector<int16_t> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
std::vector<int16_t> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& strct)
{
std::vector<int16_t> res{x.get<1>()};
auto y = std::get<std::vector<int16_t>>(x);
res.insert(res.end(), y.begin(), y.end());
std::vector res{strct.get<1>()};
auto vec = std::get<std::vector<int16_t>>(strct);
res.insert(res.end(), vec.begin(), vec.end());
return res;
}
sdbus::Variant TestAdaptor::processVariant(const std::variant<int32_t, double, std::string>& v)
sdbus::Variant TestAdaptor::processVariant(const std::variant<int32_t, double, std::string>& var)
{
sdbus::Variant res{static_cast<int32_t>(std::get<double>(v))};
sdbus::Variant res{static_cast<int32_t>(std::get<double>(var))};
return res;
}
std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vector<int32_t>& vec, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& strct)
{
std::map<int32_t, sdbus::Variant> res;
for (auto item : x)
for (auto item : vec)
{
res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y);
res[item] = (item <= 0) ? std::get<0>(strct) : std::get<1>(strct);
}
return res;
}
@@ -96,24 +113,24 @@ sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> TestAdapto
return sdbus::Struct{STRING_VALUE, sdbus::Struct{std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}}};
}
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& strctA, const sdbus::Struct<int32_t, int64_t>& strctB)
{
int32_t res{0};
res += std::get<0>(a) + std::get<1>(a);
res += std::get<0>(b) + std::get<1>(b);
res += std::get<0>(strctA) + std::get<1>(strctA);
res += std::get<0>(strctB) + std::get<1>(strctB); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
return res;
}
uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& a, const std::array<uint64_t, 3>& b)
uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& vec, const std::array<uint64_t, 3>& arr)
{
uint32_t res{0};
for (auto x : a)
for (auto elem : vec)
{
res += x;
res += elem;
}
for (auto x : b)
for (auto elem : arr)
{
res += x;
res += elem;
}
return res;
}
@@ -289,12 +306,17 @@ void TestAdaptor::blocking(const bool& value)
m_blocking = value;
}
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct)
{
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(s);
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(strct);
}
std::string TestAdaptor::getExpectedXmlApiDescription() const
void TestAdaptor::emitSignalWithErrorAndTypeMismatch()
{
getObject().emitSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME);
}
std::string TestAdaptor::getExpectedXmlApiDescription()
{
return
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
@@ -472,4 +494,4 @@ R"delimiter(
)delimiter";
}
}}
} // namespace sdbus::test
+24 -14
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestAdaptor.h
*
@@ -35,7 +35,7 @@
#include <utility>
#include <memory>
namespace sdbus { namespace test {
namespace sdbus::test {
class ObjectManagerTestAdaptor final : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
{
@@ -46,6 +46,11 @@ public:
registerAdaptor();
}
ObjectManagerTestAdaptor(const ObjectManagerTestAdaptor&) = delete;
ObjectManagerTestAdaptor& operator=(const ObjectManagerTestAdaptor&) = delete;
ObjectManagerTestAdaptor(ObjectManagerTestAdaptor&&) = delete;
ObjectManagerTestAdaptor& operator=(ObjectManagerTestAdaptor&&) = delete;
~ObjectManagerTestAdaptor()
{
unregisterAdaptor();
@@ -58,24 +63,28 @@ class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integr
{
public:
TestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path);
TestAdaptor(const TestAdaptor&) = delete;
TestAdaptor& operator=(const TestAdaptor&) = delete;
TestAdaptor(TestAdaptor&&) = delete;
TestAdaptor& operator=(TestAdaptor&&) = delete;
~TestAdaptor();
protected:
void noArgNoReturn() override;
int32_t getInt() override;
std::tuple<uint32_t, std::string> getTuple() override;
double multiply(const int64_t& a, const double& b) override;
void multiplyWithNoReply(const int64_t& a, const double& b) override;
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) override;
double multiply(const int64_t& lhs, const double& rhs) override;
void multiplyWithNoReply(const int64_t& lhs, const double& rhs) override;
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& strct) override;
sdbus::Variant processVariant(const std::variant<int32_t, double, std::string>& variant) override;
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) override;
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& vec, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& strct) override;
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override;
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) override;
uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1) override;
uint32_t doOperation(const uint32_t& arg0) override;
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& strctA, const sdbus::Struct<int32_t, int64_t>& strctB) override;
uint32_t sumArrayItems(const std::vector<uint16_t>& vec, const std::array<uint64_t, 3>& arr) override;
uint32_t doOperation(const uint32_t& param) override;
std::map<int32_t, std::string> doOperationWithLargeData(const std::map<int32_t, std::string>& largeParam) override;
void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) override;
void doOperationAsyncWithLargeData(sdbus::Result<std::map<int32_t, std::string>>&& result, uint32_t arg0, const std::map<int32_t, std::string>& largeParam) override;
void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t param) override;
void doOperationAsyncWithLargeData(sdbus::Result<std::map<int32_t, std::string>>&& result, uint32_t param, const std::map<int32_t, std::string>& largeMap) override;
sdbus::Signature getSignature() override;
sdbus::ObjectPath getObjPath() override;
sdbus::UnixFd getUnixFd() override;
@@ -96,8 +105,9 @@ protected:
std::string state() override;
public:
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
std::string getExpectedXmlApiDescription() const;
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct);
void emitSignalWithErrorAndTypeMismatch();
static std::string getExpectedXmlApiDescription() ;
private:
const std::string m_state{DEFAULT_STATE_VALUE};
@@ -162,6 +172,6 @@ protected:
std::string state() override { return {}; }
};
}}
} // namespace sdbus::test
#endif /* INTEGRATIONTESTS_TESTADAPTOR_H_ */
+6 -3
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestFixture.cpp
*
@@ -25,8 +25,11 @@
*/
#include "TestFixture.h"
#include <memory>
#include "sdbus-c++/IConnection.h"
#include <thread>
namespace sdbus { namespace test {
namespace sdbus::test {
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_adaptorConnection = sdbus::createBusConnection();
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_proxyConnection = sdbus::createBusConnection();
@@ -41,4 +44,4 @@ int TestFixture<SdEventLoop>::s_eventExitFd{-1};
#endif // SDBUS_basu
}}
} // namespace sdbus::test
+36 -36
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestFixture.h
*
@@ -41,26 +41,25 @@
#include <thread>
#include <chrono>
#include <atomic>
#include <chrono>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
namespace sdbus { namespace test {
namespace sdbus::test {
inline const uint32_t ANY_UNSIGNED_NUMBER{123};
class BaseTestFixture : public ::testing::Test
{
public:
static void SetUpTestCase()
static void SetUpTestSuite()
{
s_adaptorConnection->requestName(SERVICE_NAME);
}
static void TearDownTestCase()
static void TearDownTestSuite()
{
s_adaptorConnection->releaseName(SERVICE_NAME);
}
@@ -93,7 +92,7 @@ public:
struct SdBusCppLoop{};
struct SdEventLoop{};
template <typename _EventLoop>
template <typename EventLoop>
class TestFixture : public BaseTestFixture{};
// Fixture working upon internal sdbus-c++ event loop
@@ -101,17 +100,17 @@ template <>
class TestFixture<SdBusCppLoop> : public BaseTestFixture
{
public:
static void SetUpTestCase()
static void SetUpTestSuite()
{
BaseTestFixture::SetUpTestCase();
BaseTestFixture::SetUpTestSuite();
s_proxyConnection->enterEventLoopAsync();
s_adaptorConnection->enterEventLoopAsync();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
}
static void TearDownTestCase()
static void TearDownTestSuite()
{
BaseTestFixture::TearDownTestCase();
BaseTestFixture::TearDownTestSuite();
s_adaptorConnection->leaveEventLoop();
s_proxyConnection->leaveEventLoop();
}
@@ -124,7 +123,7 @@ template <>
class TestFixture<SdEventLoop> : public BaseTestFixture
{
public:
static void SetUpTestCase()
static void SetUpTestSuite()
{
sd_event_new(&s_adaptorSdEvent);
sd_event_new(&s_proxySdEvent);
@@ -133,7 +132,7 @@ public:
s_proxyConnection->attachSdEventLoop(s_proxySdEvent);
s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
auto exitHandler = [](sd_event_source *s, auto...){ return sd_event_exit(sd_event_source_get_event(s), 0); };
auto exitHandler = [](sd_event_source *src, auto...){ return sd_event_exit(sd_event_source_get_event(src), 0); };
sd_event_add_io(s_adaptorSdEvent, nullptr, s_eventExitFd, EPOLLIN, exitHandler, nullptr);
sd_event_add_io(s_proxySdEvent, nullptr, s_eventExitFd, EPOLLIN, exitHandler, nullptr);
@@ -146,11 +145,11 @@ public:
sd_event_loop(s_proxySdEvent);
});
BaseTestFixture::SetUpTestCase();
BaseTestFixture::SetUpTestSuite();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
}
static void TearDownTestCase()
static void TearDownTestSuite()
{
(void)eventfd_write(s_eventExitFd, 1);
@@ -161,7 +160,7 @@ public:
sd_event_unref(s_proxySdEvent);
close(s_eventExitFd);
BaseTestFixture::TearDownTestCase();
BaseTestFixture::TearDownTestSuite();
}
private:
@@ -172,24 +171,24 @@ private:
static int s_eventExitFd;
};
typedef ::testing::Types<SdBusCppLoop, SdEventLoop> EventLoopTags;
using EventLoopTags = ::testing::Types<SdBusCppLoop, SdEventLoop>;
#else // SDBUS_basu
typedef ::testing::Types<SdBusCppLoop> EventLoopTags;
using EventLoopTags = ::testing::Types<SdBusCppLoop>;
#endif // SDBUS_basu
TYPED_TEST_SUITE(TestFixture, EventLoopTags);
template <typename _EventLoop>
using SdbusTestObject = TestFixture<_EventLoop>;
template <typename EventLoop>
using SdbusTestObject = TestFixture<EventLoop>;
TYPED_TEST_SUITE(SdbusTestObject, EventLoopTags);
template <typename _EventLoop>
using AsyncSdbusTestObject = TestFixture<_EventLoop>;
template <typename EventLoop>
using AsyncSdbusTestObject = TestFixture<EventLoop>;
TYPED_TEST_SUITE(AsyncSdbusTestObject, EventLoopTags);
template <typename _EventLoop>
using AConnection = TestFixture<_EventLoop>;
template <typename EventLoop>
using AConnection = TestFixture<EventLoop>;
TYPED_TEST_SUITE(AConnection, EventLoopTags);
class TestFixtureWithDirectConnection : public ::testing::Test
@@ -197,7 +196,7 @@ class TestFixtureWithDirectConnection : public ::testing::Test
private:
void SetUp() override
{
int sock = openUnixSocket();
const int sock = openUnixSocket();
createClientAndServerConnections(sock);
createAdaptorAndProxyObjects();
}
@@ -212,18 +211,19 @@ private:
static int openUnixSocket()
{
int sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
const int sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
assert(sock >= 0);
sockaddr_un sa;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", DIRECT_CONNECTION_SOCKET_PATH.c_str());
sockaddr_un saddr{};
memset(&saddr, 0, sizeof(saddr));
saddr.sun_family = AF_UNIX;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
(void)snprintf(saddr.sun_path, sizeof(saddr.sun_path), "%s", DIRECT_CONNECTION_SOCKET_PATH.c_str());
unlink(DIRECT_CONNECTION_SOCKET_PATH.c_str());
umask(0000);
[[maybe_unused]] int r = bind(sock, (const sockaddr*) &sa, sizeof(sa.sun_path));
[[maybe_unused]] int r = bind(sock, reinterpret_cast<const sockaddr*>(&saddr), sizeof(saddr.sun_path));
assert(r >= 0);
r = listen(sock, 5);
@@ -236,7 +236,7 @@ private:
{
std::thread t([&]()
{
auto fd = accept4(sock, NULL, NULL, /*SOCK_NONBLOCK|*/SOCK_CLOEXEC);
auto fd = accept4(sock, nullptr, nullptr, /*SOCK_NONBLOCK|*/SOCK_CLOEXEC);
m_adaptorConnection = sdbus::createServerBus(fd);
// This is necessary so that createDirectBusConnection() below does not block
m_adaptorConnection->enterEventLoopAsync();
@@ -265,14 +265,14 @@ public:
std::unique_ptr<TestProxy> m_proxy;
};
template <typename _Fnc>
inline bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
template <typename Fnc>
inline bool waitUntil(const Fnc& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
using namespace std::chrono_literals;
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
const std::chrono::milliseconds step{5ms};
do { // NOLINT(cppcoreguidelines-avoid-do-while)
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
@@ -287,6 +287,6 @@ inline bool waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout
return waitUntil([&flag]() -> bool { return flag; }, timeout);
}
}}
} // namespace sdbus::test
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */
+64 -14
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestProxy.cpp
*
@@ -25,16 +25,27 @@
*/
#include "TestProxy.h"
#include <thread>
#include <sdbus-c++/sdbus-c++.h>
#include "Defs.h"
#include <string>
#include <memory>
#include <map>
#include <cstdint>
#include <optional>
#include <functional>
#include <future>
#include <chrono>
#include <atomic>
#include <utility>
#include <vector>
namespace sdbus { namespace test {
namespace sdbus::test {
TestProxy::TestProxy(ServiceName destination, ObjectPath objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct){ this->onSignalWithoutRegistration(strct); });
getProxy().uponSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME).call([this](std::optional<sdbus::Error> err, int wrongParameter){ this->onSignalWithErrorAndTypeMismatch(std::move(err), wrongParameter); });
registerProxy();
}
@@ -49,7 +60,8 @@ TestProxy::TestProxy(ServiceName destination, ObjectPath objectPath, dont_run_ev
TestProxy::TestProxy(sdbus::IConnection& connection, ServiceName destination, ObjectPath objectPath)
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct){ this->onSignalWithoutRegistration(strct); });
getProxy().uponSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME).call([this](std::optional<sdbus::Error> err, int wrongParameter){ this->onSignalWithErrorAndTypeMismatch(std::move(err), wrongParameter); });
registerProxy();
}
@@ -79,17 +91,23 @@ void TestProxy::onSignalWithVariant(const sdbus::Variant& aVariant)
m_gotSignalWithVariant = true;
}
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct)
{
// Static cast to std::string is a workaround for gcc 11.4 false positive warning (which later gcc versions nor Clang emit)
m_signatureFromSignal[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
m_signatureFromSignal[std::get<0>(strct)] = static_cast<std::string>(std::get<0>(std::get<1>(strct)));
m_gotSignalWithSignature = true;
}
void TestProxy::onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error)
void TestProxy::onSignalWithErrorAndTypeMismatch(std::optional<sdbus::Error> err, [[maybe_unused]] int wrongParameter)
{
m_errorFromSignal = std::move(err);
m_gotSignalWithTypeMismatch = true;
}
void TestProxy::onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const
{
if (m_DoOperationClientSideAsyncReplyHandler)
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
m_DoOperationClientSideAsyncReplyHandler(returnValue, std::move(error));
}
void TestProxy::onPropertiesChanged( const sdbus::InterfaceName& interfaceName
@@ -108,7 +126,7 @@ void TestProxy::installDoOperationClientSideAsyncReplyHandler(std::function<void
uint32_t TestProxy::doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
{
using namespace std::chrono_literals;
uint32_t result;
uint32_t result = 0;
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(timeout).withArguments(param).storeResultsTo(result);
return result;
}
@@ -186,6 +204,38 @@ std::future<void> TestProxy::doErroneousOperationClientSideAsync(with_future_t)
.getResultAsFuture<>();
}
sdbus::Awaitable<uint32_t> TestProxy::doOperationClientSideAsync(uint32_t param, sdbus::with_awaitable_t)
{
return getProxy().callMethodAsync("doOperation")
.onInterface(sdbus::test::INTERFACE_NAME)
.withArguments(param)
.getResultAsAwaitable<uint32_t>();
}
sdbus::Awaitable<std::map<int32_t, std::string>> TestProxy::doOperationWithLargeDataClientSideAsync(const std::map<int32_t, std::string>& largeParam, sdbus::with_awaitable_t)
{
return getProxy().callMethodAsync("doOperationWithLargeData")
.onInterface(sdbus::test::INTERFACE_NAME)
.withArguments(largeParam)
.getResultAsAwaitable<std::map<int32_t, std::string>>();
}
sdbus::Awaitable<MethodReply> TestProxy::doOperationClientSideAsyncOnBasicAPILevel(uint32_t param, sdbus::with_awaitable_t)
{
auto methodCall = getProxy().createMethodCall(sdbus::test::INTERFACE_NAME, sdbus::MethodName{"doOperation"});
methodCall << param;
return getProxy().callMethodAsync(methodCall, sdbus::with_awaitable);
}
sdbus::Awaitable<void> TestProxy::doErroneousOperationClientSideAsync(sdbus::with_awaitable_t)
{
return getProxy().callMethodAsync("throwError")
.onInterface(sdbus::test::INTERFACE_NAME)
.getResultAsAwaitable<>();
}
void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
{
using namespace std::chrono_literals;
@@ -201,15 +251,15 @@ void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microse
int32_t TestProxy::callNonexistentMethod()
{
int32_t result;
int32_t result = 0;
getProxy().callMethod("callNonexistentMethod").onInterface(sdbus::test::INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t TestProxy::callMethodOnNonexistentInterface()
{
sdbus::InterfaceName nonexistentInterfaceName{"sdbuscpp.interface.that.does.not.exist"};
int32_t result;
sdbus::InterfaceName const nonexistentInterfaceName{"sdbuscpp.interface.that.does.not.exist"};
int32_t result = 0;
getProxy().callMethod("someMethod").onInterface(nonexistentInterfaceName).storeResultsTo(result);
return result;
}
@@ -219,4 +269,4 @@ void TestProxy::setStateProperty(const std::string& value)
getProxy().setProperty("state").onInterface(sdbus::test::INTERFACE_NAME).toValue(value);
}
}}
} // namespace sdbus::test
+25 -10
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TestProxy.h
*
@@ -35,7 +35,7 @@
#include <future>
#include <memory>
namespace sdbus { namespace test {
namespace sdbus::test {
class ObjectManagerTestProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
{
@@ -46,6 +46,11 @@ public:
registerProxy();
}
ObjectManagerTestProxy(const ObjectManagerTestProxy&) = delete;
ObjectManagerTestProxy& operator=(const ObjectManagerTestProxy&) = delete;
ObjectManagerTestProxy(ObjectManagerTestProxy&&) = delete;
ObjectManagerTestProxy& operator=(ObjectManagerTestProxy&&) = delete;
~ObjectManagerTestProxy()
{
unregisterProxy();
@@ -77,6 +82,10 @@ public:
TestProxy(ServiceName destination, ObjectPath objectPath);
TestProxy(ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t);
TestProxy(sdbus::IConnection& connection, ServiceName destination, ObjectPath objectPath);
TestProxy(const TestProxy&) = delete;
TestProxy& operator=(const TestProxy&) = delete;
TestProxy(TestProxy&&) = delete;
TestProxy& operator=(TestProxy&&) = delete;
~TestProxy();
protected:
@@ -84,8 +93,9 @@ protected:
void onSignalWithMap(const std::map<int32_t, std::string>& aMap) override;
void onSignalWithVariant(const sdbus::Variant& aVariant) override;
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
void onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error);
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct);
void onSignalWithErrorAndTypeMismatch(std::optional<sdbus::Error> err, int wrongParameter);
void onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const;
// Signals of standard D-Bus interfaces
void onPropertiesChanged( const sdbus::InterfaceName& interfaceName
@@ -102,22 +112,27 @@ public:
std::future<std::map<int32_t, std::string>> doOperationWithLargeDataClientSideAsync(const std::map<int32_t, std::string>& largeParam, with_future_t);
std::future<MethodReply> doOperationClientSideAsyncOnBasicAPILevel(uint32_t param);
std::future<void> doErroneousOperationClientSideAsync(with_future_t);
sdbus::Awaitable<uint32_t> doOperationClientSideAsync(uint32_t param, sdbus::with_awaitable_t);
sdbus::Awaitable<std::map<int32_t, std::string>> doOperationWithLargeDataClientSideAsync(const std::map<int32_t, std::string>& largeParam, sdbus::with_awaitable_t);
sdbus::Awaitable<MethodReply> doOperationClientSideAsyncOnBasicAPILevel(uint32_t param, sdbus::with_awaitable_t);
sdbus::Awaitable<void> doErroneousOperationClientSideAsync(sdbus::with_awaitable_t);
void doErroneousOperationClientSideAsync();
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
int32_t callNonexistentMethod();
int32_t callMethodOnNonexistentInterface();
void setStateProperty(const std::string& value);
//private:
public: // for tests
//private: (Kept public for tests)
int m_SimpleSignals = 0;
std::atomic<bool> m_gotSimpleSignal{false};
std::atomic<bool> m_gotSignalWithMap{false};
std::map<int32_t, std::string> m_mapFromSignal;
std::atomic<bool> m_gotSignalWithVariant{false};
double m_variantFromSignal;
double m_variantFromSignal{};
std::atomic<bool> m_gotSignalWithSignature{false};
std::map<std::string, Signature> m_signatureFromSignal;
std::atomic<bool> m_gotSignalWithTypeMismatch{false};
std::optional<sdbus::Error> m_errorFromSignal;
std::function<void(uint32_t res, std::optional<sdbus::Error> err)> m_DoOperationClientSideAsyncReplyHandler;
std::function<void(const sdbus::InterfaceName&, const std::map<PropertyName, sdbus::Variant>&, const std::vector<PropertyName>&)> m_onPropertiesChangedHandler;
@@ -134,7 +149,7 @@ class DummyTestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integ
{
public:
DummyTestProxy(ServiceName destination, ObjectPath objectPath)
: ProxyInterfaces(destination, objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
}
@@ -144,12 +159,12 @@ protected:
void onSignalWithVariant(const sdbus::Variant&) override {}
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>&) {}
void onDoOperationReply(uint32_t, std::optional<sdbus::Error>) {}
void onDoOperationReply(uint32_t, const std::optional<sdbus::Error>&) {}
// Signals of standard D-Bus interfaces
void onPropertiesChanged(const InterfaceName&, const std::map<PropertyName, sdbus::Variant>&, const std::vector<PropertyName>&) override {}
};
}}
} // namespace sdbus::test
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file sdbus-c++-integration-tests.cpp
*
+37 -25
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file client.cpp
*
@@ -25,20 +25,22 @@
*/
#include "perftests-proxy.h"
#include <cstdint>
#include <cstddef>
#include <cstdlib>
#include <ctime>
#include <sdbus-c++/sdbus-c++.h>
#include <vector>
#include <utility>
#include <string>
#include <iostream>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <cassert>
#include <algorithm>
#include <iostream>
using namespace std::chrono_literals;
uint64_t totalDuration = 0;
uint64_t totalDuration = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
class PerftestProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::perftests_proxy>
{
@@ -49,13 +51,18 @@ public:
registerProxy();
}
PerftestProxy(const PerftestProxy&) = delete;
PerftestProxy& operator=(const PerftestProxy&) = delete;
PerftestProxy(PerftestProxy&&) = delete;
PerftestProxy& operator=(PerftestProxy&&) = delete;
~PerftestProxy()
{
unregisterProxy();
}
protected:
virtual void onDataSignal([[maybe_unused]] const std::string& data) override
void onDataSignal([[maybe_unused]] const std::string& data) override
{
static unsigned int counter = 0;
static std::chrono::time_point<std::chrono::steady_clock> startTime;
@@ -71,7 +78,7 @@ protected:
auto stopTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
totalDuration += duration;
std::cout << "Received " << m_msgCount << " signals in: " << duration << " ms" << std::endl;
std::cout << "Received " << m_msgCount << " signals in: " << duration << " ms" << '\n';
counter = 0;
}
}
@@ -90,8 +97,13 @@ std::string createRandomString(size_t length)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
return charset[ random() % max_index ];
};
struct timespec ts{};
(void)timespec_get(&ts, TIME_UTC);
srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
@@ -106,44 +118,44 @@ int main(int /*argc*/, char */*argv*/[])
PerftestProxy client(std::move(destination), std::move(objectPath));
const unsigned int repetitions{20};
unsigned int msgCount = 1000;
unsigned int const msgCount = 1000;
unsigned int msgSize{};
msgSize = 20;
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
for (unsigned int r = 0; r < repetitions; ++r)
for (unsigned int i = 0; i < repetitions; ++i)
{
client.sendDataSignals(msgCount, msgSize);
std::this_thread::sleep_for(1000ms);
}
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
totalDuration = 0;
msgSize = 1000;
std::cout << std::endl << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
std::cout << '\n' << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
for (unsigned int r = 0; r < repetitions; ++r)
for (unsigned int i = 0; i < repetitions; ++i)
{
client.sendDataSignals(msgCount, msgSize);
std::this_thread::sleep_for(1000ms);
}
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
totalDuration = 0;
msgSize = 20;
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
for (unsigned int r = 0; r < repetitions; ++r)
std::cout << '\n' << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
for (unsigned int i = 0; i < repetitions; ++i)
{
auto str1 = createRandomString(msgSize/2);
auto str2 = createRandomString(msgSize/2);
auto startTime = std::chrono::steady_clock::now();
for (unsigned int i = 0; i < msgCount; i++)
for (unsigned int j = 0; j < msgCount; j++)
{
auto result = client.concatenateTwoStrings(str1, str2);
@@ -153,23 +165,23 @@ int main(int /*argc*/, char */*argv*/[])
auto stopTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
totalDuration += duration;
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << '\n';
std::this_thread::sleep_for(1000ms);
}
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
totalDuration = 0;
msgSize = 1000;
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
for (unsigned int r = 0; r < repetitions; ++r)
std::cout << '\n' << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
for (unsigned int i = 0; i < repetitions; ++i)
{
auto str1 = createRandomString(msgSize/2);
auto str2 = createRandomString(msgSize/2);
auto startTime = std::chrono::steady_clock::now();
for (unsigned int i = 0; i < msgCount; i++)
for (unsigned int j = 0; j < msgCount; j++)
{
auto result = client.concatenateTwoStrings(str1, str2);
@@ -179,12 +191,12 @@ int main(int /*argc*/, char */*argv*/[])
auto stopTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
totalDuration += duration;
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << '\n';
std::this_thread::sleep_for(1000ms);
}
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
totalDuration = 0;
return 0;
+22 -9
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file server.cpp
*
@@ -25,10 +25,13 @@
*/
#include "perftests-adaptor.h"
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <sdbus-c++/sdbus-c++.h>
#include <vector>
#include <utility>
#include <string>
#include <thread>
#include <chrono>
#include <algorithm>
#include <iostream>
@@ -46,13 +49,18 @@ public:
registerAdaptor();
}
PerftestAdaptor(const PerftestAdaptor&) = delete;
PerftestAdaptor& operator=(const PerftestAdaptor&) = delete;
PerftestAdaptor(PerftestAdaptor&&) = delete;
PerftestAdaptor& operator=(PerftestAdaptor&&) = delete;
~PerftestAdaptor()
{
unregisterAdaptor();
}
protected:
virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override // NOLINT(bugprone-easily-swappable-parameters)
{
auto data = createRandomString(signalMsgSize);
@@ -63,10 +71,10 @@ protected:
emitDataSignal(data);
}
auto stop_time = std::chrono::steady_clock::now();
std::cout << "Server sent " << numberOfSignals << " signals in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count() << " ms" << std::endl;
std::cout << "Server sent " << numberOfSignals << " signals in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count() << " ms" << '\n';
}
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override
std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override
{
return string1 + string2;
}
@@ -81,8 +89,13 @@ std::string createRandomString(size_t length)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
return charset[ random() % max_index ];
};
struct timespec ts{};
(void)timespec_get(&ts, TIME_UTC);
srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
@@ -92,11 +105,11 @@ std::string createRandomString(size_t length)
//-----------------------------------------
int main(int /*argc*/, char */*argv*/[])
{
sdbus::ServiceName serviceName{"org.sdbuscpp.perftests"};
sdbus::ServiceName const serviceName{"org.sdbuscpp.perftests"};
auto connection = sdbus::createSystemBusConnection(serviceName);
sdbus::ObjectPath objectPath{"/org/sdbuscpp/perftests"};
PerftestAdaptor server(*connection, std::move(objectPath));
PerftestAdaptor server(*connection, std::move(objectPath)); // NOLINT(misc-const-correctness)
connection->enterEventLoop();
}
+70 -31
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file sdbus-c++-stress-tests.cpp
*
@@ -34,16 +34,22 @@
#include <vector>
#include <string>
#include <iostream>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <cassert>
#include <cstdlib>
#include <cstdint>
#include <cstddef>
#include <atomic>
#include <sstream>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <memory>
#include <utility>
#include <map>
#include <optional>
#include <stdexcept>
using namespace std::chrono_literals;
@@ -62,13 +68,18 @@ public:
registerAdaptor();
}
CelsiusThermometerAdaptor(const CelsiusThermometerAdaptor&) = delete;
CelsiusThermometerAdaptor& operator=(const CelsiusThermometerAdaptor&) = delete;
CelsiusThermometerAdaptor(CelsiusThermometerAdaptor&&) = delete;
CelsiusThermometerAdaptor& operator=(CelsiusThermometerAdaptor&&) = delete;
~CelsiusThermometerAdaptor()
{
unregisterAdaptor();
}
protected:
virtual uint32_t getCurrentTemperature() override
uint32_t getCurrentTemperature() override
{
return m_currentTemperature++;
}
@@ -86,6 +97,11 @@ public:
registerProxy();
}
CelsiusThermometerProxy(const CelsiusThermometerProxy&) = delete;
CelsiusThermometerProxy& operator=(const CelsiusThermometerProxy&) = delete;
CelsiusThermometerProxy(CelsiusThermometerProxy&&) = delete;
CelsiusThermometerProxy& operator=(CelsiusThermometerProxy&&) = delete;
~CelsiusThermometerProxy()
{
unregisterProxy();
@@ -142,7 +158,7 @@ public:
{
// Destroy existing delegate object
// Here we are testing dynamic removal of a D-Bus object in an async way
std::lock_guard<std::mutex> lock{childrenMutex_};
const std::lock_guard lock{childrenMutex_};
children_.erase(request.delegateObjectPath);
}
}
@@ -152,6 +168,11 @@ public:
registerAdaptor();
}
FahrenheitThermometerAdaptor(const FahrenheitThermometerAdaptor&) = delete;
FahrenheitThermometerAdaptor& operator=(const FahrenheitThermometerAdaptor&) = delete;
FahrenheitThermometerAdaptor(FahrenheitThermometerAdaptor&&) = delete;
FahrenheitThermometerAdaptor& operator=(FahrenheitThermometerAdaptor&&) = delete;
~FahrenheitThermometerAdaptor()
{
exit_ = true;
@@ -163,13 +184,13 @@ public:
}
protected:
virtual uint32_t getCurrentTemperature() override
uint32_t getCurrentTemperature() override
{
// In this D-Bus call, make yet another D-Bus call to another service over the same connection
return static_cast<uint32_t>(celsiusProxy_.getCurrentTemperature() * 1.8 + 32.);
}
virtual void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) override
void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) override
{
static size_t objectCounter{};
objectCounter++;
@@ -180,7 +201,7 @@ protected:
cond_.notify_one();
}
virtual void destroyDelegateObject(sdbus::Result<>&& /*result*/, sdbus::ObjectPath delegate) override
void destroyDelegateObject(sdbus::Result<>&& /*result*/, sdbus::ObjectPath delegate) override
{
std::unique_lock<std::mutex> lock(mutex_);
requests_.push(WorkItem{0, std::move(delegate), {}});
@@ -203,7 +224,7 @@ private:
std::condition_variable cond_;
std::queue<WorkItem> requests_;
std::vector<std::thread> workers_;
std::atomic<bool> exit_{};
std::atomic<bool> exit_;
};
class FahrenheitThermometerProxy : public sdbus::ProxyInterfaces< org::sdbuscpp::stresstests::fahrenheit::thermometer_proxy
@@ -216,6 +237,11 @@ public:
registerProxy();
}
FahrenheitThermometerProxy(const FahrenheitThermometerProxy&) = delete;
FahrenheitThermometerProxy& operator=(const FahrenheitThermometerProxy&) = delete;
FahrenheitThermometerProxy(FahrenheitThermometerProxy&&) = delete;
FahrenheitThermometerProxy& operator=(FahrenheitThermometerProxy&&) = delete;
~FahrenheitThermometerProxy()
{
unregisterProxy();
@@ -262,6 +288,11 @@ public:
registerAdaptor();
}
ConcatenatorAdaptor(const ConcatenatorAdaptor&) = delete;
ConcatenatorAdaptor& operator=(const ConcatenatorAdaptor&) = delete;
ConcatenatorAdaptor(ConcatenatorAdaptor&&) = delete;
ConcatenatorAdaptor& operator=(ConcatenatorAdaptor&&) = delete;
~ConcatenatorAdaptor()
{
exit_ = true;
@@ -273,7 +304,7 @@ public:
}
protected:
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) override
void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) override
{
std::unique_lock<std::mutex> lock(mutex_);
requests_.push(WorkItem{std::move(params), std::move(result)});
@@ -291,7 +322,7 @@ private:
std::condition_variable cond_;
std::queue<WorkItem> requests_;
std::vector<std::thread> workers_;
std::atomic<bool> exit_{};
std::atomic<bool> exit_;
};
class ConcatenatorProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::concatenator_proxy>
@@ -303,13 +334,18 @@ public:
registerProxy();
}
ConcatenatorProxy(const ConcatenatorProxy&) = delete;
ConcatenatorProxy& operator=(const ConcatenatorProxy&) = delete;
ConcatenatorProxy(ConcatenatorProxy&&) = delete;
ConcatenatorProxy& operator=(ConcatenatorProxy&&) = delete;
~ConcatenatorProxy()
{
unregisterProxy();
}
private:
virtual void onConcatenateReply(const std::string& result, [[maybe_unused]] std::optional<sdbus::Error> error) override
void onConcatenateReply(const std::string& result, [[maybe_unused]] std::optional<sdbus::Error> error) override
{
assert(error == std::nullopt);
@@ -318,21 +354,21 @@ private:
str >> aString;
assert(aString == "sdbus-c++-stress-tests");
uint32_t aNumber;
uint32_t aNumber{};
str >> aNumber;
assert(aNumber > 0);
++repliesReceived_;
}
virtual void onConcatenatedSignal(const std::string& concatenatedString) override
void onConcatenatedSignal(const std::string& concatenatedString) override
{
std::stringstream str(concatenatedString);
std::string aString;
str >> aString;
assert(aString == "sdbus-c++-stress-tests");
uint32_t aNumber;
uint32_t aNumber{};
str >> aNumber;
assert(aNumber > 0);
@@ -340,15 +376,15 @@ private:
}
public:
std::atomic<uint32_t> repliesReceived_{};
std::atomic<uint32_t> signalsReceived_{};
std::atomic<uint32_t> repliesReceived_;
std::atomic<uint32_t> signalsReceived_;
};
//-----------------------------------------
int main(int argc, char *argv[])
int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape, readability-function-cognitive-complexity)
{
long loops;
long loopDuration;
long loops{};
long loopDuration{};
if (argc == 1)
{
@@ -357,49 +393,52 @@ int main(int argc, char *argv[])
}
else if (argc == 3)
{
loops = std::atol(argv[1]);
loopDuration = std::atol(argv[2]);
loops = std::atol(argv[1]); // NOLINT(cert-err34-c, cppcoreguidelines-pro-bounds-pointer-arithmetic)
loopDuration = std::atol(argv[2]); // NOLINT(cert-err34-c, cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
else
throw std::runtime_error("Wrong program options");
std::cout << "Going on with " << loops << " loops and " << loopDuration << "ms loop duration" << std::endl;
std::cout << "Going on with " << loops << " loops and " << loopDuration << "ms loop duration\n";
std::atomic<uint32_t> concatenationCallsMade{0};
std::atomic<uint32_t> concatenationRepliesReceived{0};
std::atomic<uint32_t> concatenationSignalsReceived{0};
std::atomic<uint32_t> thermometerCallsMade{0};
std::atomic<bool> exitLogger{};
std::atomic exitLogger{false};
std::thread loggerThread([&]()
{
while (!exitLogger)
{
std::this_thread::sleep_for(1s);
std::cout << "Made " << concatenationCallsMade << " concatenation calls, received " << concatenationRepliesReceived << " replies and " << concatenationSignalsReceived << " signals so far." << std::endl;
std::cout << "Made " << thermometerCallsMade << " thermometer calls so far." << std::endl << std::endl;
std::cout << "Made " << concatenationCallsMade << " concatenation calls, received " << concatenationRepliesReceived << " replies and " << concatenationSignalsReceived << " signals so far.\n";
std::cout << "Made " << thermometerCallsMade << " thermometer calls so far.\n\n";
}
});
for (long loop = 0; loop < loops; ++loop)
{
std::cout << "Entering loop " << loop+1 << std::endl;
std::cout << "Entering loop " << loop+1 << '\n';
auto service2Connection = sdbus::createSystemBusConnection(SERVICE_2_BUS_NAME);
std::atomic<bool> service2ThreadReady{};
std::atomic service2ThreadReady{false};
std::thread service2Thread([&con = *service2Connection, &service2ThreadReady]()
{
// NOLINTNEXTLINE(misc-const-correctness)
CelsiusThermometerAdaptor thermometer(con, CELSIUS_THERMOMETER_OBJECT_PATH);
service2ThreadReady = true;
con.enterEventLoop();
});
auto service1Connection = sdbus::createSystemBusConnection(SERVICE_1_BUS_NAME);
std::atomic<bool> service1ThreadReady{};
std::atomic service1ThreadReady{false};
std::thread service1Thread([&con = *service1Connection, &service1ThreadReady]()
{
// NOLINTNEXTLINE(misc-const-correctness)
ConcatenatorAdaptor concatenator(con, CONCATENATOR_OBJECT_PATH);
// NOLINTNEXTLINE(misc-const-correctness)
FahrenheitThermometerAdaptor thermometer(con, FAHRENHEIT_THERMOMETER_OBJECT_PATH, false);
service1ThreadReady = true;
con.enterEventLoop();
@@ -415,7 +454,7 @@ int main(int argc, char *argv[])
bool clientThreadExit{};
std::thread clientThread([&, &con = *clientConnection]()
{
std::atomic<bool> stopClients{false};
std::atomic stopClients{false};
std::thread concatenatorThread([&]()
{
@@ -442,8 +481,8 @@ int main(int argc, char *argv[])
// Update statistics
concatenationCallsMade = localCounter;
concatenationRepliesReceived = (uint32_t)concatenator.repliesReceived_;
concatenationSignalsReceived = (uint32_t)concatenator.signalsReceived_;
concatenationRepliesReceived = static_cast<uint32_t>(concatenator.repliesReceived_);
concatenationSignalsReceived = static_cast<uint32_t>(concatenator.signalsReceived_);
}
}
});
+24 -16
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Connection_test.cpp
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -26,10 +26,16 @@
*/
#include "Connection.h"
#include "sdbus-c++/Error.h"
#include "sdbus-c++/Types.h"
#include "unittests/mocks/SdBusMock.h"
#include "mocks/SdBusMock.h"
#include <gtest/gtest.h>
#include <gtest/gtest.h> // IWYU pragma: export
#include <cerrno>
#include <memory>
#include <utility>
// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
using ::testing::_;
using ::testing::DoAll;
@@ -180,10 +186,10 @@ template<> void AConnectionNameRequest<Connection::pseudo_bus_t>::setUpBusOpenEx
// `sd_bus_start` for pseudo connection shall return an error value, remember this is a fake connection...
EXPECT_CALL(*sdBusIntfMock_, sd_bus_start(fakeBusPtr_)).WillOnce(Return(-EINVAL));
}
template <typename _BusTypeTag>
std::unique_ptr<Connection> AConnectionNameRequest<_BusTypeTag>::makeConnection()
template <typename BusTypeTag>
std::unique_ptr<Connection> AConnectionNameRequest<BusTypeTag>::makeConnection()
{
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), _BusTypeTag{});
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), BusTypeTag{});
}
template<> std::unique_ptr<Connection> AConnectionNameRequest<Connection::custom_session_bus_t>::makeConnection()
{
@@ -194,30 +200,32 @@ template<> std::unique_ptr<Connection> AConnectionNameRequest<Connection::remote
return std::make_unique<Connection>(std::unique_ptr<NiceMock<SdBusMock>>(sdBusIntfMock_), Connection::remote_system_bus, "some host");
}
typedef ::testing::Types< Connection::default_bus_t
, Connection::system_bus_t
, Connection::session_bus_t
, Connection::custom_session_bus_t
, Connection::remote_system_bus_t
, Connection::pseudo_bus_t
> BusTypeTags;
using BusTypeTags = ::testing::Types< Connection::default_bus_t
, Connection::system_bus_t
, Connection::session_bus_t
, Connection::custom_session_bus_t
, Connection::remote_system_bus_t
, Connection::pseudo_bus_t
>;
TYPED_TEST_SUITE(AConnectionNameRequest, BusTypeTags);
}
} // namespace
TYPED_TEST(AConnectionNameRequest, DoesNotThrowOnSuccess)
{
EXPECT_CALL(*this->sdBusIntfMock_, sd_bus_request_name(_, _, _)).WillOnce(Return(1));
sdbus::ConnectionName name{"org.sdbuscpp.somename"};
const sdbus::ConnectionName name{"org.sdbuscpp.somename"};
this->con_->requestName(name);
}
TYPED_TEST(AConnectionNameRequest, ThrowsOnFail)
{
sdbus::ConnectionName name{"org.sdbuscpp.somename"};
const sdbus::ConnectionName name{"org.sdbuscpp.somename"};
EXPECT_CALL(*this->sdBusIntfMock_, sd_bus_request_name(_, _, _)).WillOnce(Return(-1));
ASSERT_THROW(this->con_->requestName(name), sdbus::Error);
}
// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+60 -52
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Message_test.cpp
*
@@ -24,17 +24,25 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sdbus-c++/Error.h>
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Types.h>
#include "MessageUtils.h"
#include <sdbus-c++/TypeTraits.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <array>
#include <cstdint>
#include <list>
#include <map>
#include <span>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
using ::testing::Eq;
using ::testing::StrEq;
using ::testing::Gt;
using ::testing::DoubleEq;
using ::testing::IsNull;
using ::testing::SizeIs;
using ::testing::ElementsAre;
@@ -48,15 +56,15 @@ namespace
msg >> str;
return str;
}
}
} // namespace
namespace sdbus {
template <typename _ElementType>
sdbus::Message& operator<<(sdbus::Message& msg, const std::list<_ElementType>& items)
template <typename ElementType>
sdbus::Message& operator<<(sdbus::Message& msg, const std::list<ElementType>& items)
{
// TODO: This can also be simplified on the basis of a callback (see dictionary...)
msg.openContainer<_ElementType>();
msg.openContainer<ElementType>();
for (const auto& item : items)
msg << item;
@@ -66,15 +74,15 @@ namespace sdbus {
return msg;
}
template <typename _ElementType>
sdbus::Message& operator>>(sdbus::Message& msg, std::list<_ElementType>& items)
template <typename ElementType>
sdbus::Message& operator>>(sdbus::Message& msg, std::list<ElementType>& items)
{
if(!msg.enterContainer<_ElementType>())
if(!msg.enterContainer<ElementType>())
return msg;
while (true)
{
_ElementType elem;
ElementType elem;
if (msg >> elem)
items.emplace_back(std::move(elem));
else
@@ -88,15 +96,15 @@ namespace sdbus {
return msg;
}
}
} // namespace sdbus
template <typename _Element, typename _Allocator>
struct sdbus::signature_of<std::list<_Element, _Allocator>>
: sdbus::signature_of<std::vector<_Element, _Allocator>>
template <typename Element, typename Allocator>
struct sdbus::signature_of<std::list<Element, Allocator>>
: sdbus::signature_of<std::vector<Element, Allocator>>
{};
namespace my {
enum class Enum
enum class Enum : std::uint8_t
{
Value1,
Value2,
@@ -105,42 +113,42 @@ namespace my {
struct Struct
{
int i;
int i{};
std::string s;
std::list<double> l;
Enum e;
Enum e{};
friend bool operator==(const Struct& lhs, const Struct& rhs) = default;
};
struct RelaxedStruct
{
int i;
int i{};
std::string s;
std::list<double> l;
Enum e;
Enum e{};
friend bool operator==(const RelaxedStruct& lhs, const RelaxedStruct& rhs) = default;
};
struct NestedStruct
{
int i;
int i{};
std::string s;
Enum e;
Enum e{};
Struct x;
friend bool operator==(const NestedStruct& lhs, const NestedStruct& rhs) = default;
};
}
} // namespace my
SDBUSCPP_REGISTER_STRUCT(my::Struct, i, s, l, e);
SDBUSCPP_REGISTER_STRUCT(my::Struct, i, s, l, e); // NOLINT(readability-identifier-length)
SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(my::RelaxedStruct);
SDBUSCPP_REGISTER_STRUCT(my::RelaxedStruct, i, s, l, e);
SDBUSCPP_REGISTER_STRUCT(my::RelaxedStruct, i, s, l, e); // NOLINT(readability-identifier-length)
SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(my::NestedStruct);
SDBUSCPP_REGISTER_STRUCT(my::NestedStruct, i, s, e, x);
SDBUSCPP_REGISTER_STRUCT(my::NestedStruct, i, s, e, x); // NOLINT(readability-identifier-length)
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -153,7 +161,7 @@ TEST(AMessage, CanBeDefaultConstructed)
TEST(AMessage, IsInvalidAfterDefaultConstructed)
{
sdbus::PlainMessage msg;
const sdbus::PlainMessage msg;
ASSERT_FALSE(msg.isValid());
}
@@ -218,7 +226,7 @@ TEST(AMessage, CanCarryASimpleInteger)
msg << dataWritten;
msg.seal();
int dataRead;
int dataRead{};
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
@@ -258,7 +266,7 @@ TEST(AMessage, CanCarryAVariant)
{
auto msg = sdbus::createPlainMessage();
const auto dataWritten = sdbus::Variant((double)3.14);
const auto dataWritten = sdbus::Variant(3.14);
msg << dataWritten;
msg.seal();
@@ -273,7 +281,7 @@ TEST(AMessage, CanCarryACollectionOfEmbeddedVariants)
{
auto msg = sdbus::createPlainMessage();
std::vector<sdbus::Variant> value{sdbus::Variant{"hello"s}, sdbus::Variant{(double)3.14}};
std::vector<sdbus::Variant> value{sdbus::Variant{"hello"s}, sdbus::Variant{3.14}};
const auto dataWritten = sdbus::Variant{value};
msg << dataWritten;
@@ -320,12 +328,12 @@ TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdArray)
{
auto msg = sdbus::createPlainMessage();
const std::array<int, 3> dataWritten{3545342, 43643532, 324325};
const std::array dataWritten{3545342, 43643532, 324325};
msg << dataWritten;
msg.seal();
std::array<int, 3> dataRead;
std::array<int, 3> dataRead{};
msg >> dataRead;
ASSERT_THAT(dataRead, Eq(dataWritten));
@@ -351,13 +359,13 @@ TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdSpan)
{
auto msg = sdbus::createPlainMessage();
const std::array<int, 3> sourceArray{3545342, 43643532, 324325};
const std::array sourceArray{3545342, 43643532, 324325};
const std::span dataWritten{sourceArray};
msg << dataWritten;
msg.seal();
std::array<int, 3> destinationArray;
std::array<int, 3> destinationArray{};
std::span dataRead{destinationArray};
msg >> dataRead;
@@ -386,8 +394,8 @@ TEST(AMessage, CanCarryAnEnumValue)
{
auto msg = sdbus::createPlainMessage();
enum class EnumA : int16_t {X = 5} aWritten{EnumA::X};
enum EnumB {Y = 11} bWritten{EnumB::Y};
const enum class EnumA : int16_t {X = 5} aWritten{EnumA::X}; // NOLINT(performance-enum-size)
const enum EnumB {Y = 11} bWritten{EnumB::Y}; // NOLINT(performance-enum-size)
msg << aWritten << bWritten;
msg.seal();
@@ -409,7 +417,7 @@ TEST(AMessage, ThrowsWhenDestinationStdArrayIsTooSmallDuringDeserialization)
msg << dataWritten;
msg.seal();
std::array<int, 3> dataRead;
std::array<int, 3> dataRead{};
ASSERT_THROW(msg >> dataRead, sdbus::Error);
}
@@ -423,7 +431,7 @@ TEST(AMessage, ThrowsWhenDestinationStdSpanIsTooSmallDuringDeserialization)
msg << dataWritten;
msg.seal();
std::array<int, 2> destinationArray;
std::array<int, 2> destinationArray{};
std::span dataRead{destinationArray};
ASSERT_THROW(msg >> dataRead, sdbus::Error);
}
@@ -433,7 +441,7 @@ TEST(AMessage, CanCarryADictionary)
{
auto msg = sdbus::createPlainMessage();
std::map<int, std::string> dataWritten{{1, "one"}, {2, "two"}};
const std::map<int, std::string> dataWritten{{1, "one"}, {2, "two"}};
msg << dataWritten;
msg.seal();
@@ -468,7 +476,7 @@ TEST(AMessage, CanCarryAComplexType)
>
>;
ComplexType dataWritten = { {1, {{{5, {{sdbus::ObjectPath{"/some/object"}, true, 45, {{6, "hello"}, {7, "world"}}}}}}, sdbus::Signature{"av"}, 3.14}}};
const ComplexType dataWritten = { {1, {{{5, {{sdbus::ObjectPath{"/some/object"}, true, 45, {{6, "hello"}, {7, "world"}}}}}}, sdbus::Signature{"av"}, 3.14}}};
msg << dataWritten;
msg.seal();
@@ -596,10 +604,10 @@ TEST(AMessage, CanDeserializeDictionaryOfStringsToVariantsIntoUserDefinedStruct)
{
auto msg = sdbus::createPlainMessage();
std::map<std::string, sdbus::Variant> dataWritten{ {"i", sdbus::Variant{3545342}}
, {"s", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
const std::map<std::string, sdbus::Variant> dataWritten{ {"i", sdbus::Variant{3545342}}
, {"s", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
msg << dataWritten;
msg.seal();
@@ -614,10 +622,10 @@ TEST(AMessage, FailsDeserializingDictionaryIntoUserDefinedStructIfStructMemberIs
{
auto msg = sdbus::createPlainMessage();
std::map<std::string, sdbus::Variant> dataWritten{ {"i", sdbus::Variant{3545342}}
, {"nonexistent", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
const std::map<std::string, sdbus::Variant> dataWritten{ {"i", sdbus::Variant{3545342}}
, {"nonexistent", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
msg << dataWritten;
msg.seal();
@@ -631,10 +639,10 @@ TEST(AMessage, DeserializesDictionaryIntoStructWithMissingMembersSuccessfullyIfR
{
auto msg = sdbus::createPlainMessage();
std::map<std::string, sdbus::Variant> dataWritten{ {"some_nonexistent_struct_member", sdbus::Variant{3545342}}
, {"another_nonexistent_struct_member", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
const std::map<std::string, sdbus::Variant> dataWritten{ {"some_nonexistent_struct_member", sdbus::Variant{3545342}}
, {"another_nonexistent_struct_member", sdbus::Variant{"hello"s}}
, {"l", sdbus::Variant{std::list<double>{3.14, 2.4568546}}}
, {"e", sdbus::Variant{my::Enum::Value2}} };
msg << dataWritten;
msg.seal();
+25 -25
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file PollData_test.cpp
*
@@ -42,84 +42,84 @@ using namespace std::chrono_literals;
TEST(PollData, ReturnsZeroRelativeTimeoutForZeroAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
pd.timeout = std::chrono::microseconds::zero();
sdbus::IConnection::PollData pollData{};
pollData.timeout = std::chrono::microseconds::zero();
auto relativeTimeout = pd.getRelativeTimeout();
auto relativeTimeout = pollData.getRelativeTimeout();
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::zero()));
}
TEST(PollData, ReturnsZeroPollTimeoutForZeroAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
pd.timeout = std::chrono::microseconds::zero();
sdbus::IConnection::PollData pollData{};
pollData.timeout = std::chrono::microseconds::zero();
auto pollTimeout = pd.getPollTimeout();
auto pollTimeout = pollData.getPollTimeout();
EXPECT_THAT(pollTimeout, Eq(0));
}
TEST(PollData, ReturnsInfiniteRelativeTimeoutForInfiniteAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
pd.timeout = std::chrono::microseconds::max();
sdbus::IConnection::PollData pollData{};
pollData.timeout = std::chrono::microseconds::max();
auto relativeTimeout = pd.getRelativeTimeout();
auto relativeTimeout = pollData.getRelativeTimeout();
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::max()));
}
TEST(PollData, ReturnsNegativePollTimeoutForInfiniteAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
pd.timeout = std::chrono::microseconds::max();
sdbus::IConnection::PollData pollData{};
pollData.timeout = std::chrono::microseconds::max();
auto pollTimeout = pd.getPollTimeout();
auto pollTimeout = pollData.getPollTimeout();
EXPECT_THAT(pollTimeout, Eq(-1));
}
TEST(PollData, ReturnsZeroRelativeTimeoutForPastAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
sdbus::IConnection::PollData pollData{};
auto past = std::chrono::steady_clock::now() - 10s;
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
auto relativeTimeout = pd.getRelativeTimeout();
auto relativeTimeout = pollData.getRelativeTimeout();
EXPECT_THAT(relativeTimeout, Eq(0us));
}
TEST(PollData, ReturnsZeroPollTimeoutForPastAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
sdbus::IConnection::PollData pollData{};
auto past = std::chrono::steady_clock::now() - 10s;
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
auto pollTimeout = pd.getPollTimeout();
auto pollTimeout = pollData.getPollTimeout();
EXPECT_THAT(pollTimeout, Eq(0));
}
TEST(PollData, ReturnsCorrectRelativeTimeoutForFutureAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
sdbus::IConnection::PollData pollData{};
auto future = std::chrono::steady_clock::now() + 1s;
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
auto relativeTimeout = pd.getRelativeTimeout();
auto relativeTimeout = pollData.getRelativeTimeout();
EXPECT_THAT(relativeTimeout, AllOf(Ge(900ms), Le(1100ms)));
}
TEST(PollData, ReturnsCorrectPollTimeoutForFutureAbsoluteTimeout)
{
sdbus::IConnection::PollData pd;
sdbus::IConnection::PollData pollData{};
auto future = std::chrono::steady_clock::now() + 1s;
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
auto pollTimeout = pd.getPollTimeout();
auto pollTimeout = pollData.getPollTimeout();
EXPECT_THAT(pollTimeout, AllOf(Ge(900), Le(1100)));
}
+63 -53
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file TypeTraits_test.cpp
*
@@ -30,6 +30,15 @@
#include <gmock/gmock.h>
#include <cstdint>
#include <type_traits>
#include <string>
#include <string_view>
#include <vector>
#include <array>
#include <map>
#include <unordered_map>
#include <variant>
#include <span>
#include <tuple>
using ::testing::Eq;
@@ -39,12 +48,12 @@ namespace
// FIXTURE DEFINITION FOR TYPED TESTS
// ----
template <typename _T>
template <typename>
class Type2DBusTypeSignatureConversion
: public ::testing::Test
{
protected:
const std::string dbusTypeSignature_{getDBusTypeSignature()};
std::string dbusTypeSignature_{getDBusTypeSignature()};
private:
static std::string getDBusTypeSignature();
};
@@ -54,20 +63,22 @@ namespace
A, B, C
};
enum struct SomeEnumStruct : int64_t
enum struct SomeEnumStruct : int64_t // NOLINT(performance-enum-size)
{
A, B, C
};
enum SomeClassicEnum
enum SomeClassicEnum // NOLINT(performance-enum-size)
{
A, B, C
};
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define TYPE(...) \
template <> \
std::string Type2DBusTypeSignatureConversion<__VA_ARGS__>::getDBusTypeSignature() \
/**/
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define HAS_DBUS_TYPE_SIGNATURE(_SIG) \
{ \
return (_SIG); \
@@ -132,46 +143,45 @@ namespace
>;
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(oanbva{is})}ghss)}")
typedef ::testing::Types< bool
, uint8_t
, int16_t
, uint16_t
, int32_t
, uint32_t
, int64_t
, uint64_t
, double
, const char*
, std::string
, std::string_view
, sdbus::BusName
, sdbus::InterfaceName
, sdbus::MemberName
, sdbus::ObjectPath
, sdbus::Signature
, sdbus::Variant
, std::variant<int16_t, std::string>
, sdbus::UnixFd
, sdbus::Struct<bool>
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
, std::vector<int16_t>
, std::array<int16_t, 3>
using DBusSupportedTypes = ::testing::Types< bool
, uint8_t
, int16_t
, uint16_t
, int32_t
, uint32_t
, int64_t
, uint64_t
, double
, const char*
, std::string
, std::string_view
, sdbus::BusName
, sdbus::InterfaceName
, sdbus::MemberName
, sdbus::ObjectPath
, sdbus::Signature
, sdbus::Variant
, std::variant<int16_t, std::string>
, sdbus::UnixFd
, sdbus::Struct<bool>
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
, std::vector<int16_t>
, std::array<int16_t, 3>
#ifdef __cpp_lib_span
, std::span<int16_t>
, std::span<int16_t>
#endif
, SomeEnumClass
, const SomeEnumClass
, volatile SomeEnumClass
, const volatile SomeEnumClass
, SomeEnumStruct
, SomeClassicEnum
, std::map<int32_t, int64_t>
, std::unordered_map<int32_t, int64_t>
, ComplexType
> DBusSupportedTypes;
, SomeEnumClass
, const SomeEnumClass
, volatile SomeEnumClass
, const volatile SomeEnumClass
, SomeEnumStruct
, SomeClassicEnum
, std::map<int32_t, int64_t>
, std::unordered_map<int32_t, int64_t>
, ComplexType >;
TYPED_TEST_SUITE(Type2DBusTypeSignatureConversion, DBusSupportedTypes);
}
} // namespace
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -189,11 +199,11 @@ TEST(FreeFunctionTypeTraits, DetectsTraitsOfTrivialSignatureFunction)
using Fnc = decltype(f);
static_assert(!sdbus::is_async_method_v<Fnc>, "Free function incorrectly detected as async method");
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<>>::value, "Incorrectly detected free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<>>::value, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, void>::value, "Incorrectly detected tuple of free function return types");
static_assert(std::is_same_v<sdbus::function_arguments_t<Fnc>, std::tuple<>>, "Incorrectly detected free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<>>, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_output_arg_types_t<Fnc>, void>, "Incorrectly detected tuple of free function return types");
static_assert(sdbus::function_argument_count_v<Fnc> == 0, "Incorrectly detected free function parameter count");
static_assert(std::is_void<sdbus::function_result_t<Fnc>>::value, "Incorrectly detected free function return type");
static_assert(std::is_void_v<sdbus::function_result_t<Fnc>>, "Incorrectly detected free function return type");
}
TEST(FreeFunctionTypeTraits, DetectsTraitsOfNontrivialSignatureFunction)
@@ -202,11 +212,11 @@ TEST(FreeFunctionTypeTraits, DetectsTraitsOfNontrivialSignatureFunction)
using Fnc = decltype(f);
static_assert(!sdbus::is_async_method_v<Fnc>, "Free function incorrectly detected as async method");
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>::value, "Incorrectly detected free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>::value, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected tuple of free function return types");
static_assert(std::is_same_v<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>, "Incorrectly detected free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected tuple of free function return types");
static_assert(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
static_assert(std::is_same_v<sdbus::function_result_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected free function return type");
}
TEST(FreeFunctionTypeTraits, DetectsTraitsOfAsyncFunction)
@@ -215,9 +225,9 @@ TEST(FreeFunctionTypeTraits, DetectsTraitsOfAsyncFunction)
using Fnc = decltype(f);
static_assert(sdbus::is_async_method_v<Fnc>, "Free async function incorrectly detected as sync method");
static_assert(std::is_same<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>::value, "Incorrectly detected free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>::value, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected tuple of free function return types");
static_assert(std::is_same_v<sdbus::function_arguments_t<Fnc>, std::tuple<double&, const char*, int>>, "Incorrectly detected free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_input_arg_types_t<Fnc>, std::tuple<double, const char*, int>>, "Incorrectly detected tuple of free function parameters");
static_assert(std::is_same_v<sdbus::tuple_of_function_output_arg_types_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected tuple of free function return types");
static_assert(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
static_assert(std::is_same_v<sdbus::function_result_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected free function return type");
}
+123 -60
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file Types_test.cpp
*
@@ -24,22 +24,35 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sdbus-c++/Error.h>
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Types.h>
#include "MessageUtils.h"
#include <sdbus-c++/TypeTraits.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <cstdint>
#include <cerrno>
#include <map>
#include <string>
#include <variant>
#include <vector>
#include <sys/eventfd.h>
#include <tuple>
#include <type_traits>
#include <unistd.h>
#include <utility>
using ::testing::Eq;
using ::testing::Gt;
using ::testing::HasSubstr;
using namespace std::string_literals;
namespace
{
constexpr const uint64_t ANY_UINT64 = 84578348354;
constexpr const double ANY_DOUBLE = 3.14;
}
} // namespace
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -52,14 +65,14 @@ TEST(AVariant, CanBeDefaultConstructed)
TEST(AVariant, ContainsNoValueAfterDefaultConstructed)
{
sdbus::Variant v;
const sdbus::Variant var;
ASSERT_TRUE(v.isEmpty());
ASSERT_TRUE(var.isEmpty());
}
TEST(AVariant, CanBeConstructedFromASimpleValue)
{
int value = 5;
const int value = 5;
ASSERT_NO_THROW(sdbus::Variant{value});
}
@@ -67,7 +80,7 @@ TEST(AVariant, CanBeConstructedFromASimpleValue)
TEST(AVariant, CanBeConstructedFromAComplexValue)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
ASSERT_NO_THROW(sdbus::Variant{value});
}
@@ -77,9 +90,9 @@ TEST(AVariant, CanBeConstructedFromAnStdVariant)
using ComplexType = std::vector<sdbus::Struct<std::string, double>>;
using StdVariantType = std::variant<std::string, uint64_t, ComplexType>;
ComplexType value{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}};
StdVariantType stdVariant{value};
const StdVariantType stdVariant{value};
sdbus::Variant sdbusVariant{stdVariant};
const sdbus::Variant sdbusVariant{stdVariant};
ASSERT_TRUE(sdbusVariant.containsValueOfType<ComplexType>());
ASSERT_THAT(sdbusVariant.get<ComplexType>(), Eq(value));
@@ -88,10 +101,10 @@ TEST(AVariant, CanBeConstructedFromAnStdVariant)
TEST(AVariant, CanBeCopied)
{
auto value = "hello"s;
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
auto variantCopy1{variant};
auto variantCopy2 = variantCopy1;
const auto variantCopy1{variant}; // NOLINT(performance-unnecessary-copy-initialization)
const auto variantCopy2 = variantCopy1; // NOLINT(performance-unnecessary-copy-initialization)
ASSERT_THAT(variantCopy1.get<std::string>(), Eq(value));
ASSERT_THAT(variantCopy2.get<std::string>(), Eq(value));
@@ -105,51 +118,102 @@ TEST(AVariant, CanBeMoved)
auto movedVariant{std::move(variant)};
ASSERT_THAT(movedVariant.get<std::string>(), Eq(value));
ASSERT_TRUE(variant.isEmpty());
ASSERT_TRUE(variant.isEmpty()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
}
TEST(AVariant, CanBeMovedIntoAMap)
{
auto value = "hello"s;
sdbus::Variant variant(value);
const auto value = "hello"s;
sdbus::Variant variant(value); // NOLINT(misc-const-correctness)
std::map<std::string, sdbus::Variant> mymap;
mymap.try_emplace("payload", std::move(variant));
ASSERT_THAT(mymap["payload"].get<std::string>(), Eq(value));
ASSERT_TRUE(variant.isEmpty());
ASSERT_TRUE(variant.isEmpty()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
}
TEST(AVariant, IsNotEmptyWhenContainsAValue)
{
sdbus::Variant v("hello");
const sdbus::Variant var("hello");
ASSERT_FALSE(v.isEmpty());
ASSERT_FALSE(var.isEmpty());
}
TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
{
int value = 5;
const int value = 5;
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
ASSERT_THAT(variant.get<int>(), Eq(value));
}
#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
TEST(ASimpleVariant, CanBeDumpedToAString)
{
const int value = 5;
const sdbus::Variant variant(value);
// This should produce something like:
// VARIANT "i" {
// INT32 5;
// };
const auto str = variant.dumpToString();
EXPECT_THAT(str, ::HasSubstr("VARIANT \"i\""));
EXPECT_THAT(str, ::HasSubstr("INT32"));
EXPECT_THAT(str, ::HasSubstr("5"));
}
#endif // SDBUS_basu
TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
ASSERT_THAT(variant.get<decltype(value)>(), Eq(value));
ASSERT_THAT(variant.get<ComplexType>(), Eq(value));
}
#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
TEST(AComplexVariant, CanBeDumpedToAString)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const sdbus::Variant variant(value);
// This should produce something like:
// VARIANT "a{ta(sd)}" {
// ARRAY "{ta(sd)}" {
// DICT_ENTRY "ta(sd)" {
// UINT64 84578348354;
// ARRAY "(sd)" {
// STRUCT "sd" {
// STRING "hello";
// DOUBLE 3.14;
// };
// STRUCT "sd" {
// STRING "world";
// DOUBLE 3.14;
// };
// };
// };
// };
// };
const auto str = variant.dumpToString();
EXPECT_THAT(str, ::HasSubstr("VARIANT \"a{ta(sd)}\""));
EXPECT_THAT(str, ::HasSubstr("hello"));
EXPECT_THAT(str, ::HasSubstr("world"));
}
#endif // SDBUS_basu
TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
{
std::string value{"I am a string"};
sdbus::Variant variant(value);
const std::string value{"I am a string"};
const sdbus::Variant variant(value);
ASSERT_THAT(variant.get<std::string>(), Eq(value));
ASSERT_THAT(variant.get<std::string>(), Eq(value));
@@ -159,9 +223,9 @@ TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
TEST(AVariant, ReturnsTrueWhenAskedIfItContainsTheTypeItReallyContains)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
ASSERT_TRUE(variant.containsValueOfType<ComplexType>());
}
@@ -170,8 +234,8 @@ TEST(AVariant, CanBeConvertedIntoAnStdVariant)
{
using ComplexType = std::vector<sdbus::Struct<std::string, double>>;
using StdVariantType = std::variant<std::string, uint64_t, ComplexType>;
ComplexType value{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}};
sdbus::Variant sdbusVariant{value};
const ComplexType value{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}};
const sdbus::Variant sdbusVariant{value};
StdVariantType stdVariant{sdbusVariant};
ASSERT_TRUE(std::holds_alternative<ComplexType>(stdVariant));
@@ -183,18 +247,18 @@ TEST(AVariant, IsImplicitlyInterchangeableWithStdVariant)
using ComplexType = std::vector<sdbus::Struct<std::string, double>>;
using StdVariantType = std::variant<std::string, uint64_t, ComplexType>;
ComplexType value{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}};
StdVariantType stdVariant{value};
const StdVariantType stdVariant{value};
auto stdVariantCopy = [](const sdbus::Variant &v) -> StdVariantType { return v; }(stdVariant);
auto stdVariantCopy = [](const sdbus::Variant &var) -> StdVariantType { return var; }(stdVariant);
ASSERT_THAT(stdVariantCopy, Eq(stdVariant));
}
TEST(ASimpleVariant, ReturnsFalseWhenAskedIfItContainsTypeItDoesntReallyContain)
{
int value = 5;
const int value = 5;
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
ASSERT_FALSE(variant.containsValueOfType<double>());
}
@@ -203,17 +267,17 @@ TEST(AVariant, CanContainOtherEmbeddedVariants)
{
using TypeWithVariants = std::vector<sdbus::Struct<sdbus::Variant, double>>;
TypeWithVariants value;
value.push_back({sdbus::Variant("a string"), ANY_DOUBLE});
value.push_back({sdbus::Variant(ANY_UINT64), ANY_DOUBLE});
value.emplace_back(sdbus::Variant("a string"), ANY_DOUBLE);
value.emplace_back(sdbus::Variant(ANY_UINT64), ANY_DOUBLE);
sdbus::Variant variant(value);
const sdbus::Variant variant(value);
ASSERT_TRUE(variant.containsValueOfType<TypeWithVariants>());
}
TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
{
sdbus::Variant variant("a string");
const sdbus::Variant variant("a string");
auto msg = sdbus::createPlainMessage();
@@ -222,7 +286,7 @@ TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
{
sdbus::Variant variant;
const sdbus::Variant variant;
auto msg = sdbus::createPlainMessage();
@@ -232,8 +296,8 @@ TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
sdbus::Variant variant(value);
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const sdbus::Variant variant(value);
auto msg = sdbus::createPlainMessage();
variant.serializeTo(msg);
@@ -241,30 +305,30 @@ TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
sdbus::Variant variant2;
variant2.deserializeFrom(msg);
ASSERT_THAT(variant2.get<decltype(value)>(), Eq(value));
ASSERT_THAT(variant2.get<ComplexType>(), Eq(value));
}
TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
sdbus::Variant variant(value);
auto variantCopy1{variant};
auto variantCopy2 = variant;
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const sdbus::Variant variant(value);
auto variantCopy1{variant}; // NOLINT(performance-unnecessary-copy-initialization)
auto variantCopy2 = variant; // NOLINT(performance-unnecessary-copy-initialization)
auto msg = sdbus::createPlainMessage();
variant.serializeTo(msg);
variantCopy1.serializeTo(msg);
variantCopy2.serializeTo(msg);
msg.seal();
sdbus::Variant receivedVariant1, receivedVariant2, receivedVariant3;
sdbus::Variant receivedVariant1, receivedVariant2, receivedVariant3; // NOLINT(readability-isolate-declaration)
receivedVariant1.deserializeFrom(msg);
receivedVariant2.deserializeFrom(msg);
receivedVariant3.deserializeFrom(msg);
ASSERT_THAT(receivedVariant1.get<decltype(value)>(), Eq(value));
ASSERT_THAT(receivedVariant2.get<decltype(value)>(), Eq(value));
ASSERT_THAT(receivedVariant3.get<decltype(value)>(), Eq(value));
ASSERT_THAT(receivedVariant1.get<ComplexType>(), Eq(value));
ASSERT_THAT(receivedVariant2.get<ComplexType>(), Eq(value));
ASSERT_THAT(receivedVariant3.get<ComplexType>(), Eq(value));
}
TEST(AStruct, CanBeCreatedFromStdTuple)
@@ -295,7 +359,7 @@ TEST(AStruct, CanBeUsedLikeStdTupleType)
TEST(AStruct, CanBeUsedInStructuredBinding)
{
sdbus::Struct valueStruct(1234, "abcd", true);
const sdbus::Struct valueStruct(1234, "abcd", true);
auto [first, second, third] = valueStruct;
@@ -311,7 +375,7 @@ TEST(AnObjectPath, CanBeConstructedFromCString)
TEST(AnObjectPath, CanBeConstructedFromStdString)
{
std::string aPath{"/some/path"};
const std::string aPath{"/some/path"};
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
}
@@ -322,7 +386,6 @@ TEST(AnObjectPath, CanBeMovedLikeAStdString)
sdbus::ObjectPath oPath{aPath};
ASSERT_THAT(sdbus::ObjectPath{std::move(oPath)}, Eq(sdbus::ObjectPath(std::move(aPath))));
ASSERT_THAT(std::string(oPath), Eq(aPath));
}
TEST(ASignature, CanBeConstructedFromCString)
@@ -334,7 +397,7 @@ TEST(ASignature, CanBeConstructedFromCString)
TEST(ASignature, CanBeConstructedFromStdString)
{
std::string aSignature{"us"};
const std::string aSignature{"us"};
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
}
@@ -365,9 +428,9 @@ TEST(AUnixFd, AdoptsAndOwnsFdAsIsUponAdoptionConstruction)
TEST(AUnixFd, DuplicatesFdUponCopyConstruction)
{
sdbus::UnixFd unixFd(::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK));
const sdbus::UnixFd unixFd(::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK));
sdbus::UnixFd unixFdCopy{unixFd};
const sdbus::UnixFd unixFdCopy{unixFd}; // NOLINT(performance-unnecessary-copy-initialization)
EXPECT_THAT(unixFdCopy.get(), Gt(unixFd.get()));
}
@@ -377,20 +440,20 @@ TEST(AUnixFd, TakesOverFdUponMoveConstruction)
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
sdbus::UnixFd unixFdNew{std::move(unixFd)};
const sdbus::UnixFd unixFdNew{std::move(unixFd)};
EXPECT_FALSE(unixFd.isValid());
EXPECT_FALSE(unixFd.isValid()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move)
EXPECT_THAT(unixFdNew.get(), Eq(fd));
}
TEST(AUnixFd, ClosesFdProperlyUponDestruction)
{
int fd, fdCopy;
int fd{}, fdCopy{}; // NOLINT(readability-isolate-declaration)
{
fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
auto unixFdNew = std::move(unixFd);
auto unixFdCopy = unixFdNew;
auto unixFdCopy = unixFdNew; // NOLINT(performance-unnecessary-copy-initialization)
fdCopy = unixFdCopy.get();
}
@@ -401,7 +464,7 @@ TEST(AUnixFd, ClosesFdProperlyUponDestruction)
TEST(AUnixFd, DoesNotCloseReleasedFd)
{
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
int fdReleased;
int fdReleased{};
{
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
fdReleased = unixFd.release();
+13 -13
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file SdBusMock.h
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
@@ -35,18 +35,18 @@
class SdBusMock : public sdbus::internal::ISdBus
{
public:
MOCK_METHOD1(sd_bus_message_ref, sd_bus_message*(sd_bus_message *m));
MOCK_METHOD1(sd_bus_message_unref, sd_bus_message*(sd_bus_message *m));
MOCK_METHOD1(sd_bus_message_ref, sd_bus_message*(sd_bus_message *msg));
MOCK_METHOD1(sd_bus_message_unref, sd_bus_message*(sd_bus_message *msg));
MOCK_METHOD3(sd_bus_send, int(sd_bus *bus, sd_bus_message *m, uint64_t *cookie));
MOCK_METHOD5(sd_bus_call, int(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply));
MOCK_METHOD6(sd_bus_call_async, int(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec));
MOCK_METHOD3(sd_bus_send, int(sd_bus *bus, sd_bus_message *msg, uint64_t *cookie));
MOCK_METHOD5(sd_bus_call, int(sd_bus *bus, sd_bus_message *msg, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply));
MOCK_METHOD6(sd_bus_call_async, int(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *msg, sd_bus_message_handler_t callback, void *userdata, uint64_t usec));
MOCK_METHOD3(sd_bus_message_new, int(sd_bus *bus, sd_bus_message **m, uint8_t type));
MOCK_METHOD6(sd_bus_message_new_method_call, int(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member));
MOCK_METHOD5(sd_bus_message_new_signal, int(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member));
MOCK_METHOD2(sd_bus_message_new_method_return, int(sd_bus_message *call, sd_bus_message **m));
MOCK_METHOD3(sd_bus_message_new_method_error, int(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e));
MOCK_METHOD3(sd_bus_message_new, int(sd_bus *bus, sd_bus_message **msg, uint8_t type));
MOCK_METHOD6(sd_bus_message_new_method_call, int(sd_bus *bus, sd_bus_message **msg, const char *destination, const char *path, const char *interface, const char *member));
MOCK_METHOD5(sd_bus_message_new_signal, int(sd_bus *bus, sd_bus_message **msg, const char *path, const char *interface, const char *member));
MOCK_METHOD2(sd_bus_message_new_method_return, int(sd_bus_message *call, sd_bus_message **msg));
MOCK_METHOD3(sd_bus_message_new_method_error, int(sd_bus_message *call, sd_bus_message **msg, const sd_bus_error *err));
MOCK_METHOD2(sd_bus_set_method_call_timeout, int(sd_bus *bus, uint64_t usec));
MOCK_METHOD2(sd_bus_get_method_call_timeout, int(sd_bus *bus, uint64_t *ret));
@@ -78,7 +78,7 @@ public:
MOCK_METHOD1(sd_bus_new, int(sd_bus **ret));
MOCK_METHOD1(sd_bus_start, int(sd_bus *bus));
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **ret));
MOCK_METHOD1(sd_bus_get_current_message, sd_bus_message*(sd_bus *bus));
MOCK_METHOD2(sd_bus_get_poll_data, int(sd_bus *bus, PollData* data));
MOCK_METHOD3(sd_bus_get_n_queued, int(sd_bus *bus, uint64_t *read, uint64_t* write));
@@ -86,7 +86,7 @@ public:
MOCK_METHOD1(sd_bus_flush_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD1(sd_bus_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD2(sd_bus_message_set_destination, int(sd_bus_message *m, const char *destination));
MOCK_METHOD2(sd_bus_message_set_destination, int(sd_bus_message *msg, const char *destination));
MOCK_METHOD3(sd_bus_query_sender_creds, int(sd_bus_message *, uint64_t, sd_bus_creds **));
MOCK_METHOD1(sd_bus_creds_ref, sd_bus_creds*(sd_bus_creds *));
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file sdbus-c++-unit-tests.cpp
*
+3 -2
View File
@@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.5)
project(sdbus-c++-tools VERSION 2.2.1)
project(sdbus-c++-tools VERSION 2.3.1)
include(GNUInstallDirs)
@@ -35,7 +35,8 @@ set(SDBUSCPP_XML2CPP_SRCS
# GENERAL COMPILER CONFIGURATION
#-------------------------------
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
unset(CMAKE_CXX_CLANG_TIDY) # Do not propagate clang-tidy to tools
#----------------------------------
# EXECUTABLE BUILD INFORMATION
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file AdaptorGenerator.cpp
*
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file AdaptorGenerator.h
*
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file BaseGenerator.cpp
*
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file BaseGenerator.h
*
+166 -39
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ProxyGenerator.cpp
*
@@ -33,6 +33,7 @@
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <optional>
#include <regex>
using std::endl;
@@ -41,6 +42,9 @@ using sdbuscpp::xml::Document;
using sdbuscpp::xml::Node;
using sdbuscpp::xml::Nodes;
// Possible implementation backends of async methods
enum class AsyncImpl { Callback, Future, Awaitable, DirectCallback };
/**
* Generate proxy code - client glue
*/
@@ -158,8 +162,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
Nodes outArgs = args.select("direction" , "out");
bool dontExpectReply{false};
bool async{false};
bool future{false}; // Async methods implemented by means of either std::future or callbacks
std::optional<AsyncImpl> asyncImpl;
std::string timeoutValue;
std::smatch smTimeout;
@@ -175,11 +178,20 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
{
if (annotationName == "org.freedesktop.DBus.Method.Async"
&& (annotationValue == "client" || annotationValue == "clientserver" || annotationValue == "client-server"))
async = true;
{
if (not asyncImpl.has_value())
{
asyncImpl = AsyncImpl::Callback; // Default to callback
}
}
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && annotationValue == "callback")
future = false;
asyncImpl = AsyncImpl::Callback;
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && annotationValue == "direct-callback")
asyncImpl = AsyncImpl::DirectCallback;
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
future = true;
asyncImpl = AsyncImpl::Future;
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
asyncImpl = AsyncImpl::Awaitable;
}
if (annotationName == "org.freedesktop.DBus.Method.Timeout")
timeoutValue = annotationValue;
@@ -211,22 +223,50 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
std::string outArgStr, outArgTypeStr;
std::tie(outArgStr, outArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(outArgs);
const std::string realRetType = (async && !dontExpectReply ? (future ? "std::future<" + retType + ">" : "sdbus::PendingAsyncCall") : async ? "void" : retType);
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
// Determine return type based on async implementation
std::string realRetType;
if (asyncImpl.has_value() && !dontExpectReply)
{
if (*asyncImpl == AsyncImpl::Future)
realRetType = "std::future<" + retType + ">";
else if (*asyncImpl == AsyncImpl::Awaitable)
realRetType = "sdbus::Awaitable<" + retType + ">";
else // Callback
realRetType = "sdbus::PendingAsyncCall";
}
else if (asyncImpl.has_value())
{
realRetType = "void";
}
else
{
realRetType = retType;
}
if (asyncImpl.has_value() && *asyncImpl == AsyncImpl::DirectCallback)
{
definitionSS << tab << "template <typename F>" << endl
<< tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << (not inArgTypeStr.empty() ? ", " : "") << "F&& callback" << ")" << endl
<< tab << "{" << endl;
}
else
{
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
<< tab << "{" << endl;
}
if (!timeoutValue.empty())
{
definitionSS << tab << tab << "using namespace std::chrono_literals;" << endl;
}
if (outArgs.size() > 0 && !async)
if (outArgs.size() > 0 && !asyncImpl.has_value())
{
definitionSS << tab << tab << retType << " result;" << endl;
}
definitionSS << tab << tab << (async && !dontExpectReply ? "return " : "")
<< "m_proxy.callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
definitionSS << tab << tab << (asyncImpl.has_value() && !dontExpectReply ? "return " : "")
<< "m_proxy.callMethod" << (asyncImpl.has_value() ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
if (!timeoutValue.empty())
{
@@ -240,16 +280,24 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
definitionSS << ".withArguments(" << inArgStr << ")";
}
if (async && !dontExpectReply)
if (asyncImpl.has_value() && !dontExpectReply)
{
auto nameBigFirst = name;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (future) // Async methods implemented through future
if (*asyncImpl == AsyncImpl::Future)
{
definitionSS << ".getResultAsFuture<" << retTypeBare << ">()";
}
else // Async methods implemented through callbacks
else if (*asyncImpl == AsyncImpl::Awaitable)
{
definitionSS << ".getResultAsAwaitable<" << retTypeBare << ">()";
}
else if (*asyncImpl == AsyncImpl::DirectCallback)
{
definitionSS << ".uponReplyInvoke(std::forward<F>(callback))";
}
else // Callback
{
definitionSS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "std::move(error)); })";
@@ -295,7 +343,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes&
".call([this](" << argTypeStr << ")"
"{ this->on" << nameBigFirst << "(" << argStr << "); });" << endl;
declarationSS << tab << "virtual void on" << nameBigFirst << "(" << argTypeStr << ") = 0;" << endl;
declarationSS << tab << "virtual void on" << nameBigFirst << "(" << argTypeStr << ") {}" << endl;
}
return std::make_tuple(registrationSS.str(), declarationSS.str());
@@ -315,10 +363,8 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
auto propertyArg = std::string("value");
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
bool asyncGet{false};
bool futureGet{false}; // Async property getter implemented by means of either std::future or callbacks
bool asyncSet{false};
bool futureSet{false}; // Async property setter implemented by means of either std::future or callbacks
std::optional<AsyncImpl> asyncImplGet;
std::optional<AsyncImpl> asyncImplSet;
Nodes annotations = (*property)["annotation"];
for (const auto& annotation : annotations)
@@ -327,28 +373,70 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
const auto annotationValue = annotation->get("value");
if (annotationName == "org.freedesktop.DBus.Property.Get.Async" && annotationValue == "client") // Server-side not supported (may be in the future)
asyncGet = true;
{
if (not asyncImplGet.has_value())
{
asyncImplGet = AsyncImpl::Callback; // Default to callback
}
}
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && annotationValue == "callback")
futureGet = false;
asyncImplGet = AsyncImpl::Callback;
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && annotationValue == "direct-callback")
asyncImplGet = AsyncImpl::DirectCallback;
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
futureGet = true;
asyncImplGet = AsyncImpl::Future;
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
asyncImplGet = AsyncImpl::Awaitable;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async" && annotationValue == "client") // Server-side not supported (may be in the future)
asyncSet = true;
{
if (not asyncImplSet.has_value())
{
asyncImplSet = AsyncImpl::Callback; // Default to callback
}
}
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && annotationValue == "callback")
futureSet = false;
asyncImplSet = AsyncImpl::Callback;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && annotationValue == "direct-callback")
asyncImplSet = AsyncImpl::DirectCallback;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
futureSet = true;
asyncImplSet = AsyncImpl::Future;
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
asyncImplSet = AsyncImpl::Awaitable;
}
if (propertyAccess == "read" || propertyAccess == "readwrite")
{
const std::string realRetType = (asyncGet ? (futureGet ? "std::future<sdbus::Variant>" : "sdbus::PendingAsyncCall") : propertyType);
// Determine return type based on async implementation
std::string realRetType;
if (asyncImplGet.has_value())
{
if (*asyncImplGet == AsyncImpl::Future)
realRetType = "std::future<sdbus::Variant>";
else if (*asyncImplGet == AsyncImpl::Awaitable)
realRetType = "sdbus::Awaitable<sdbus::Variant>";
else // Callback
realRetType = "sdbus::PendingAsyncCall";
}
else
{
realRetType = propertyType;
}
propertySS << tab << realRetType << " " << propertyNameSafe << "()" << endl
<< tab << "{" << endl;
propertySS << tab << tab << "return m_proxy.getProperty" << (asyncGet ? "Async" : "") << "(\"" << propertyName << "\")"
if (asyncImplGet.has_value() && asyncImplGet.value() == AsyncImpl::DirectCallback)
{
propertySS << tab << "template <typename F>" << endl
<< tab << realRetType << " " << propertyNameSafe << "(F&& callback)" << endl;
}
else
{
propertySS << tab << realRetType << " " << propertyNameSafe << "()" << endl;
}
propertySS << tab << "{" << endl;
propertySS << tab << tab << "return m_proxy.getProperty" << (asyncImplGet.has_value() ? "Async" : "") << "(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)";
if (!asyncGet)
if (!asyncImplGet.has_value())
{
propertySS << ".get<" << realRetType << ">()";
}
@@ -357,11 +445,19 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
auto nameBigFirst = propertyName;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (futureGet) // Async methods implemented through future
if (*asyncImplGet == AsyncImpl::Future)
{
propertySS << ".getResultAsFuture()";
}
else // Async methods implemented through callbacks
else if (*asyncImplGet == AsyncImpl::Awaitable)
{
propertySS << ".getResultAsAwaitable()";
}
else if (*asyncImplGet == AsyncImpl::DirectCallback)
{
propertySS << ".uponReplyInvoke(std::forward<F>(callback))";
}
else // Callback
{
propertySS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error, const sdbus::Variant& value)"
"{ this->on" << nameBigFirst << "PropertyGetReply(value.get<" << propertyType << ">(), std::move(error)); })";
@@ -378,25 +474,56 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
if (propertySignature == "v")
propertyArg = "{" + propertyArg + ", sdbus::embed_variant}";
const std::string realRetType = (asyncSet ? (futureSet ? "std::future<void>" : "sdbus::PendingAsyncCall") : "void");
// Determine return type based on async implementation
std::string realRetType;
if (asyncImplSet.has_value())
{
if (*asyncImplSet == AsyncImpl::Future)
realRetType = "std::future<void>";
else if (*asyncImplSet == AsyncImpl::Awaitable)
realRetType = "sdbus::Awaitable<void>";
else // Callback
realRetType = "sdbus::PendingAsyncCall";
}
else
{
realRetType = "void";
}
propertySS << tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
<< tab << "{" << endl;
propertySS << tab << tab << (asyncSet ? "return " : "") << "m_proxy.setProperty" << (asyncSet ? "Async" : "")
if (asyncImplSet.has_value() && asyncImplSet.value() == AsyncImpl::DirectCallback)
{
propertySS << tab << "template <typename F>" << endl
<< tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << (not propertyTypeArg.empty() ? ", " : "") << "F&& callback)" << endl;
}
else
{
propertySS << tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl;
}
propertySS << tab << "{" << endl;
propertySS << tab << tab << (asyncImplSet.has_value() ? "return " : "") << "m_proxy.setProperty" << (asyncImplSet.has_value() ? "Async" : "")
<< "(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)"
".toValue(" << propertyArg << ")";
if (asyncSet)
if (asyncImplSet.has_value())
{
auto nameBigFirst = propertyName;
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
if (futureSet) // Async methods implemented through future
if (*asyncImplSet == AsyncImpl::Future)
{
propertySS << ".getResultAsFuture()";
}
else // Async methods implemented through callbacks
else if (*asyncImplSet == AsyncImpl::Awaitable)
{
propertySS << ".getResultAsAwaitable()";
}
else if (*asyncImplSet == AsyncImpl::DirectCallback)
{
propertySS << ".uponReplyInvoke(std::forward<T>(callback))";
}
else // Callback
{
propertySS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error)"
"{ this->on" << nameBigFirst << "PropertySetReply(std::move(error)); })";
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file ProxyGenerator.h
*
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
*
* @file xml2cpp.cpp
*