forked from Kistler-Group/sdbus-cpp
Compare commits
17
Commits
@@ -0,0 +1,3 @@
|
||||
# TODO: Introduce common clang-format rule set
|
||||
DisableFormat: true
|
||||
SortIncludes: false
|
||||
+66
@@ -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'
|
||||
+31
-17
@@ -7,6 +7,7 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- release/v2.0
|
||||
- feat/release-v3.x
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -46,34 +47,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 +74,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
|
||||
|
||||
@@ -16,6 +16,9 @@ tests/run-test-on-device.sh
|
||||
.settings
|
||||
*.log
|
||||
|
||||
# vscode
|
||||
.vscode/
|
||||
|
||||
#autotools
|
||||
sdbus-cpp.pc
|
||||
*Makefile
|
||||
|
||||
+28
-11
@@ -4,7 +4,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(sdbus-c++ VERSION 2.1.0 LANGUAGES CXX C)
|
||||
project(sdbus-c++ VERSION 2.2.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
|
||||
@@ -186,7 +189,7 @@ set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HD
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
#----------------------------------
|
||||
# LIBRARY BUILD INFORMATION
|
||||
@@ -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
|
||||
@@ -318,12 +333,14 @@ set(CPACK_PACKAGE_VENDOR "Kistler")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "High-level C++ D-Bus library")
|
||||
set(CPACK_PACKAGE_CONTACT "info@kistler.com")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
|
||||
set(CPACK_COMPONENTS_ALL runtime dev doc)
|
||||
set(CPACK_COMPONENT_DEV_DEPENDS "runtime")
|
||||
set(CPACK_COMPONENTS_ALL sdbus-c++-runtime sdbus-c++-dev sdbus-c++-doc)
|
||||
set(CPACK_COMPONENT_DEV_DEPENDS "sdbus-c++-runtime")
|
||||
# specific for DEB generator
|
||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
||||
set(CPACK_DEBIAN_RUNTIME_DEBUGINFO_PACKAGE ON)
|
||||
set(CPACK_DEBIAN_RUNTIME_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_DEBIAN_SDBUS-C++-RUNTIME_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_DEBIAN_SDBUS-C++-DEV_PACKAGE_NAME "sdbus-c++-dev")
|
||||
set(CPACK_DEBIAN_SDBUS-C++-DOC_PACKAGE_NAME "sdbus-c++-doc")
|
||||
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
@@ -301,3 +301,17 @@ v2.1.0
|
||||
- Change googletest to default version 1.14.0
|
||||
- Add version parameter to the xml2cpp codegen tool
|
||||
- A few other internal refactorings and improvements
|
||||
|
||||
v2.2.0
|
||||
- Add createLightWeightProxy() overload for convenience
|
||||
- Add cookie-related API to Message class
|
||||
- Add async overloads of GetManagedObjects() function
|
||||
- Add signature_of specialization for r-value references
|
||||
- Create a valid sdbus::Error even when errno is invalid or zero
|
||||
- Fix the return type of some slot-returning functions
|
||||
- Fix annotation generation in xml2cpp tool
|
||||
- A few other, mainly CI related updates
|
||||
|
||||
v2.2.1
|
||||
- Fix component names in CPack configuration
|
||||
- Generate correct, expected DEB package names
|
||||
|
||||
@@ -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()
|
||||
+63
-10
@@ -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,7 +1310,7 @@ 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`, `future` and `awaitable`. The default behavior is callback-based method.
|
||||
|
||||
#### Generating callback-based async methods
|
||||
|
||||
@@ -1294,11 +1318,31 @@ For each client-side async method, a corresponding `on<MethodName>Reply` pure vi
|
||||
|
||||
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`.
|
||||
|
||||
#### Generating std:future-based async methods
|
||||
#### 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 +1382,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 +1391,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 +1413,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 +1521,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 +1732,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
@@ -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);
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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) mutable
|
||||
{
|
||||
// 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)
|
||||
@@ -331,21 +331,21 @@ 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 future = promise->get_future();
|
||||
std::promise<future_return_t<Args...>> promise{};
|
||||
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) mutable
|
||||
{
|
||||
if (!error)
|
||||
if constexpr (!std::is_void_v<future_return_t<_Args...>>)
|
||||
promise->set_value({std::move(args)...});
|
||||
if constexpr (!std::is_void_v<future_return_t<Args...>>)
|
||||
promise.set_value({std::move(args)...});
|
||||
else
|
||||
promise->set_value();
|
||||
promise.set_value();
|
||||
else
|
||||
promise->set_exception(std::make_exception_ptr(*std::move(error)));
|
||||
promise.set_exception(std::make_exception_ptr(*std::move(error)));
|
||||
});
|
||||
|
||||
// Will be std::future<void> for no D-Bus method return 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,48 +412,48 @@ 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) mutable
|
||||
{
|
||||
// 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& e)
|
||||
{
|
||||
// Pass message deserialization exceptions to the client via callback error parameter,
|
||||
// instead of propagating them up the message loop call stack.
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
Error(Name name, std::string message)
|
||||
: std::runtime_error("[" + name + "] " + message)
|
||||
: std::runtime_error(!message.empty() ? "[" + name + "] " + message : "[" + name + "]")
|
||||
, name_(std::move(name))
|
||||
, message_(std::move(message))
|
||||
{
|
||||
@@ -90,15 +90,16 @@ namespace sdbus {
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
Error createError(int errNo, std::string customMsg);
|
||||
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)) \
|
||||
/**/
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
@@ -277,7 +277,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addMatch(const std::string& match, message_handler callback) = 0;
|
||||
virtual void addMatch(const std::string& match, message_handler&& callback) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Installs a match rule for messages received on this bus connection
|
||||
@@ -300,14 +300,14 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler callback, return_slot_t) = 0;
|
||||
[[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler&& callback, return_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Asynchronously installs a floating match rule for messages received on this bus connection
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
|
||||
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
|
||||
* @param[in] installCallback One-shot handler invoked once with the broker's response to the install request
|
||||
*
|
||||
* This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously,
|
||||
* in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response.
|
||||
@@ -323,14 +323,14 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0;
|
||||
virtual void addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Asynchronously installs a match rule for messages received on this bus connection
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
|
||||
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
|
||||
* @param[in] installCallback One-shot handler invoked once with the broker's response to the install request
|
||||
* @return RAII-style slot handle representing the ownership of the subscription
|
||||
*
|
||||
* This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously,
|
||||
@@ -347,8 +347,8 @@ namespace sdbus {
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, message_handler&& callback
|
||||
, match_install_handler&& installCallback
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
@@ -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_ */
|
||||
|
||||
+24
-14
@@ -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,34 +426,44 @@ 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>
|
||||
void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items)
|
||||
{
|
||||
addVTable(std::move(interfaceName), {std::forward<VTableItems>(items)...});
|
||||
// Built via emplace_back rather than a braced initializer_list: items hold move-only
|
||||
// callbacks, and initializer_list elements are const (copy-only).
|
||||
std::vector<VTableItem> vtable;
|
||||
vtable.reserve(sizeof...(items));
|
||||
(vtable.emplace_back(std::forward<VTableItems>(items)), ...);
|
||||
addVTable(std::move(interfaceName), std::move(vtable));
|
||||
}
|
||||
|
||||
template <typename... VTableItems, typename>
|
||||
VTableAdder IObject::addVTable(VTableItems&&... items)
|
||||
{
|
||||
return addVTable(std::vector<VTableItem>{std::forward<VTableItems>(items)...});
|
||||
// Built via emplace_back rather than a braced initializer_list: items hold move-only
|
||||
// callbacks, and initializer_list elements are const (copy-only).
|
||||
std::vector<VTableItem> vtable;
|
||||
vtable.reserve(sizeof...(items));
|
||||
(vtable.emplace_back(std::forward<VTableItems>(items)), ...);
|
||||
return addVTable(std::move(vtable));
|
||||
}
|
||||
|
||||
inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)
|
||||
{
|
||||
return VTableAdder(*this, std::move(vtable));
|
||||
return {*this, std::move(vtable)};
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -474,11 +484,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_ */
|
||||
|
||||
+126
-74
@@ -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
|
||||
@@ -454,7 +455,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) = 0;
|
||||
virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously
|
||||
@@ -479,7 +480,7 @@ namespace sdbus {
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
@@ -505,7 +506,7 @@ namespace sdbus {
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, uint64_t timeout ) = 0;
|
||||
|
||||
/*!
|
||||
@@ -532,32 +533,31 @@ namespace sdbus {
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, uint64_t timeout
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @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 );
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, 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
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, 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,57 @@ 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 );
|
||||
|
||||
/*!
|
||||
* @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;
|
||||
|
||||
/*!
|
||||
* @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
|
||||
*
|
||||
@@ -624,7 +669,7 @@ namespace sdbus {
|
||||
*/
|
||||
virtual void registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler ) = 0;
|
||||
, signal_handler&& signalHandler ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers a handler for the desired signal emitted by the D-Bus object
|
||||
@@ -644,7 +689,7 @@ namespace sdbus {
|
||||
*/
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
protected: // Internal API for efficiency reasons used by high-level API helper classes
|
||||
@@ -655,10 +700,10 @@ namespace sdbus {
|
||||
[[nodiscard]] virtual MethodCall createMethodCall(const char* interfaceName, const char* methodName) const = 0;
|
||||
virtual void registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler ) = 0;
|
||||
, signal_handler&& signalHandler ) = 0;
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t ) = 0;
|
||||
};
|
||||
|
||||
@@ -698,132 +743,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 )
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, 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
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, 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 +910,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 +936,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 +963,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 +994,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 +1015,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
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
+243
-203
@@ -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,23 +66,29 @@ 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 {
|
||||
|
||||
// Callbacks from sdbus-c++
|
||||
using method_callback = std::function<void(MethodCall msg)>;
|
||||
using async_reply_handler = std::function<void(MethodReply reply, std::optional<Error> error)>;
|
||||
using signal_handler = std::function<void(Signal signal)>;
|
||||
using message_handler = std::function<void(Message msg)>;
|
||||
using property_set_callback = std::function<void(PropertySetCall msg)>;
|
||||
using property_get_callback = std::function<void(PropertyGetReply& reply)>;
|
||||
// Repeatable server-side and client-side callbacks
|
||||
using method_callback = std::move_only_function<void(MethodCall msg)>;
|
||||
using property_set_callback = std::move_only_function<void(PropertySetCall msg)>;
|
||||
using property_get_callback = std::move_only_function<void(PropertyGetReply& reply)>;
|
||||
using signal_handler = std::move_only_function<void(Signal signal)>;
|
||||
using message_handler = std::move_only_function<void(Message msg)>;
|
||||
|
||||
// One-shot callbacks: invoked exactly once (async reply arrives / match rule installed).
|
||||
// Rvalue-qualified so the library must std::move to invoke, making the call-once contract
|
||||
// visible at the call site and letting handlers move-consume captured resources.
|
||||
using async_reply_handler = std::move_only_function<void(MethodReply reply, std::optional<Error> error) &&>;
|
||||
using match_install_handler = std::move_only_function<void(Message msg) &&>;
|
||||
|
||||
// Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++
|
||||
using Slot = std::unique_ptr<void, std::function<void(void*)>>;
|
||||
using Slot = std::unique_ptr<void, std::move_only_function<void(void*)>>;
|
||||
|
||||
// Tag specifying that an owning handle (so-called slot) of the logical resource shall be provided to the client
|
||||
struct return_slot_t { explicit return_slot_t() = default; };
|
||||
@@ -109,19 +115,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,24 +140,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 <>
|
||||
@@ -251,12 +264,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 <>
|
||||
@@ -271,10 +284,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;
|
||||
@@ -317,93 +330,96 @@ 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;
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
concept valid_signature = signature_of<Types...>::is_valid;
|
||||
|
||||
// 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;
|
||||
@@ -420,175 +436,196 @@ 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 <typename FunctionType>
|
||||
struct function_traits<std::move_only_function<FunctionType>> : function_traits<FunctionType>
|
||||
{};
|
||||
|
||||
template <class _Function>
|
||||
constexpr auto has_error_param_v = function_traits<_Function>::has_error_param;
|
||||
template <class Function>
|
||||
constexpr auto is_async_method_v = function_traits<Function>::is_async;
|
||||
|
||||
template <typename _FunctionType>
|
||||
using function_arguments_t = typename function_traits<_FunctionType>::arguments_type;
|
||||
template <class Function>
|
||||
constexpr auto has_error_param_v = function_traits<Function>::has_error_param;
|
||||
|
||||
template <typename _FunctionType, size_t _Idx>
|
||||
using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>;
|
||||
template <typename FunctionType>
|
||||
using function_arguments_t = typename function_traits<FunctionType>::arguments_type;
|
||||
|
||||
template <typename _FunctionType>
|
||||
constexpr auto function_argument_count_v = function_traits<_FunctionType>::arity;
|
||||
template <typename FunctionType, size_t Idx>
|
||||
using function_argument_t = typename function_traits<FunctionType>::template arg_t<Idx>;
|
||||
|
||||
template <typename _FunctionType>
|
||||
using function_result_t = typename function_traits<_FunctionType>::result_type;
|
||||
template <typename FunctionType>
|
||||
constexpr auto function_argument_count_v = function_traits<FunctionType>::arity;
|
||||
|
||||
template <typename _Function>
|
||||
template <typename FunctionType>
|
||||
using function_result_t = typename function_traits<FunctionType>::result_type;
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -597,7 +634,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).
|
||||
@@ -605,94 +642,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
@@ -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_ */
|
||||
|
||||
@@ -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,14 +38,14 @@ namespace sdbus {
|
||||
|
||||
struct MethodVTableItem
|
||||
{
|
||||
template <typename _Function> MethodVTableItem& implementedAs(_Function&& callback);
|
||||
MethodVTableItem& withInputParamNames(std::vector<std::string> names);
|
||||
template <typename... _String> MethodVTableItem& withInputParamNames(_String... names);
|
||||
MethodVTableItem& withOutputParamNames(std::vector<std::string> names);
|
||||
template <typename... _String> MethodVTableItem& withOutputParamNames(_String... names);
|
||||
MethodVTableItem& markAsDeprecated();
|
||||
MethodVTableItem& markAsPrivileged();
|
||||
MethodVTableItem& withNoReply();
|
||||
template <typename Function> MethodVTableItem&& implementedAs(Function&& callback) &&;
|
||||
MethodVTableItem&& withInputParamNames(std::vector<std::string> names) &&;
|
||||
template <typename... String> MethodVTableItem&& withInputParamNames(String... names) &&;
|
||||
MethodVTableItem&& withOutputParamNames(std::vector<std::string> names) &&;
|
||||
template <typename... String> MethodVTableItem&& withOutputParamNames(String... names) &&;
|
||||
MethodVTableItem&& markAsDeprecated() &&;
|
||||
MethodVTableItem&& markAsPrivileged() &&;
|
||||
MethodVTableItem&& withNoReply() &&;
|
||||
|
||||
MethodName name;
|
||||
Signature inputSignature;
|
||||
@@ -61,10 +61,10 @@ 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);
|
||||
SignalVTableItem& markAsDeprecated();
|
||||
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;
|
||||
Signature signature;
|
||||
@@ -77,11 +77,11 @@ namespace sdbus {
|
||||
|
||||
struct PropertyVTableItem
|
||||
{
|
||||
template <typename _Function> PropertyVTableItem& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyVTableItem& withSetter(_Function&& callback);
|
||||
PropertyVTableItem& markAsDeprecated();
|
||||
PropertyVTableItem& markAsPrivileged();
|
||||
PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
template <typename Function> PropertyVTableItem&& withGetter(Function&& callback) &&;
|
||||
template <typename Function> PropertyVTableItem&& withSetter(Function&& callback) &&;
|
||||
PropertyVTableItem&& markAsDeprecated() &&;
|
||||
PropertyVTableItem&& markAsPrivileged() &&;
|
||||
PropertyVTableItem&& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&;
|
||||
|
||||
PropertyName name;
|
||||
Signature signature;
|
||||
@@ -95,10 +95,10 @@ namespace sdbus {
|
||||
|
||||
struct InterfaceFlagsVTableItem
|
||||
{
|
||||
InterfaceFlagsVTableItem& markAsDeprecated();
|
||||
InterfaceFlagsVTableItem& markAsPrivileged();
|
||||
InterfaceFlagsVTableItem& withNoReplyMethods();
|
||||
InterfaceFlagsVTableItem& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
InterfaceFlagsVTableItem&& markAsDeprecated() &&;
|
||||
InterfaceFlagsVTableItem&& markAsPrivileged() &&;
|
||||
InterfaceFlagsVTableItem&& withNoReplyMethods() &&;
|
||||
InterfaceFlagsVTableItem&& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&;
|
||||
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
@@ -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) mutable
|
||||
{
|
||||
// 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,63 +66,63 @@ 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));
|
||||
}
|
||||
};
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withInputParamNames(std::vector<std::string> names)
|
||||
inline MethodVTableItem&& MethodVTableItem::withInputParamNames(std::vector<std::string> names) &&
|
||||
{
|
||||
inputParamNames = std::move(names);
|
||||
|
||||
return *this;
|
||||
return std::move(*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...});
|
||||
return std::move(*this).withInputParamNames({names...});
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(std::vector<std::string> names)
|
||||
inline MethodVTableItem&& MethodVTableItem::withOutputParamNames(std::vector<std::string> names) &&
|
||||
{
|
||||
outputParamNames = std::move(names);
|
||||
|
||||
return *this;
|
||||
return std::move(*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...});
|
||||
return std::move(*this).withOutputParamNames({names...});
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::markAsDeprecated()
|
||||
inline MethodVTableItem&& MethodVTableItem::markAsDeprecated() &&
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::markAsPrivileged()
|
||||
inline MethodVTableItem&& MethodVTableItem::markAsPrivileged() &&
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withNoReply()
|
||||
inline MethodVTableItem&& MethodVTableItem::withNoReply() &&
|
||||
{
|
||||
flags.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline MethodVTableItem registerMethod(MethodName methodName)
|
||||
@@ -139,36 +139,36 @@ namespace sdbus {
|
||||
/*** Signal VTable Item ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters()
|
||||
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;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(std::vector<std::string> names)
|
||||
template <typename... Args>
|
||||
inline SignalVTableItem&& SignalVTableItem::withParameters(std::vector<std::string> names) &&
|
||||
{
|
||||
paramNames = std::move(names);
|
||||
|
||||
return withParameters<_Args...>();
|
||||
return std::move(*this).template 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 std::move(*this).template withParameters<Args...>({names...});
|
||||
}
|
||||
|
||||
inline SignalVTableItem& SignalVTableItem::markAsDeprecated()
|
||||
inline SignalVTableItem&& SignalVTableItem::markAsDeprecated() &&
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline SignalVTableItem registerSignal(SignalName signalName)
|
||||
@@ -185,37 +185,37 @@ 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) mutable
|
||||
{
|
||||
// Get the propety value and serialize it into the pre-constructed reply message
|
||||
reply << callback();
|
||||
};
|
||||
|
||||
return *this;
|
||||
return std::move(*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) mutable
|
||||
{
|
||||
// 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
|
||||
@@ -225,28 +225,28 @@ namespace sdbus {
|
||||
callback(property);
|
||||
};
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::markAsDeprecated()
|
||||
inline PropertyVTableItem&& PropertyVTableItem::markAsDeprecated() &&
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::markAsPrivileged()
|
||||
inline PropertyVTableItem&& PropertyVTableItem::markAsPrivileged() &&
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
inline PropertyVTableItem&& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&
|
||||
{
|
||||
flags.set(behavior);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline PropertyVTableItem registerProperty(PropertyName propertyName)
|
||||
@@ -263,32 +263,32 @@ namespace sdbus {
|
||||
/*** Interface Flags VTable Item ***/
|
||||
/*** --------------------------- ***/
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsDeprecated()
|
||||
inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::markAsDeprecated() &&
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsPrivileged()
|
||||
inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::markAsPrivileged() &&
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withNoReplyMethods()
|
||||
inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::withNoReplyMethods() &&
|
||||
{
|
||||
flags.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&
|
||||
{
|
||||
flags.set(behavior);
|
||||
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem setInterfaceFlags()
|
||||
|
||||
@@ -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
|
||||
|
||||
+125
-93
@@ -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,27 +27,40 @@
|
||||
#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 {
|
||||
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory)
|
||||
Connection::Connection(std::unique_ptr<ISdBus>&& interface, BusFactory&& busFactory)
|
||||
: sdbus_(std::move(interface))
|
||||
, bus_(openBus(busFactory))
|
||||
, bus_(openBus(std::move(busFactory)))
|
||||
{
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -215,12 +238,12 @@ uint64_t Connection::getMethodCallTimeout() const
|
||||
return timeout;
|
||||
}
|
||||
|
||||
void Connection::addMatch(const std::string& match, message_handler callback)
|
||||
void Connection::addMatch(const std::string& match, message_handler&& callback)
|
||||
{
|
||||
floatingMatchRules_.push_back(addMatch(match, std::move(callback), return_slot));
|
||||
}
|
||||
|
||||
Slot Connection::addMatch(const std::string& match, message_handler callback, return_slot_t)
|
||||
Slot Connection::addMatch(const std::string& match, message_handler&& callback, return_slot_t)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
|
||||
|
||||
@@ -230,19 +253,19 @@ 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)
|
||||
void Connection::addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback)
|
||||
{
|
||||
floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback), return_slot));
|
||||
}
|
||||
|
||||
Slot Connection::addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, message_handler&& callback
|
||||
, match_install_handler&& installCallback
|
||||
, return_slot_t )
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
|
||||
@@ -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)
|
||||
@@ -710,10 +739,10 @@ sd_bus_message* Connection::createErrorReplyMessage(sd_bus_message* sdbusMsg, co
|
||||
return sdbusErrorReply;
|
||||
}
|
||||
|
||||
Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
|
||||
Connection::BusPtr Connection::openBus(BusFactory&& busFactory)
|
||||
{
|
||||
sd_bus* bus{};
|
||||
int r = busFactory(&bus);
|
||||
const int r = std::move(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;
|
||||
}
|
||||
@@ -888,14 +920,14 @@ int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void
|
||||
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection);
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->installCallback(std::move(message)); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ std::move(matchInfo->installCallback)(std::move(message)); }, retError);
|
||||
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
+39
-33
@@ -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;
|
||||
@@ -108,12 +111,12 @@ namespace sdbus::internal {
|
||||
void setMethodCallTimeout(uint64_t timeout) override;
|
||||
[[nodiscard]] uint64_t getMethodCallTimeout() const override;
|
||||
|
||||
void addMatch(const std::string& match, message_handler callback) override;
|
||||
[[nodiscard]] Slot addMatch(const std::string& match, message_handler callback, return_slot_t) override;
|
||||
void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) override;
|
||||
void addMatch(const std::string& match, message_handler&& callback) override;
|
||||
[[nodiscard]] Slot addMatch(const std::string& match, message_handler&& callback, return_slot_t) override;
|
||||
void addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) override;
|
||||
[[nodiscard]] Slot addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, message_handler&& callback
|
||||
, match_install_handler&& installCallback
|
||||
, return_slot_t ) override;
|
||||
|
||||
void attachSdEventLoop(sd_event *event, int priority) override;
|
||||
@@ -178,11 +181,11 @@ namespace sdbus::internal {
|
||||
sd_bus_message* createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error) override;
|
||||
|
||||
private:
|
||||
using BusFactory = std::function<int(sd_bus**)>;
|
||||
using BusPtr = std::unique_ptr<sd_bus, std::function<sd_bus*(sd_bus*)>>;
|
||||
Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory);
|
||||
using BusFactory = std::move_only_function<int(sd_bus**) &&>;
|
||||
using BusPtr = std::unique_ptr<sd_bus, std::move_only_function<sd_bus*(sd_bus*)>>;
|
||||
Connection(std::unique_ptr<ISdBus>&& interface, BusFactory&& busFactory);
|
||||
|
||||
BusPtr openBus(const std::function<int(sd_bus**)>& busFactory);
|
||||
BusPtr openBus(BusFactory&& busFactory);
|
||||
BusPtr openPseudoBus();
|
||||
void finishHandshake(sd_bus* bus);
|
||||
bool waitForNextEvent();
|
||||
@@ -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();
|
||||
@@ -227,8 +234,8 @@ namespace sdbus::internal {
|
||||
struct MatchInfo
|
||||
{
|
||||
message_handler callback;
|
||||
message_handler installCallback;
|
||||
Connection& connection;
|
||||
match_install_handler installCallback;
|
||||
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_ */
|
||||
|
||||
+16
-7
@@ -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,21 +29,30 @@
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
#include SDBUS_HEADER
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
sdbus::Error createError(int errNo, std::string customMsg)
|
||||
Error createError(int errNo, std::string customMsg)
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
sd_bus_error_set_errno(&sdbusError, errNo);
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
Error::Name name(sdbusError.name);
|
||||
Error::Name name(sd_bus_error_is_set(&sdbusError) != 0 ? sdbusError.name : "");
|
||||
std::string message(std::move(customMsg));
|
||||
message.append(" (");
|
||||
message.append(sdbusError.message);
|
||||
message.append(")");
|
||||
if (!message.empty() && sdbusError.message != nullptr)
|
||||
{
|
||||
message.append(" (");
|
||||
message.append(sdbusError.message);
|
||||
message.append(")");
|
||||
}
|
||||
else if (sdbusError.message != nullptr)
|
||||
{
|
||||
message = sdbusError.message;
|
||||
}
|
||||
|
||||
return Error(std::move(name), std::move(message));
|
||||
return {std::move(name), std::move(message)};
|
||||
}
|
||||
} // namespace sdbus
|
||||
|
||||
+3
-7
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_ */
|
||||
|
||||
+30
-22
@@ -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;
|
||||
|
||||
@@ -292,7 +300,7 @@ void Object::finalizeSdBusVTable(std::vector<sd_bus_vtable>& vtable)
|
||||
vtable.push_back(createSdBusVTableEndItem());
|
||||
}
|
||||
|
||||
const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, std::string_view methodName)
|
||||
Object::VTable::MethodItem* Object::findMethod(VTable& vtable, std::string_view methodName)
|
||||
{
|
||||
auto it = std::lower_bound(vtable.methods.begin(), vtable.methods.end(), methodName, [](const auto& methodItem, const auto& methodName)
|
||||
{
|
||||
@@ -302,7 +310,7 @@ const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, std::
|
||||
return it != vtable.methods.end() && it->name == methodName ? &*it : nullptr;
|
||||
}
|
||||
|
||||
const Object::VTable::PropertyItem* Object::findProperty(const VTable& vtable, std::string_view propertyName)
|
||||
Object::VTable::PropertyItem* Object::findProperty(VTable& vtable, std::string_view propertyName)
|
||||
{
|
||||
auto it = std::lower_bound(vtable.properties.begin(), vtable.properties.end(), propertyName, [](const auto& propertyItem, const auto& propertyName)
|
||||
{
|
||||
@@ -328,11 +336,11 @@ int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData,
|
||||
|
||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_);
|
||||
|
||||
const auto* methodItem = findMethod(*vtable, message.getMemberName());
|
||||
auto* methodItem = findMethod(*vtable, message.getMemberName());
|
||||
assert(methodItem != nullptr);
|
||||
assert(methodItem->callback);
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ methodItem->callback(std::move(message)); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&] { methodItem->callback(std::move(message)); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
@@ -349,7 +357,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
const auto* propertyItem = findProperty(*vtable, property);
|
||||
auto* propertyItem = findProperty(*vtable, property);
|
||||
assert(propertyItem != nullptr);
|
||||
|
||||
// Getter may be empty - the case of "write-only" property
|
||||
@@ -361,7 +369,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &vtable->object->connection_);
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->getCallback(reply); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&] { propertyItem->getCallback(reply); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
@@ -378,27 +386,27 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
const auto* propertyItem = findProperty(*vtable, property);
|
||||
auto* propertyItem = findProperty(*vtable, property);
|
||||
assert(propertyItem != nullptr);
|
||||
assert(propertyItem->setCallback);
|
||||
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &vtable->object->connection_);
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->setCallback(std::move(value)); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&] { propertyItem->setCallback(std::move(value)); }, retError);
|
||||
|
||||
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
|
||||
|
||||
+21
-15
@@ -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,20 +133,20 @@ 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);
|
||||
static void writePropertyRecordToSdBusVTable(const VTable::PropertyItem& property, std::vector<sd_bus_vtable>& vtable);
|
||||
static void finalizeSdBusVTable(std::vector<sd_bus_vtable>& vtable);
|
||||
|
||||
static const VTable::MethodItem* findMethod(const VTable& vtable, std::string_view methodName);
|
||||
static const VTable::PropertyItem* findProperty(const VTable& vtable, std::string_view propertyName);
|
||||
static VTable::MethodItem* findMethod(VTable& vtable, std::string_view methodName);
|
||||
static VTable::PropertyItem* findProperty(VTable& vtable, std::string_view propertyName);
|
||||
|
||||
static std::string paramNamesToString(const std::vector<std::string>& paramNames);
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
+106
-70
@@ -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 )
|
||||
@@ -106,44 +117,46 @@ MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
return message.send(timeout);
|
||||
}
|
||||
|
||||
PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback)
|
||||
PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback)
|
||||
{
|
||||
return Proxy::callMethodAsync(message, std::move(asyncReplyCallback), /*timeout*/ 0);
|
||||
}
|
||||
|
||||
Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, return_slot_t)
|
||||
Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, return_slot_t)
|
||||
{
|
||||
return Proxy::callMethodAsync(message, std::move(asyncReplyCallback), /*timeout*/ 0, return_slot);
|
||||
}
|
||||
|
||||
PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout)
|
||||
PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, uint64_t timeout)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL);
|
||||
|
||||
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)
|
||||
Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, uint64_t timeout, return_slot_t)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL);
|
||||
|
||||
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)
|
||||
@@ -153,15 +166,15 @@ std::future<MethodReply> Proxy::callMethodAsync(const MethodCall& message, with_
|
||||
|
||||
std::future<MethodReply> Proxy::callMethodAsync(const MethodCall& message, uint64_t timeout, with_future_t)
|
||||
{
|
||||
auto promise = std::make_shared<std::promise<MethodReply>>();
|
||||
auto future = promise->get_future();
|
||||
std::promise<MethodReply> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply reply, std::optional<Error> error) noexcept
|
||||
async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply reply, std::optional<Error> error) mutable noexcept
|
||||
{
|
||||
if (!error)
|
||||
promise->set_value(std::move(reply));
|
||||
promise.set_value(std::move(reply));
|
||||
else
|
||||
promise->set_exception(std::make_exception_ptr(*std::move(error)));
|
||||
promise.set_exception(std::make_exception_ptr(*std::move(error)));
|
||||
};
|
||||
|
||||
(void)Proxy::callMethodAsync(message, std::move(asyncReplyCallback), timeout);
|
||||
@@ -169,16 +182,41 @@ 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 )
|
||||
, signal_handler&& signalHandler )
|
||||
{
|
||||
Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler));
|
||||
}
|
||||
|
||||
void Proxy::registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler )
|
||||
, signal_handler&& signalHandler )
|
||||
{
|
||||
auto slot = Proxy::registerSignalHandler(interfaceName, signalName, std::move(signalHandler), return_slot);
|
||||
|
||||
@@ -187,7 +225,7 @@ void Proxy::registerSignalHandler( const char* interfaceName
|
||||
|
||||
Slot Proxy::registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t )
|
||||
{
|
||||
return Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler), return_slot);
|
||||
@@ -195,7 +233,7 @@ Slot Proxy::registerSignalHandler( const InterfaceName& interfaceName
|
||||
|
||||
Slot Proxy::registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t )
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
@@ -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()
|
||||
@@ -258,12 +296,12 @@ int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userDat
|
||||
const auto* error = sd_bus_message_get_error(sdbusMessage);
|
||||
if (error == nullptr)
|
||||
{
|
||||
asyncCallInfo->callback(std::move(message), {});
|
||||
std::move(asyncCallInfo->callback)(std::move(message), {});
|
||||
}
|
||||
else
|
||||
{
|
||||
Error exception(Error::Name{error->name}, error->message);
|
||||
asyncCallInfo->callback(std::move(message), std::move(exception));
|
||||
std::move(asyncCallInfo->callback)(std::move(message), std::move(exception));
|
||||
}
|
||||
}, retError);
|
||||
|
||||
@@ -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
|
||||
|
||||
+29
-22
@@ -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,48 +45,52 @@ 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;
|
||||
PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) override;
|
||||
Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, return_slot_t ) override;
|
||||
PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, uint64_t timeout ) override;
|
||||
Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, async_reply_handler&& asyncReplyCallback
|
||||
, uint64_t timeout
|
||||
, 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
|
||||
, signal_handler signalHandler ) override;
|
||||
, signal_handler&& signalHandler ) override;
|
||||
void registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler ) override;
|
||||
, signal_handler&& signalHandler ) override;
|
||||
Slot registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t ) override;
|
||||
Slot registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler
|
||||
, signal_handler&& signalHandler
|
||||
, return_slot_t ) override;
|
||||
void unregister() override;
|
||||
|
||||
@@ -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::move_only_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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
+9
-5
@@ -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,14 +52,16 @@
|
||||
#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
|
||||
{
|
||||
callable();
|
||||
std::forward<Callable>(callable)();
|
||||
}
|
||||
catch (const Error& e)
|
||||
{
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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,11 +349,10 @@ TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
|
||||
{
|
||||
auto& object = this->m_adaptor->getObject();
|
||||
sdbus::InterfaceName 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::return_slot );
|
||||
sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"};
|
||||
auto vtableSlot = object.addVTable( 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; })
|
||||
).forInterface(interfaceName, sdbus::return_slot);
|
||||
|
||||
// The new remote vtable is registered as long as we keep vtableSlot, so remote method calls now should pass
|
||||
auto proxy = sdbus::createLightWeightProxy(SERVICE_NAME, OBJECT_PATH);
|
||||
@@ -369,12 +365,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( 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; })
|
||||
).forInterface(interfaceName, sdbus::return_slot);
|
||||
|
||||
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::return_slot );
|
||||
vtableSlot.reset(); // Letting the slot go means letting go the associated vtable registration
|
||||
|
||||
// No such remote D-Bus method under given interface exists anymore...
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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,12 @@ 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
|
||||
std::string TestAdaptor::getExpectedXmlApiDescription()
|
||||
{
|
||||
return
|
||||
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
@@ -472,4 +489,4 @@ R"delimiter(
|
||||
)delimiter";
|
||||
}
|
||||
|
||||
}}
|
||||
} // namespace sdbus::test
|
||||
|
||||
@@ -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,8 @@ 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);
|
||||
static std::string getExpectedXmlApiDescription() ;
|
||||
|
||||
private:
|
||||
const std::string m_state{DEFAULT_STATE_VALUE};
|
||||
@@ -162,6 +171,6 @@ protected:
|
||||
std::string state() override { return {}; }
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace sdbus::test
|
||||
|
||||
#endif /* INTEGRATIONTESTS_TESTADAPTOR_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 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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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,26 @@
|
||||
*/
|
||||
|
||||
#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); });
|
||||
|
||||
registerProxy();
|
||||
}
|
||||
@@ -49,7 +59,7 @@ 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); });
|
||||
|
||||
registerProxy();
|
||||
}
|
||||
@@ -79,17 +89,17 @@ 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::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 +118,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 +196,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 +243,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 +261,4 @@ void TestProxy::setStateProperty(const std::string& value)
|
||||
getProxy().setProperty("state").onInterface(sdbus::test::INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
}}
|
||||
} // namespace sdbus::test
|
||||
|
||||
@@ -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,8 @@ 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 onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const;
|
||||
|
||||
// Signals of standard D-Bus interfaces
|
||||
void onPropertiesChanged( const sdbus::InterfaceName& interfaceName
|
||||
@@ -102,20 +111,23 @@ 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;
|
||||
|
||||
@@ -134,7 +146,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 +156,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
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
+186
-58
@@ -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,45 +101,119 @@ 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));
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeMoved)
|
||||
{
|
||||
auto value = "hello"s;
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
auto movedVariant{std::move(variant)};
|
||||
|
||||
ASSERT_THAT(movedVariant.get<std::string>(), Eq(value));
|
||||
ASSERT_TRUE(variant.isEmpty()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeMovedIntoAMap)
|
||||
{
|
||||
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()); // 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));
|
||||
@@ -136,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>());
|
||||
}
|
||||
@@ -147,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));
|
||||
@@ -160,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>());
|
||||
}
|
||||
@@ -180,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();
|
||||
|
||||
@@ -199,7 +286,7 @@ TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
|
||||
|
||||
TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
|
||||
{
|
||||
sdbus::Variant variant;
|
||||
const sdbus::Variant variant;
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
@@ -209,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);
|
||||
@@ -218,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)
|
||||
@@ -272,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;
|
||||
|
||||
@@ -288,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));
|
||||
}
|
||||
@@ -299,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)
|
||||
@@ -311,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));
|
||||
}
|
||||
@@ -342,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()));
|
||||
}
|
||||
@@ -354,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();
|
||||
}
|
||||
|
||||
@@ -378,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();
|
||||
@@ -430,6 +516,7 @@ TEST(AnError, CanBeConstructedFromANameAndAMessage)
|
||||
auto error = sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.error"}, "message");
|
||||
EXPECT_THAT(error.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
EXPECT_THAT(error.getMessage(), Eq<std::string>("message"));
|
||||
EXPECT_TRUE(error.isValid());
|
||||
}
|
||||
|
||||
TEST(AnError, CanBeConstructedFromANameOnly)
|
||||
@@ -439,6 +526,47 @@ TEST(AnError, CanBeConstructedFromANameOnly)
|
||||
EXPECT_THAT(error1.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
EXPECT_THAT(error2.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
|
||||
EXPECT_THAT(error1.getMessage(), Eq<std::string>(""));
|
||||
EXPECT_THAT(error2.getMessage(), Eq<std::string>(""));
|
||||
EXPECT_TRUE(error1.getMessage().empty());
|
||||
EXPECT_TRUE(error2.getMessage().empty());
|
||||
|
||||
EXPECT_TRUE(error1.isValid());
|
||||
EXPECT_TRUE(error2.isValid());
|
||||
}
|
||||
|
||||
TEST(AnError, IsInvalidWhenConstructedWithAnEmptyName)
|
||||
{
|
||||
auto error = sdbus::Error({});
|
||||
|
||||
EXPECT_TRUE(error.getName().empty());
|
||||
EXPECT_TRUE(error.getMessage().empty());
|
||||
EXPECT_FALSE(error.isValid());
|
||||
}
|
||||
|
||||
TEST(AnErrorFactory, CanCreateAnErrorFromErrno)
|
||||
{
|
||||
auto error = sdbus::createError(ENOENT, "custom message");
|
||||
|
||||
EXPECT_THAT(error.getName(), Eq<std::string>("org.freedesktop.DBus.Error.FileNotFound"));
|
||||
EXPECT_THAT(error.getMessage(), Eq<std::string>("custom message (No such file or directory)"));
|
||||
EXPECT_TRUE(error.isValid());
|
||||
}
|
||||
|
||||
#ifndef SDBUS_basu // Creating error from invalid errno is not supported on basu backend
|
||||
TEST(AnErrorFactory, CreatesGenericErrorWhenErrnoIsUnknown)
|
||||
{
|
||||
auto error = sdbus::createError(123456, "custom message");
|
||||
|
||||
EXPECT_THAT(error.getName(), Eq<std::string>("org.freedesktop.DBus.Error.Failed"));
|
||||
EXPECT_THAT(error.getMessage(), Eq<std::string>("custom message (Unknown error 123456)"));
|
||||
EXPECT_TRUE(error.isValid());
|
||||
}
|
||||
#endif // SDBUS_basu
|
||||
|
||||
TEST(AnErrorFactory, CreatesEmptyInvalidErrorWhenErrnoIsZero)
|
||||
{
|
||||
auto error = sdbus::createError(0, "custom message");
|
||||
|
||||
EXPECT_TRUE(error.getName().empty());
|
||||
EXPECT_THAT(error.getMessage(), Eq<std::string>("custom message"));
|
||||
EXPECT_FALSE(error.isValid());
|
||||
}
|
||||
|
||||
@@ -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,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
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(sdbus-c++-tools VERSION 2.1.0)
|
||||
project(sdbus-c++-tools VERSION 2.2.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,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,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,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,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
|
||||
*
|
||||
|
||||
@@ -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 };
|
||||
|
||||
/**
|
||||
* 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,13 @@ 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;
|
||||
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 == "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,7 +216,26 @@ 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);
|
||||
// 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;
|
||||
}
|
||||
|
||||
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
|
||||
@@ -220,13 +244,13 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
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 +264,20 @@ 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 // Callback
|
||||
{
|
||||
definitionSS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "std::move(error)); })";
|
||||
@@ -315,10 +343,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 +353,46 @@ 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;
|
||||
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 == "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;
|
||||
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 == "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 << "\")"
|
||||
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 +401,15 @@ 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 // 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 +426,43 @@ 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" : "")
|
||||
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 // Callback
|
||||
{
|
||||
propertySS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error)"
|
||||
"{ this->on" << nameBigFirst << "PropertySetReply(std::move(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 ProxyGenerator.h
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user